Skip to content

feat(profiles): emit printer printable_area in /profiles/bundled - #4

Merged
jappyjan merged 1 commit into
bambuddy/profile-resolverfrom
bambuddy/printable-area
Aug 7, 2026
Merged

feat(profiles): emit printer printable_area in /profiles/bundled#4
jappyjan merged 1 commit into
bambuddy/profile-resolverfrom
bambuddy/printable-area

Conversation

@jappyjan

@jappyjan jappyjan commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Prerequisite for bambuddy#67 / bambuddy#68. GET /profiles/bundled returned printers as {name, base_id}, so Bambuddy had no way to learn a printer's bed size — every other candidate source (the Printer DB model, PRINTER_MODEL_MAP, the preset-name parser) carries no geometry either. The only bed dimensions Bambuddy reads today come out of a 3MF, which is why an STL and a bedless 3MF both render on a hardcoded 256×256 plate.

Printer entries now carry printable_area.

Reuses the existing resolver

printerMetadata mirrors filamentMetadata and delegates to the same resolveProfile walk from #2/#3. No second walker: printers inherit the depth cap, the cycle termination and the declared-name index (for parents whose file basename sanitizes a slash) for free. A fixture pins the slash case on the machine category too, so a regression there is caught on both.

The walk is what makes it work — measured, not assumed

Both bundled trees at the versions the sidecar images carry:

tree leaf states printable_area resolves through the walk
SoftFever/OrcaSlicer@v2.3.2, resources/profiles/BBL/machine 4/44 44/44
bambulab/BambuStudio@v02.07.01.57, resources/profiles/BBL/machine 7/56 56/56

(Counting instantiable type: "machine" presets. Depth distribution Orca: 4 at depth 0, 19 at 1, 21 at 2. Bambu: 7 / 28 / 21.)

Reading only the leaf would report null for ~90% of the tier — exactly the failure mode filament_type had in bambuddy#47.

The two slicers genuinely disagree on ~330 setting keys, so the spelling was checked rather than assumed: printable_area is spelled identically in both, and carries the same corner-point shape in both.

The listing also contains type: "machine_model" catalogue entries ("Bambu Lab H2D" with no nozzle suffix) — 11 in Orca, 14 in Bambu. Those describe a printer family, not a slicing preset, declare no bed anywhere in their chain, and report null. So against what the endpoint actually emits: 44 of 55 (Orca) and 56 of 70 (Bambu).

Emitted raw, deliberately

printable_area is a list of "<x>x<y>" corner points in bed millimetres, e.g. ["0x0","256x0","256x256","0x256"] — not a width/height pair. It is passed through as the declared polygon rather than reduced here, because a reduction would silently flatten the outlines that are not origin-anchored rectangles, and those exist. Across OrcaSlicer's full vendor tree, 597 profiles declare the key:

  • 582 declare 4 points
  • 8 declare 72 (round delta beds)
  • 3 declare 6
  • 3 declare 239

Only the container shape is normalised, never the geometry — every declared point survives, in order:

  • a polygon written as one comma-joined string is split ("0x0,400x0,400x400,0x400" — Creality Ender-5 Max)
  • stray whitespace inside a point is trimmed ("0x256 "Bambu Lab X2D 0.4 nozzle, BambuStudio)

Degrade rules (per #3)

null rather than a fabricated value, and the degrade path is logged. A cyclic chain that blows the depth cap reports null even though a profile inside the cycle states a bed. Fewer than three usable points degrades to null with a warning rather than reaching the consumer as a zero-area bed — null has to keep meaning "absent", never "0 × 0".

The per-cache-fill count line now reports printable_area N. The dangling-parent degrade is silent by design and never throws, so a tier-wide regression to all-null would otherwise produce no signal at all — and would be indistinguishable from a deployment still running an old sidecar. That is the diagnosability gap that cost bambuddy#47 and AFKFelix#51 a ticket each.

bed_exclude_area — verified, deliberately not implemented

It exists under that exact spelling in both trees and resolves for the same presets (44/44, 56/56). It is non-empty for 20 presets in each: the ["0x0","18x0","18x28","0x28"] nozzle-wipe corner on P1P / P1S / X1 / X1 Carbon / X1E, all nozzle sizes.

Correction to bambuddy#68's premise: the ticket states "the H2D's is real". It is not — every H2D variant resolves bed_exclude_area: [] (empty), via fdm_bbl_3dp_002_common. The printers that actually have one are the X1/P1 family. It would matter for arrangement/collision on those, not for plate sizing, which is what AFKFelix#67 needs.

Tests

New tests/e2e/bundled-printer-bed.spec.ts, 15 cases: bed two levels up, leaf-stated bed not overwritten, slash-named ancestor, non-rectangular polygon emitted raw, both packaging warts, machine_model → null, and the degrade paths (dangling / cyclic / corrupt ancestor / sub-polygon) with their warnings.

Full suite, host without a slicer binary (the slice e2e specs need the one in the Docker test image):

files tests
before 14 (6 failed / 8 passed) 142 (22 failed / 120 passed)
after 15 (6 failed / 9 passed) 157 (22 failed / 135 passed)

Same 22 pre-existing failures, +15 passing. tsc --noEmit clean. eslint ./src/** reports one error in src/routes/health/health.service.ts:48 — present on the base commit too, untouched here.

Mutation checks — all five bit:

mutation tests failed
walk made inert (needsWalk = false) 4
feature absent entirely (pristine route.ts) 14 of 15
.trim() removed 1
comma-joined-string branch removed 2
< 3 point guard removed 3
reduced to a bounding box instead of raw 1

Note for whoever rebuilds the image

printable_height resolves from the very same walk at zero extra cost — 44/44 and 56/56, same as printable_area — and bambuddy#69 needs a z dimension for its build volume (today's fallback is a hardcoded z: 256). It is not in this PR because bambuddy#68 scoped to printable_area only. If you want it, say so before the image rebuild: adding it afterwards costs a second foreground rebuild.

No image was rebuilt or pushed.

🤖 Generated with Claude Code

Bambuddy has no way to learn a printer's bed size (bambuddy#67 blocker
table): `/profiles/bundled` returned printers as `{name, base_id}`, and
every other candidate source — the Printer DB model, PRINTER_MODEL_MAP,
the preset-name parser — carries no geometry either. The only bed
dimensions Bambuddy ever reads today come out of a 3MF, which is why an
STL and a bedless 3MF both render on a hardcoded 256x256 plate.

Emit each bundled machine preset's `printable_area`, resolved through the
same `resolveProfile` inherits walk PR #2/#3 built for filament metadata.
No second walker: printers get the depth cap, the cycle termination and
the declared-name index (for parents whose file basename sanitizes a
slash) for free.

The walk is what makes it work. Measured against the two bundled trees
the sidecar images carry, the leaf states `printable_area` for only 4/44
presets in SoftFever/OrcaSlicer@v2.3.2 and 7/56 in
bambulab/BambuStudio@v02.07.01.57; through the walk it resolves for
44/44 and 56/56. The key is spelled identically in both trees and carries
the same corner-point shape in both — measured, not assumed, since the
two slicers genuinely disagree on ~330 setting keys.

Emitted raw as the declared point list, not reduced to width/height. A
reduction would silently flatten the outlines that are not
origin-anchored rectangles, and those exist: across OrcaSlicer's full
vendor tree 582 profiles declare 4 points, but 8 declare 72 (round delta
beds), 3 declare 6 and 3 declare 239. Only the container shape is
normalised — a polygon written as one comma-joined string is split
(Creality Ender-5 Max) and stray whitespace inside a point is trimmed
(`"0x256 "` on Bambu Lab X2D) — never the geometry.

Degrade rules follow PR #3: `null` rather than a fabricated value, and
the degrade path is logged. `null` means "absent" and is never "a bed of
size zero"; fewer than three usable points degrades to `null` rather than
reaching the consumer as a zero-area bed. The per-cache-fill count line
now reports `printable_area N`, which is what distinguishes "deployment
still on an old sidecar" from "the resolver broke" — the same
diagnosability gap that cost bambuddy#47 and AFKFelix#51 a ticket each.

Also verified and deliberately NOT implemented: `bed_exclude_area` exists
under that spelling in both trees and resolves for the same presets. It
is non-empty for 20 presets in each (the 18x28 nozzle-wipe corner on
P1P/P1S/X1/X1 Carbon/X1E) and empty for every H2D variant.

Refs bambuddy#68, bambuddy#67

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant