look is two things in one native binary.
A renderer. GLB, STL, and STEP models become PNG images and an interactive viewer — GPU-rendered, automatically framed, in roughly a second on a typical laptop. No CAD application to open, no converter to configure, no browser pipeline to build.
A model generation pipeline. A Python API with exact build123d syntax drives a certified constructive-geometry kernel: your existing build123d scripts run unmodified, every part is built and certified by the kernel (volumes carry exact certificates, refusals state their reason), and the result ships as a colored indexed GLB with per-part materials — plus the fingerprint STL, measurements, and timing columns for CI.
STEP files are CAD boundary representations rather than meshes, so look
tessellates them on load. That happens inside the binary — there is nothing to
install and no converter to configure:
look part.step --output part.pngThe Falcon Heavy above is the end-to-end demo: 2,142 parts built and certified by the kernel in ~0.02 s, written as a colored indexed GLB with per-part materials, and opened in the interactive viewer — see the demo walkthrough.
look is faster than F3D 3.5 across every scene measured, by 1.4x on typical
glTF samples and up to 5.9x on large ones. On STEP it beats F3D's OpenCASCADE
reader by 3.21x on the core_xy assembly. See benchmarks
for the numbers, raw samples, image licenses, and methodology.
Render an automatically framed isometric view:
look model.glb --output render.pngThat command loads model.glb, selects a technical material and lighting setup,
fits the camera to the model, renders an isometric view, and writes render.png.
No configuration file is required.
Render a tileset — several camera views in one GPU-generated atlas PNG — in a single pass. This works for GLB, STL, and STEP alike; STEP is tessellated on load inside the binary:
look core_xy.step --views front,right,top,iso --atlas 2 --resolution 512x512 --output views.png --jsonOne process, one readback, one PNG: the whole tileset, from an unparsed STEP file to the finished image in roughly a second on a typical laptop.
Render four camera views directly into one GPU-generated PNG:
look model.glb --material-mode source \
--views front,right,top,iso --camera orthographic \
--resolution 384x384 --atlas 2 --output views.png --jsonThe atlas path draws every view into one render target in a single GPU pass, then does one readback and one PNG, rather than paying per-view capture overhead.
look can also:
- render named camera views with controllable lighting and materials;
- combine several views into one atlas image for efficient agent inspection;
- report mesh, triangle, material, texture, and bounds metadata as JSON;
- execute repeatable YAML render jobs;
- keep a scene GPU-resident for multiple inspection passes; and
- open an interactive HTML viewer in the default browser.
It uses Rust and wgpu directly and emits machine-readable results for agent
workflows. There is no browser, Electron shell, VTK scene layer, or import
framework on the hot path.
Yes, every command has built-in help:
look --help
look render --help
look persist --help
look --versionlook help render is equivalent to look render --help.
Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/stefangolas/look/main/install.sh | shWindows PowerShell:
irm https://raw.githubusercontent.com/stefangolas/look/main/install.ps1 | iexRelease archives and Debian packages are also attached to each GitHub release. See installation for version pinning and source builds.
The render subcommand is implied when the first argument is a model path:
look model.glb --view iso --resolution 1024x1024 --output render.png
look model.glb --material-mode source --antialias --output pbr.png
look bracket.stl --view front --camera orthographic --output bracket.png
look model.glb --views front,right,top,iso --output-dir renders --jsonPack multiple views into one GPU-rendered PNG atlas. The resolution is the size of each tile, not the whole atlas:
look model.glb --views front,right,top,iso --atlas 2 --output views.png --jsonUse the F3D 3.5/VTK compatibility profile when comparing the two renderers:
look model.glb --preset f3d-match --view front --camera orthographic --output matched.pngThe profile matches F3D's default camera framing, background, and five-light kit. It is a compatibility preset, not a promise of pixel identity for every PBR material.
STEP files are CAD boundary representations, so look evaluates and
tessellates them on load. There is no separate converter or OCCT dependency to
install:
look core_xy.step --view iso --output core_xy.png --jsonSTEP renders take every flag a mesh render does — named views, atlases, material modes, lighting, and YAML jobs all work unchanged:
look core_xy.step --views front,right,top,iso --atlas 2 --resolution 512x512 --output views.png --json
look core_xy.step --material-mode source --antialias --view front --camera orthographic --output pbr.pngUse --material-mode technical (the default) when only geometry matters; it
skips source texture decode and upload. Use --material-mode source when PBR
fidelity and source colours matter. The glTF source mode also reads STEP
styled-item colours where the chain resolves.
Faces that cannot be tessellated are reported as machine-readable warnings on
the --json output (for example BoundaryProjectionFailed) rather than
silently dropped; incomplete assemblies stay visible, and the missing faces are
named so they can be chased down.
render --gui opens an interactive, self-contained HTML 3D viewer in the
default browser instead of writing a PNG. It applies the same lighting,
background, and material arguments as a normal render, so the view matches the
screenshot path:
look model.glb --gui --material-mode source --view iso --output model_viewer.html --json
look core_xy.step --gui --view iso --jsonThe viewer is a single HTML file with embedded geometry — drag to orbit, scroll
to zoom — and works offline, with no server or browser extension. --json
reports the viewer path, scene, and triangle count. --gui conflicts with
--session (a session is a GPU-resident render loop, not an HTML view).
To write the viewer file without opening a browser, use ui with an explicit
output path:
look ui core_xy.step --output core_xy_viewer.html --jsonModels are authored in exact build123d syntax — the kernel answers the
same names (Cylinder, Location, Compound, Pos, Plane, mirror,
...) as the build123d API, so existing scripts run unmodified:
from cadgen import build123d as bd
part = bd.Cylinder(radius=r, height=z1 - z0).locate(bd.Location((x, y, (z0 + z1) / 2)))
part = part.moved(bd.Location((x, y, 0)))
engine = bd.Compound(obj=parts, children=parts, label=label)The repository ships a text-to-CAD corpus with a door script that builds every
model on the kernel engine and exports both a certification artifact (binary
STL) and a render artifact (colored indexed GLB, one node per part, materials
from the script's own colors). Refusals are self-describing: each non-green
run returns a ttc_door_run.v2 record whose error block carries a stable
refusal_code, the verb/carrier/phase in scope, the corpus
client_site, and a hand-maintained known_gap pointer into the gap
register — see docs/REFUSALS.md for the full schema and
code table. One line builds the Falcon Heavy — 2,142 parts — into both
artifacts:
python corpus/ttc/door.py --engine truck corpus/ttc/trees/falcon_heavy/src lib.falcon_common build_vehicle "[]" falcon_heavy.stl --glb falcon_heavy.glbThen open it in the interactive viewer, with --performance booking end-to-end
wall time, per-stage timings, and peak process memory into the JSON output:
look ui falcon_heavy.glb --performance --jsonMeasured on one Windows x64 machine (release build, quiet system, medians of
repeated runs; the kernel column varies with --deflection, which trades
triangle density for time and memory):
| stage | OCCT (build123d) | kernel (truck123d) |
|---|---|---|
| geometry build (2,142 solids) | 3.84 s | 0.012–0.026 s |
| build → artifacts on disk | 27.4–28.2 s → 47 MB GLB | 3.1–3.3 s → 117 MB GLB + 213 MB STL |
| peak process memory | 1,569–1,572 MiB | 1,565 MiB |
render → PNG (look render) |
2.08–2.15 s | 0.77–1.14 s |
The kernel geometry build is deflection-invariant; mesh emission scales with
the requested density. The demo ships 0.4 mm: at that precision the kernel
writes a denser artifact than the OCCT reference (117 MB vs 47 MB GLB) in
3.1–3.3 s with memory parity — roughly 9x the speed end to end. See
docs/TT_TIMING_RESULTS.md for the per-row
series and scratch/fh_render/TIMING.md for the raw samples.
Repeated inspection should avoid parsing, texture decoding, shader creation,
and GPU upload. persist starts a private loopback server, warms the scene, and
returns a session ID:
look persist assembly.glb --material-mode source --ttl 600 --json
look render --session SESSION_ID --views front,right,top,iso --atlas 2 --output views.png --json
look inspect --session SESSION_ID --json
look close SESSION_ID --jsonUse look sessions --json, look server status --json, and
look server stop --json to manage the local server. Sessions expire after the
configured idle lifetime. The server binds only to loopback and authenticates
requests with a per-process token stored in the user's cache directory.
look run examples/technical.yaml --jsonversion: 1
scene:
source: assembly.glb
up_axis: y
render:
resolution: [1024, 1024]
material_mode: technical
background: "#252525"
antialias: false
atlas_columns: 2
lighting:
preset: technical
ambient: 0.35
direction: [-1, -2, -3]
intensity: 0.85
color: "#ffffff"
views:
- id: front
type: orthographic
direction: [0, 0, 1]
- id: iso
type: perspective
direction: [1, 1, 1]
output:
directory: renders
naming: "{view}.png"Unknown YAML fields are rejected instead of silently ignored.
The repository includes tests/fixtures/triangle.stl, a 162-byte ASCII STL
used for CLI, package, parser, and render smoke tests:
look tests/fixtures/triangle.stl --output triangle.png --jsonLarger Khronos models are benchmark inputs rather than fixtures, and are kept out of the repository to avoid bloating clones and redistributing third-party assets without their license records.
- Embedded-buffer GLB/glTF 2.0 and binary or ASCII STL
- Technical material mode and glTF metallic-roughness source materials
- Base-color, metallic-roughness, normal, emissive, and occlusion textures
- Alpha modes, UV0/UV1, vertex colors, instancing, and geometry deduplication
- Perspective and orthographic bounds-fit cameras with seven named views
- Configurable technical lighting and an F3D 3.5 compatibility light kit
- Multi-view PNGs and single-pass GPU atlas rendering
- Content-validated scene metadata cache and bounded GPU-resident session cache
- DirectX 12, Vulkan, Metal, and browser WebGPU-class portability through
wgpu
This is deliberately a renderer, not an embeddable CAD framework or general scene editor.
Fresh-process, against F3D 3.5: 1.40x geometric mean on six glTF samples, 2.00x
on New York Boulevard at 4K, and 5.94x on the 10.8M-triangle Sponza foliage
composite. On STEP, 3.21x against F3D's OpenCASCADE reader on the core_xy
assembly (9.1 MB, 5,623 tessellated faces): 2,005 ms in look versus 6,442 ms
for OCCT through F3D 3.5 at 512x512. See benchmarks for
raw samples.
core_xy.step is a local reference model, not a repo fixture. Re-measure it by
launching each renderer fresh and timing process start through a completed PNG.
The settings below match docs/BENCHMARKS.md and the --preset f3d-match
profile: 512x512, front orthographic, no AA/AO/tone-mapping, #252525
background. look reads STEP with its own Part 21 parser and tessellator;
F3D reads STEP through its bundled OpenCASCADE plugin, so --force-reader=STEP
is required. Do one unmeasured launch per tool first so drivers and caches are
warm, alternate launch order between samples, and take a median of five.
# look (release build)
look render core_xy.step --view front --camera orthographic --resolution 512x512 `
--preset f3d-match --background "#252525" --output corexy-look.png
# OCCT through F3D 3.5 console
f3d-console core_xy.step --no-config --force-reader=STEP --output corexy-f3d.png `
--resolution 512,512 "--camera-direction=-Z" --camera-orthographic `
--anti-aliasing=none --ambient-occlusion=0 --tone-mapping=0 `
--background-color "#252525"Score a run only if a PNG was produced, and confirm the F3D PNG contains the
model (compare foreground bounding boxes and luminance coverage against the
look output) — a mis-served file can otherwise look like a successful render.
The 3.21x above is one assembly on one RTX 5050 Laptop GPU, not a universal
STEP claim.
Resident, against Three.js at 512 px tiles: a four-view atlas takes 8.94 ms in
look versus 22.50 ms in WebGL2 and 27.30 ms in WebGPU.
These are local results on one NVIDIA RTX 5050 Laptop GPU, not universal guarantees. Commands, raw samples, fidelity metrics, hardware fingerprints, and methodological limits are in benchmarks.
Two build modes serve different purposes. Pick by what you are doing.
The quick profile trades runtime for iteration speed. It keeps dev
semantics/assertions, uses opt-level = 2 so focused validation stays usable,
and disables LTO with high codegen parallelism plus incremental compilation.
It builds to target/quick/, a separate artifact tree from release.
cargo qcheck # check --profile quick --locked
cargo qbuild # build --profile quick --locked
cargo qtest # test --profile quick --tests --locked
cargo test --profile quick --lib <filter> --locked # narrow kernel testqtest uses --tests, so a routine dev-test run does not compile the many
examples/ probe binaries. Run a probe deliberately when you need it.
target/release/look.exe is the authoritative performance and regression
artifact. Its semantics are fixed and measured.
cargo build --release --lockedtarget/quick/look.exe must never be used for recorded performance numbers:
quick runtime is not comparable to release runtime.
cargo fmt --all -- --check
cargo check --locked --all-targets
cargo test --locked --all-targets
cargo test --release --test gpu_smoke -- --ignored --nocapture --test-threads=1cargo check --locked --all-targets and cargo test --locked --all-targets use
the default (debug) profile and cover the full target set, including the probes.
See cross-platform testing, and AGENTS.md. GitHub Actions builds and smoke-tests release binaries for Linux, Windows, and macOS on x64 and ARM64.
Licensed under MIT or Apache-2.0.

