Skip to content

feat(slicer): carry the printer's printable_area on UnifiedPreset - #36

Merged
jappyjan merged 1 commit into
slicer-ux-redesignfrom
bed-1-printable-area
Aug 7, 2026
Merged

feat(slicer): carry the printer's printable_area on UnifiedPreset#36
jappyjan merged 1 commit into
slicer-ux-redesignfrom
bed-1-printable-area

Conversation

@jappyjan

@jappyjan jappyjan commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Prerequisite for maziggy#67 (bed.1). Both halves of that epic need the selected printer's bed size, and Bambuddy could not obtain it anywhere — the Printer model has no dimensions, PRINTER_MODEL_MAP has none, and printerPresetAxes.ts says outright that the preset NAME is the only carrier. The only bed geometry Bambuddy reads today comes out of a 3MF, which is why an STL and a bedless 3MF both render on a hardcoded 256×256 plate.

UnifiedPreset now carries printable_area for the printer slot.

Pairs with jappyjan/orca-slicer-api#4, which makes the sidecar emit it. This PR is safe to merge before that image is rebuilt — see the degrade section.

Shape

The slicer's own polygon of "<x>x<y>" corner points in bed millimetres:

{"id": "Bambu Lab H2D 0.4 nozzle", "name": "", "source": "standard",
 "printable_area": ["0x0", "350x0", "350x320", "0x320"]}

Not a width/height pair, and deliberately not reduced here. Across OrcaSlicer's full vendor tree, 597 profiles declare the key: 582 with 4 points, 8 with 72 (round delta beds), 3 with 6, 3 with 239. Flattening any of those would hand the viewport a rectangle that lies about where a model may be placed. Consumers reduce it themselves.

Only the container shape is normalised, never the geometry — both of these occur verbatim in the bundled trees:

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

Per tier

tier source
standard the sidecar's printable_area, resolved through the bundled profile's inherits: chain
orca_cloud the profile content Orca's sync already returns
local the same key out of LocalPreset.setting, the stored resolved blob
cloud borrowed across the name bridge — Bambu Cloud ships no profile content at all

The bridge is the same one filament_vendor rides (maziggy#58), and it matters more here: only the standard tier resolves a real bed, so without it the bed a printer reports would depend on which tier happened to win dedup — invisible to the user and not something they chose. It only ever fills a gap; an entry that states its own bed keeps it.

No hardcoded model→bed map. One existed and was deliberately removed in favour of reading printable_area (CHANGELOG:1173). There is consequently no name-parse fallback the way there is for filament_vendor — a bed cannot be guessed from a string, so an unresolvable one stays None.

Degrades to None on every sidecar that has not been rebuilt

That is the state each deployment is in today, and it is the normal state rather than an error state. Tested explicitly: the old {name, base_id} response still yields a complete listing with the bed simply absent — no raise, no dropped printer, no invented bed.

None stays distinguishable from a bed of size zero throughout. Fewer than three usable points reads as "no bed known", never as a zero-area one, because a consumer treats the first as "fall back to the default plate" and the second as "place everything at the origin".

Scope

Nothing in the viewport is touched — no ModelViewer, no PlateStage, no SlicerPage. Consuming this value is #69. The one frontend change is the additive optional field on the UnifiedPreset interface in api/client.ts, so #69 does not need a type change to read it.

Tests

22 new cases in backend/tests/unit/test_slicer_presets.py: the normaliser (rectangle, hexagon, origin-offset bed, comma-joined string, whitespace, junk, sub-polygon), each tier, the old-sidecar degrade, the name bridge, and serialisation through UnifiedPresetsResponse.

  • Backend: 2 failed, 7454 passed — the two failures are the known pre-existing test_extract_video_last_frame ones (local ffmpeg missing libx265), unrelated.
  • Frontend: 214 files passed, 2888 tests passed. npx eslint . → exit 0 and npx tsc --noEmit -p tsconfig.app.json → exit 0, run as separate commands with separately checked exit codes (test_frontend.sh ends with cd .. and exits 0 regardless).
  • ruff check clean. ruff format also normalised two pre-existing blocks in the test file — that file already failed ruff format --check on e018c336, so this is 6 lines of incidental cleanup, not new churn. tests/integration/test_notifications_api.py still fails the check and is untouched here.

Mutation checks — all five bit:

mutation tests failed
sidecar field never read 3
cross-tier bed bridge made inert 1
>= 3 point guard removed 3
local-blob read made inert 1
trim + comma-split normalisation removed 2

Two things #69 should know

  1. A reducer already exists, at backend/app/api/routes/archives.py:3011-3027, turning a 3MF's printable_area into a build_volume. It independently uses the same len(...) >= 3 guard. Two caveats before reusing it: it parses coordinates with int(), so a fractional coordinate is silently skipped; and it takes only max_x/max_y with no min, so an origin-offset bed loses its offset.
  2. printable_height is not in this PR. #68 scoped to printable_area, but that same reducer uses printable_height for the z axis, and today's fallback is a hardcoded z: 256. It resolves from the identical sidecar walk at zero extra cost (44/44 and 56/56). If it is wanted, it should be decided before the sidecar image is rebuilt — adding it afterwards costs a second foreground rebuild.

No image was rebuilt or pushed.

🤖 Generated with Claude Code

Prerequisite for maziggy#67. Both halves of that epic need the selected
printer's bed size and Bambuddy could not obtain it anywhere: the
`Printer` model has no dimensions, `PRINTER_MODEL_MAP` has none, and
`printerPresetAxes.ts` states outright that the preset NAME is the only
carrier. The only bed geometry Bambuddy reads today comes out of a 3MF,
which is why an STL and a bedless 3MF both render on a hardcoded
256x256 plate.

`UnifiedPreset` now carries `printable_area` for the printer slot: the
bed outline as the slicer's own polygon of `"<x>x<y>"` corner points in
bed millimetres, e.g. `["0x0","350x0","350x320","0x320"]` for an H2D.
Populated per tier — standard from the sidecar (jappyjan/orca-slicer-api#4,
resolved through the bundled profile's `inherits:` chain), orca_cloud and
local from the profile content each already holds, cloud across the same
name bridge `filament_vendor` rides (maziggy#58).

Carried raw rather than reduced to width/height: 8 profiles in
OrcaSlicer's vendor tree declare 72-point round delta beds, 3 declare 6
points and 3 declare 239, and flattening any of those would hand the
viewport a rectangle that lies about where a model may be placed.
Consumers reduce it themselves. Only the container shape is normalised —
a polygon written as one comma-joined string is split and stray
whitespace inside a point is trimmed, both of which occur verbatim in the
bundled trees.

No hardcoded model->bed map: one existed and was deliberately removed in
favour of reading `printable_area` (CHANGELOG:1173). There is
consequently no name-parse fallback for this field the way there is for
`filament_vendor` — a bed cannot be guessed from a string, so an
unresolvable one stays `None`.

**Degrades to `None` on every sidecar that has not been rebuilt**, which
is the state each deployment is in today. That is the normal state, not
an error state, and it is tested explicitly: the old `{name, base_id}`
response still yields a complete listing with the bed simply absent.
`None` stays distinguishable from a bed of size zero throughout — fewer
than three usable points reads as "no bed known", never as a zero-area
one, because the first means "fall back to the default plate" and the
second means "place everything at the origin".

Consuming the value is #69's job; nothing in the viewport is touched here.

Refs #68, maziggy#67

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jappyjan
jappyjan merged commit 0af501b into slicer-ux-redesign Aug 7, 2026
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