v0.2.1 — the blank-render fix
0.2.0 rendered a uniform grey frame with no model in it for small models — anything spanning less than ~4.5 cm, roughly 11 studs. This release fixes that. (This sentence originally read “for every input”; see the correction at the bottom.)
What was wrong
The camera distance was derived from the scene bounds; the camera clip planes were not. ImportLDraw imports at real-world metre scale — two 2×4 bricks genuinely span 3.2 cm — so distance = span * 2.2 placed the camera 7 cm from the model, inside Blender's default clip_start of 0.1 m. Every mesh was clipped away before shading, and the frame rendered as the bare white world, which AgX maps to a plausible grey.
Nothing failed along the way. The import succeeded (472 vertices per brick, nothing hidden from rendering), Blender exited 0, and the PNG was well-formed. The fault was a parameter that was never set, so no line of code reads wrong on inspection — only rendering and measuring the pixels found it.
The fix
Both clip planes are now derived from the same distance the camera position already uses. That holds at any model scale, rather than special-casing small models with a fixed tiny near plane that would quietly cost depth precision on large ones.
Measured on an otherwise identical scene:
| max pixel deviation | pixels differing >40 | |
|---|---|---|
clip_start = 0.1 (before) |
6 | 0 / 40000 |
| derived from span | 195 | 13010 / 40000 |
Verified from the built wheel in a clean environment, not just the source tree: max deviation 412, 105023 of 320000 pixels.
Also
- The blank-frame eval's control had never run in CI. It sat under a module-level
skipif(not is_available())and CI runners have no Blender, so the one check proving the detector can tell a blank frame from a drawn one was skipped exactly where it mattered — while its docstring claimed it ran without a renderer. The skip now applies only to the test that drives Blender, andnumpy(which that control imports) joins thetestextra instead of being present by luck. server.json's fourth version copy is now guarded._meta.publisher-provided.versionwas not covered by the version-sync test that exists precisely because unchecked version sources drift.
Fixes #14.
Correction (2026-08-01)
This note originally said the bug affected "every input". Measured, that is false: the
failure is size-dependent. A model is clipped only when span * 2.2 falls below
Blender's default 0.1 m near plane — about 4.5 cm, roughly 11 studs across.
Measured on 0.2.0's own code:
| model | span | camera distance | result |
|---|---|---|---|
| single 2×4 brick | 32 mm | 0.070 m | blank — 0 pixels differ from background |
| two bricks, 56 mm apart | 56 mm | 0.123 m | renders correctly |
| two bricks, 192 mm apart | 192 mm | 0.422 m | renders correctly |
So small models — the single part, the demo, the test case — were broken, while larger
builds were always fine.
The same correction applies to 0.1.0, 0.1.1 and 0.1.2: none of them set the clip planes
either (verified against the published 0.1.0 sdist, which has no git tag), so every release
before 0.2.1 carries the defect under that size threshold.
Separately, main now rejects a blank render instead of returning it as a success — the
render path had no output postcondition, which is why this shipped invisibly in the first
place (#18).