BrickBench is an open-source Unity project for benchmarking manual assembly instruction modalities using LEGO Duplo bricks. While AR is increasingly recognized as an effective tool for in-situ assembly assistance, the interaction between hardware form factor and spatial task complexity remains underexplored. BrickBench was built to address this gap by enabling a controlled comparison of three instruction modalities — baseline monitor-based instructions, handheld augmented reality, and head-mounted augmented reality — across three spatial complexity levels. For background information and details regarding the conducted user study involving this project, refer to the publication (Blattgerste, Krumstroh & Pfeiffer, 2026).
Assets/Scenes: benchmark scenes and complexity setupsAssets/Scripts: runtime and editor scripts for setup loading, building, and loggingAssets/StreamingAssets: JSON setup files used by the buildersPackages: Unity package manifest and lock fileProjectSettings: Unity project configuration
- Unity 6000.3.6f1
- For Apple Vision Pro: the PolySpatial Unity package
- A compatible AR/XR device (Apple Vision Pro & iPhone 14 Pro with LiDAR or newer) or the Unity editor for development and testing
The project runs a sequence of benchmark setups inside one Unity scene. A root object called Setups contains the individual complexity setups, and the runtime switches between them through SetupLoader.
For AR alignment, TrackedImageCalibrationAnchor listens for an ARTrackedImageManager marker. When the marker is detected, it anchors the benchmark content to that image so the setups stay aligned in the real world.
- Unity 6000.3.6f1
- The project opened through Unity Hub
- For Apple Vision Pro, the PolySpatial package enabled in the project
- An AR setup with
ARTrackedImageManagerif you want marker-based alignment
A typical scene should contain:
AR SessionAR Session Originor the equivalent XR origin used by the projectARTrackedImageManager- A parent object named
SetupsorMonitor_Setups - One child GameObject per benchmark complexity
SetupLoaderon the object that manages the setup switchingTrackedImageCalibrationAnchorif you want marker anchoring
The Setups object is the root for the benchmark content. Each child under it should represent one complexity level.
The instruction sets are written in JSON and must use a single wrapper object with a bricks array. Each item in that array is one instruction step.
Use the same field names and value types as the shipped complexity files:
{
"bricks": [
{
"prefab": 0,
"x": 0,
"y": 0,
"z": 0,
"color": "Blue",
"rot90": false,
"view": "Center"
}
]
}Required fields for each step are prefab, x, y, z, color, and rot90. view is optional; if omitted, it defaults to Center. The current builder also accepts entries instead of bricks, prefabIndex instead of prefab, and rotateY90 instead of rot90.
- Create one child object under
Setupsfor each complexity level. - Give each child a clear name, because the name is used in logs.
- Put either
AutoBuilderorBrickBuilderunder each setup, depending on the experiment variant. - Keep the hierarchy clean so
SetupLoadercan find the builders in the children.
SetupLoader can also auto-discover setups by scanning the children of its own transform, but explicit assignment is usually easier to maintain.
- Create or import a reference image library for your AR project.
- Add the image you want to use as the marker.
- Make sure the image name is unique and stable, because
TrackedImageCalibrationAnchorcan filter markers by name. - Add
ARTrackedImageManagerto the scene and assign the reference library.
If you want the anchor to react only to one marker, set the name filter in TrackedImageCalibrationAnchor so it matches part of the reference image name.
- Add
TrackedImageCalibrationAnchorto the scene. - Assign
contentRootto theSetupsroot, or leave it empty and let the component resolve it automatically. - Assign the
ARTrackedImageManagerreference, or let the component discover it at runtime. - Set the marker name filter if you only want one tracked image to drive the anchor.
When the marker is detected, the script creates a stable anchor object and parents the content root under it. If freezeAfterFirstDetection is enabled, the content stays locked after the first successful detection.
- Set the JSON input directly, or
- Set
jsonFilePathto a file inAssets/StreamingAssets - Assign the correct Brick prefabs (found in
Assets/LegoDuploModelle/...) - Assign the Cameras for different static views (only for monitor scene, not relevant for AR scene)
On device builds, use a relative file name such as setup1.json instead of an editor absolute path. The loader resolves the file against Application.streamingAssetsPath.
- Attach
SetupLoaderto the object that controls the benchmark flow. - Assign the
setupsarray if you want explicit control. - Leave transition UI enabled if you want a prompt between complexities.
- Disable keyboard or gamepad input if the scene should only advance through the UI or external controls.
SetupLoader activates one setup at a time, records the step progress, and writes timing data through Logger.
The logger writes JSON files into the app's persistent data path under a Logs folder.
A successful run should produce:
- A session start timestamp
- Completion entries for each complexity
- Step-by-step progress records
If the log file is not created, confirm that Logger exists in the scene or is initialized before the benchmark starts.
This open-source project is published under the MIT License.
Third-party assets and code that are bundled with the project are listed in THIRD_PARTY_NOTICES.md.
