From cb4854e1c5f10cd1c81d118c590e9b9c72abe9a7 Mon Sep 17 00:00:00 2001 From: physicsG Date: Fri, 21 Aug 2026 19:53:53 +0200 Subject: [PATCH 01/18] docs(ace-mmu): design the U1 printer panel, and how to draw an ACE and a plate The Printer section is shared by Prepare and Preview, and on a U1 it draws four tabs that each hold the same Diameter combo, says nothing about which toolhead an ACE feeds, and hides its sync behind an unlabelled glyph. Measured by running the app rather than by reading it. Doc 15 takes Bambu Studio's panel apart against the screenshots and applies its shape to four heads. Two things it turned up are defects in existing code, both written down: a unit shared between two heads double-counts capacity in the planner, so the infeasible-plate refusal would pass a plate it exists to catch; and Combined mode emits the wrong ACE= and SLOT= because the emitter has one unit per head while the plan's slot is an index within the head. Doc 16 settles how an ACE is drawn. It was drawn four ways - circles on one page, cards on another, bars on a third - while the filament-mapping popup already used Orca's own AMS widgets, because the ACE is projected onto amsList. So the AMS is the standard, and the geometry is lifted from AMSItem.hpp rather than invented, which is what stops it drifting again. Doc 17 does the same for the build plate. The silhouette is measured, not traced: a first attempt drawn by eye was wrong in every dimension, so the product PNG was decoded to raw pixels and its edges sampled per column. It is drawn deliberately overstated, because at 44 px the true notch is one pixel and a truthful outline says nothing. Snapmaker's own plates are photographed; anything else is drawn generically, so the app never brands a bed type with a vendor it does not mention. The ACE mode switch is the printer's own - SET_ACE_MODE MODE=normal|multi|head, read from the firmware's macro help, not guessed. It also answers whether one unit can feed several heads: in head mode it can, and the popover is where that happens. Design only; no code. NEXT.md carries the decisions, the two things still open, the shipping order and the traps on this branch. Co-Authored-By: Claude Opus 5 --- docs/ace-mmu/15-printer-panel.md | 127 +++ docs/ace-mmu/16-ace-visuals.md | 115 +++ docs/ace-mmu/17-plate-template.md | 119 +++ docs/ace-mmu/NEXT.md | 135 +++ docs/ace-mmu/README.md | 59 ++ docs/ace-mmu/ace-visual-standard.html | 1006 ++++++++++++++++++++ docs/ace-mmu/plate-thumbnails-options.html | 415 ++++++++ docs/ace-mmu/printer-panel-mockup.html | 954 +++++++++++++++++++ 8 files changed, 2930 insertions(+) create mode 100644 docs/ace-mmu/15-printer-panel.md create mode 100644 docs/ace-mmu/16-ace-visuals.md create mode 100644 docs/ace-mmu/17-plate-template.md create mode 100644 docs/ace-mmu/NEXT.md create mode 100644 docs/ace-mmu/README.md create mode 100644 docs/ace-mmu/ace-visual-standard.html create mode 100644 docs/ace-mmu/plate-thumbnails-options.html create mode 100644 docs/ace-mmu/printer-panel-mockup.html diff --git a/docs/ace-mmu/15-printer-panel.md b/docs/ace-mmu/15-printer-panel.md new file mode 100644 index 00000000000..fedf3dbaeae --- /dev/null +++ b/docs/ace-mmu/15-printer-panel.md @@ -0,0 +1,127 @@ +# The U1 printer panel (Prepare / Preview) + +Interactive mockup: [printer-panel-mockup.html](printer-panel-mockup.html) · +Visual standard: [16-ace-visuals.md](16-ace-visuals.md) + +> **Status: design only. No code has landed.** This branch carries the docs and mockups; +> every implementation step below is still to do. The ACE machinery referenced here — +> `ace_head_capacity` / `ace_head_unit`, `AceMmuProvider`, `sync_ace_topology`, +> `AceMmuPlan` — lives on `feat/ace-mmu-slicing` and does not exist on +> `develop/add-multiace-support` yet. Start from [NEXT.md](NEXT.md). + +**Prepare and Preview share one sidebar.** The Printer section at the top of it is a +single widget seen in two tabs, so this is one change in two places — and anything +added to it is also on screen while reading a sliced preview, where vertical space is +contested. + +## What is wrong today + +Measured by running the app, not by reading it (`.claude/tools/start.sh headless`). + +| # | Defect | Where | +|---|--------|-------| +| 1 | **Four tabs hold one control each.** `Nozzle 1..4`, each with a `Diameter` combo; changing any one writes all four and switches the whole preset, because the U1 refuses mixed diameters. Three tabs exist to be clicked and show nothing new. | `Sidebar::update_nozzle_settings`, Plater.cpp:8682 | +| 2 | **Three names for one thing.** Sidebar says *Nozzle 1–4*, Printer Settings says *Toolhead 1–4*, the assignment dialog says *T1–T4*. | Plater.cpp:8814, Tab.cpp:4808, `resources/web/aceplan` | +| 3 | **No topology.** The preset knows head 4 is fed by ACE 1 with four slots (`ace_head_capacity`, `ace_head_unit`); the panel never says so. | — | +| 4 | **No contents, and no way to ask.** The spool colours at each head are known when the printer is on the LAN — they already drive the filament sync — but never reach this panel. | `append_ace_filament_list`, Plater.cpp:773 | +| 5 | **Two half-syncs.** The sidebar glyph syncs nozzle diameters only; multiACE topology sync is a separate button buried in Printer Settings › Multimaterial. | Plater.cpp:2214, Tab.cpp:4652 | + +## The shape: Bambu's panel, for four heads + +Taken from `bambu_studio_inspiration/Nozzle_and_filament_info/`, piece by piece. + +- **Three cards across the top** — printer (thumbnail over preset combo), plate + (texture swatch + ⓘ, absorbing today's `Bed type` row), and **Sync info**. +- **A green corner tick** on any card that agrees with the connected machine. On a head + box it means the ACE wiring matches what the printer reports — a claim we can make, + because `sync_ace_topology` already computes exactly that diff. +- **A bordered box per head**, Bambu's Left/Right Nozzle panes wrapped **2×2**: an + `ACE` row (badge when a unit feeds it, `Stock feeder` otherwise, adjust button always) + and a `Diameter` row. No `Flow` row — this fork deleted the control and there is no + setting behind it. +- **One `Nozzle` row**, not four tabs. Per-head diameters return only if the U1 ever + allows mixed sets; a machine reporting differing diameters still routes to the + existing `NozzleDiameterSelectDialog`. +- **Sync in two steps** — *Successfully synchronized nozzle, ACE mode and ACE unit + information* → **[Continue to sync filaments] [Cancel]**, anchored over the viewport. + Step two opens the existing `Sidebar::show_sync_filament_dialog`. + +## ACE mode — the printer's own switch + +Verified against firmware (`/printer/gcode/help` on 192.168.2.242): + +``` +SET_ACE_MODE MODE=normal|multi|head [HEAD=n] +ACE_SET_HEAD_ACE HEAD=0..3 ACE=0..3 "each ACE head is wired to exactly one ACE" +ACE_SET_HEAD_FEEDER HEAD=0..3 ENABLE=0|1 "(head mode only)" +``` + +The panel mirrors it as a labelled dropdown — **Normal** / **Per toolhead** / +**Combined** — with the raw `SET_ACE_MODE MODE=…` in the tooltip. Only in **head** mode +does per-toolhead wiring mean anything, so the head boxes grey their ACE rows in Normal. +Sync info reads the mode back along with the wiring. + +## The assign popover + +A **choice**, not a count: the firmware offers exactly two macros, so the list has +exactly two kinds of row and a tick rather than a spinner. + +``` +Which ACE feeds Toolhead 4? + ⬡ Stock feeder One spool, loaded at the head ( ) + ▤ ACE 1 · ACE 2 Pro 4 slots · connected · 39% RH (✓) +``` + +Units are named as the printer names them — `protocol: "v2"` → **ACE 2 Pro**, `"v1"` → +**ACE Pro** — the same mapping `resources/web/multiace/index.html` already uses. Between +them the rows write exactly `ace_head_capacity` and `ace_head_unit`. + +**One unit may feed several heads.** `ACE_SET_HEAD_ACE` binds a head to one ACE; it says +nothing about an ACE feeding one head, and `head_ace` is a map from head to unit. Ticking +the same unit on a second head is therefore legal, each row then reads *also feeds +Toolhead N*, and a warning states the real capacity. + +## Two defects this uncovered + +1. **A shared unit double-counts capacity.** `AceMmuPlan.hpp` sums capacity per head + (`total_cap += cap[h]`) and enforces it per head (`if (++load[h] > cap[h])`). Two + heads on one 4-slot unit read as **8 places** when there are 4, so the + infeasible-plate refusal — whose whole purpose is catching this — would pass a plate + that cannot be laid out. Needs a per-unit pool constraint beside the per-head one. +2. **Combined mode cannot be emitted.** `ace_head_capacity` already offers *6 slots* and + *8 slots*, but `GCode.cpp`'s `unit_of_head()` returns the single `ace_head_unit[h]` + and the plan's slot is an index *within the head*. Slot 5 of an 8-slot head emits + `ACE= SLOT=5` where the machine needs `ACE= SLOT=1` — wrong + unit, wrong slot, wrong colour. Those enum values are unsafe until the emitter maps + slot → (unit, slot). + +## Touch points + +| Piece | Where | State | +|-------|-------|-------| +| The panel | `Plater.cpp:2199–2565` | Title bar, preset card, Bed type row, nozzle notebook — built once in the Sidebar constructor | +| The head boxes | `Sidebar::update_nozzle_settings`, `Plater.cpp:8682` | Rebuilds one page per `nozzle_diameter` entry; becomes a 2×2 grid | +| Sync, nozzles | `Plater.cpp:2214–2350` | Queries the machine, `NozzleDiameterSelectDialog` on mixed diameters. Keep; becomes half the press | +| Sync, topology | `TabPrinter::sync_ace_topology`, `Tab.cpp:4652` | Reads `/multiace/api/state`, diffs per head, reports. Lift out of `TabPrinter` so the sidebar can call it | +| Sync, filaments | `Sidebar::show_sync_filament_dialog`, `Plater.cpp:8467` | Already lists U1 toolheads *and* ACE slots. What *Continue to sync filaments* opens | +| Topology | `ace_head_capacity`, `ace_head_unit` | Per-head `coInts` in the printer preset — the panel works with the printer off | +| Live contents | `AceMmuProvider`, `AceSnapshot` | Units, slots, colours, humidity, per-head bindings. One `fetch_once()` | + +**Before building:** the U1 connects as a `PrintHost` through the webview, not as a +`MachineObject`, so this panel cannot lean on `MachineObject::poll_ace_ams()`. It +resolves a host with `AceMmuProvider::resolve_connected_host()` and reads on demand — +the other reason press-to-sync fits the U1 better than a background poll. + +## Shipping order + +Each is one branch off `develop/add-multiace-support`, one squashed PR. + +1. **Panel structure** — three cards, 2×2 head boxes, one Nozzle row, `Toolhead N` + naming, plate card absorbing Bed type. No ACE; no new config. Self-contained. +2. **Topology in the preset** — `ace_head_capacity` / `ace_head_unit`, the Multimaterial + settings page, `sync_ace_topology`. +3. **The panel's ACE row** — badge, assign popover, ACE mode dropdown, on top of 1 + 2. +4. **Sync info, two-step** — nozzle + topology in one press, chaining to the filament sync. +5. **Per-unit capacity pool** — the shared-unit fix. Before any user can share a unit. +6. **Combined mode** — the emitter's slot → (unit, slot) map. Until then the mode is + listed and disabled, with the reason on it. diff --git a/docs/ace-mmu/16-ace-visuals.md b/docs/ace-mmu/16-ace-visuals.md new file mode 100644 index 00000000000..6c4d847c600 --- /dev/null +++ b/docs/ace-mmu/16-ace-visuals.md @@ -0,0 +1,115 @@ +# The ACE visual standard + +Interactive sheet: [ace-visual-standard.html](ace-visual-standard.html) + +An ACE was drawn four different ways. The device page gave it 60 px circular spools; the +assignment dialog 96 px cards in a teal-banded box; the printer panel 7×15 px bars; and +the filament-mapping popup — which reads the ACE through `amsList` — **Orca's real AMS +widgets**. Four languages for one object. + +That last one is the way out. The ACE is already projected onto `Ams`/`AmsTray`, so the +AMS widgets are the standard, and **the geometry below is lifted from +`src/slic3r/GUI/Widgets/AMSItem.hpp` rather than invented** — which is what stops it +drifting again. + +## The three forms + +One treatment — **outlined chassis, solid bays, one stroke weight** — in three +proportions. Four bays is not a variable: `/api/state` returns `"slots": [/* exactly 4 */]` +and `SLOT_COUNT = 4` is a constant. There is no single-bay form; an AMS Lite has one +spool, an ACE never does. + +| Form | Size | Where | Function | +|------|------|-------|----------| +| **Badge** | 44×26 fill | a head box | `ace_badge()` | +| **Glyph** | 44×26 line, stroke 1.6 | a popover row, a label | `ace_glyph()` | +| **Glyph, square** | 24×24 line, stroke 1.6 | a tab, a menu, a `ScalableButton` | `ace_glyph_square()` | + +**Badge** — hood, four bays, base drawn *over* them; the base is slightly wider than the +hood, which is what makes it read as a cabinet rather than a bar chart. Bays are 5×14 +capsules at x 6/15/24/33 — **padding 4 = gap 4**, matching the proportions of Bambu's +own icon. Colour and emptiness are all that survive at this size, so the badge carries +colour only; an empty bay is white against the grey hood, with no outline. Trust and +staleness live wherever the badge is a control. + +**Glyph** — the badge's own silhouette in line: one stepped path, hood shoulders on top, +base stepping out at the bottom, bays filled. + +**Glyph, square** — body and four bays, no hood or base step. It is deliberately *not* +the same silhouette: the family is carried by the bay treatment and the stroke, because +the square has a third of the width to say the same thing in. If the two ever sit side by +side and the mismatch shows, the fallback is the wide drawing letterboxed into the square. + +## The box the spools sit in + +Orca's AMS already owns the neutrals, and uses them for exactly these roles: + +- `AMS_CONTROL_DEF_BLOCK_BK_COLOUR` **#EEEEEE** — the band, and an empty tube +- `AMS_CONTROL_DEF_LIB_BK_COLOUR` **#F8F8F8** — the box the tubes stand in +- `AMS_CONTROL_BRAND_COLOUR` **#009688** — hover, 2 px +- `AMS_CONTROL_DISABLE_COLOUR` **#CECECE** — a unit configured but not answering + +All go through `StateColor::darkModeColorFor`, so dark mode is not a second palette. + +**The spool object is `AMSLib`** — 58×80 (`AMS_CAN_LIB_SIZE`), a well inset by 4, the +filament colour drawn **from the bottom up to how much is left**. Not a swatch on a card: +a level in a tube, so a row reads as an inventory. Selection is 2 px in *the filament's +own colour* (`AMSLib`'s rule); hover is the brand teal. Label ink follows the fill's +luminance, the same `< 0.6` test `AMSLib` uses for its badge. + +## Moisture and temperature + +`AMSHumidity`, unchanged: a pill (radius = half the height) on `#EEEEEE`, the +`hum_level1..5` droplet at 16 px, a 1 px `#C2C2C2` divider, then the dryer glyph +(`ams_drying` / `ams_is_drying`). `AMS_HUMIDITY_SIZE` 93×26 with a percentage, +`AMS_HUMIDITY_NO_PERCENT_SIZE` 60×26 without. + +`AMSinfo` already handles the ACE's exact case: `humidity_raw = -1` selects the numbered +droplet, anything else the plain droplet plus the number. Bucket the raw percentage +1 = ≤20, 2 = ≤35, 3 = ≤50, 4 = ≤65, 5 = >65 to pick the glyph. + +**Temperature is the one addition.** The AMS carries `current_temperature` but never +draws it here; the ACE reports `temp` per unit and it matters while drying. It goes in +the same pill behind a second divider — one chip, not three. Absent when unreported, +never zeroed. + +## Where a level comes from + +An ACE slot has **no remain field**: `/api/state`'s `slots[]` carries material, brand, +colour and source, and nothing about quantity. But a Spoolman-backed printer binds them: + +```jsonc +"spool_mode": "spoolman", +"spool_binding": { "0_0": "15", "0_1": "10", "0_3": "16" }, +"spools": { "15": { "weight_g": 500.1, "used_mm": 0.0, "density": 1.27, ... } } +``` + +So bound slots can drive the column honestly, and an unbound one is drawn full but +hatched and labelled *amount unknown* rather than pretending to be full. + +**What is not available is a percentage.** Spoolman knows the initial weight; this +payload does not, so a column scaled to 1 kg would call an 843 g spool 84% when it may be +a full 850 g one. Show the grams and treat the column as a gauge — or fetch +`remaining_weight` from Spoolman directly and scale it properly, which is its own piece +of work. `AceSlot` parses none of the binding today; wiring it through is the +prerequisite for the column meaning anything. + +## Adoption + +| Surface | Draws now | Becomes | +|---------|-----------|---------| +| Filament mapping popup (`AmsMappingPopup.cpp`) | Orca's AMS widgets, via the `amsList` projection | **Nothing** — it is already the standard, and the reference | +| Device / AMS tab (`AMSControl`, `AmsItem`) | Orca's AMS widgets, fed by the projection | **Nothing**, beyond naming the unit *ACE 2 Pro* rather than *AMS* | +| Printer panel (`Plater.cpp` sidebar) | 7×15 px bars in an ad-hoc strip | **Badge** in the head box | +| Assignment dialog (`resources/web/aceplan`) | 96 px `.pos` cards in a teal `.acebox` | **Spool box** + `AMSLib` columns; keep the drag targets | +| U1 + multiACE page (`resources/web/multiace`) | 60 px circular spools; 36 px circular swatches | **Spool box** + `AMSLib` columns. The circles are the biggest departure and the one worth losing — nothing else in Orca draws filament round | + +**Note on `AMSPreview`.** The 82×27 strip of 14×14 cubes is real, shipping code, but it +has only two call sites — `AMSControl.cpp:1173` (the unit selector) and +`CalibrationWizardPresetPage.cpp:617`. `AMS_ITEM_CUBE_SIZE` appears nowhere else: the +cube is internal to that widget and is never drawn alone. It is documented here so the +two native surfaces are not diverged from, not as a form to build with. + +**One arithmetic snag** if `AMSPreview` is ever reused: padding 7 plus four 14 px cubes +plus three 5 px gaps is 85, not the 82 the constant states. Callers size the preview +themselves today. Fix it once rather than per surface. diff --git a/docs/ace-mmu/17-plate-template.md b/docs/ace-mmu/17-plate-template.md new file mode 100644 index 00000000000..8c71450a080 --- /dev/null +++ b/docs/ace-mmu/17-plate-template.md @@ -0,0 +1,119 @@ +# The U1 plate template + +Interactive sheet: [plate-thumbnails-options.html](plate-thumbnails-options.html) · +Used by: [15-printer-panel.md](15-printer-panel.md) (the plate card) + +One silhouette, four plates, two ways of filling it. The same relationship +[16-ace-visuals.md](16-ace-visuals.md) has to the ACE: a shape that is fixed, so every +surface that draws a build plate draws the same object. + +## The silhouette + +**Measured, not traced.** A first attempt was drawn by eye from the product photos and was +wrong in every dimension — deep crenellations where the plate has small nicks. So the +product PNG was decoded to raw pixels (pure Python: `zlib` + manual unfiltering, no imaging +library needed), thresholded against the background, and the top and bottom edges sampled +column by column. + +| Property | Measured | +|----------|----------| +| Plate | 391 × 413 px → **aspect 0.947**, slightly taller than wide | +| Top notches | three, centred at **x 26 / 50 / 74** | +| Notch size | ~**6 wide**, **2.9 deep** | +| Bottom tongue | **x 23 → 77.5**, protruding **2.9** below the side edges | +| Corner radius | **~2** | + +All as percentages of the plate's own box: width 100, height 105.6. **Do not re-trace by +eye.** + +## Drawing it: emphasised, deliberately + +At 44 × 40 — the plate card's thumbnail — a 2.9 % notch is **just over one pixel**. Drawn +truthfully the U1 plate is a rounded square with three nicks nobody can resolve, and the +silhouette contributes nothing. Exaggerating is a normal icon convention, but it is a +decision, so it was taken explicitly rather than arrived at by sloppy tracing. + +Four points along that axis were drawn and compared (*As measured*, *Emphasised*, +*Exaggerated*, *Plain*). **Emphasised** was chosen: the measured notches roughly doubled, +enough to register as a notched plate at a glance without reading as a different object. + +``` +platePath(notchDepth, notchHalfWidth, tongueDepth, cornerRadius) + measured (3.06, 3.0, 3.06, 2) + emphasised (5.5, 3.8, 4.2, 2) ← chosen +``` + +The chosen path, in a `0 0 100 105.6` viewBox: + +``` +M2 0 H22.2 L26 5.50 L29.8 0 H46.2 L50 5.50 L53.8 0 H70.2 L74 5.50 L77.8 0 +H98 A2 2 0 0 1 100 2 V99.40 A2 2 0 0 1 98 101.40 +H79.5 L77 105.60 H23 L20.5 101.40 H2 A2 2 0 0 1 0 99.40 V2 A2 2 0 0 1 2 0 Z +``` + +**Aspect is preserved, never stretched.** The plate is taller than wide and the card slot +is 44 × 40, so the drawing letterboxes. Squashing it would change the notch proportions, +which is the one thing the silhouette exists to carry. + +## Filling it + +**Photograph Snapmaker's own plates. Draw everything else generically.** + +The three plates Snapmaker sells for the U1 are first-party products for their bed types, +so a photograph is simply what the plate looks like. Anything else is drawn: the nearest +real product is somebody else's, and using it would brand a **bed type** — an abstract +setting — with a vendor the app never otherwise mentions. Whoever selects *Cool Steel +Plate* may own any plate, or none. + +| Bed type | Enum | Fill | Source | +|----------|------|------|--------| +| Textured PEI Plate | `btPEI` | photo | Snapmaker product shot | +| Smooth PEI Plate | `btPTE` | photo | Snapmaker product shot | +| Graphic Effect Plate | `btGESP` | photo | Snapmaker product shot | +| Cool Steel Plate | `btSuperTack` | **drawn** | cool blue, soft sheen, no maker's marks | + +That is the U1's whole default set. The advanced-mode plates +(`support_multi_bed_types`: Cool Plate, Engineering, Textured Cool) are out of scope; when +they arrive they are **drawn**, by the same rule. + +**Sampling a photograph.** Take the middle of the flat product shot, zoomed ~150–195 % so +the crop lands inside the plate's surface, then clip to the silhouette. Never fit the whole +photo — the background and the plate's own edge would come with it, and the silhouette is +already doing that job. *Smooth PEI is matte black*, not amber; only Textured PEI is the +bronze people picture when they hear "PEI". + +**Drawing a plate.** Paths and gradients only — icon SVGs go through **nanosvg** +(`BitmapCache.cpp:18`), which has no filters, no `` and no CSS. A base gradient +plus one or two soft highlight sweeps is enough; do not invent surface detail that claims +to be a particular product. + +## Sizes and formats + +| Where | Size | +|-------|------| +| Plate card thumbnail | **44 × 40** | +| Plate picker cell | **40 × 36** | + +Photographs ship as **PNG at 1× / 2×** — the sources are `.webp` and `.jpg`, which Orca's +icon path cannot read. Drawn plates ship as **SVG**. + +## Two traps + +**Key off the enum, never the label.** The same `BedType` is named differently per printer: +`btPTE` is *Smooth High Temp Plate* generically and *Smooth PEI Plate* on the U1; +`btSuperTack` is *Cool Plate (SuperTack)* generically and *Cool Steel Plate* on the U1. +Match on the label and the U1 shows a Bambu plate under a Snapmaker name. + +**The card cannot be narrow without a picture.** Bambu's plate card is 92 px, so the label +clips to *Textur…* and the picture carries the identification. Without art, a 92 px card is +just clipped text — worse than the full-width `Bed type` row it replaces. Which is why the +row stays as it is until these exist. + +## Open + +**Licensing.** The three photographs are Snapmaker's, used here as design reference the way +`bambu_studio_inspiration/` holds Bambu's screenshots. Shipping them in an **AGPL-3.0** +repository needs permission. What can ship: ask Snapmaker, photograph the plates yourself, +or draw all four. The drawn cool plate has no such problem and is the model for anything +that has to be replaced — the silhouette and the sampling rules are unaffected either way, +so it is a swap of the fill, not a redesign. diff --git a/docs/ace-mmu/NEXT.md b/docs/ace-mmu/NEXT.md new file mode 100644 index 00000000000..fca49203632 --- /dev/null +++ b/docs/ace-mmu/NEXT.md @@ -0,0 +1,135 @@ +# Where this stopped, and what to do next + +**Branch:** `feat/u1-printer-panel`, cut from `origin/develop/add-multiace-support`. +**Contents:** design docs and mockups only. **No code.** Read this before touching anything. + +## What was produced + +| File | What it is | +|------|------------| +| [15-printer-panel.md](15-printer-panel.md) | The panel design: five measured defects, Bambu's shape for four heads, the ACE mode switch, two defects it uncovered, touch points, shipping order | +| [16-ace-visuals.md](16-ace-visuals.md) | The ACE visual standard: three forms under one rule, the spool box, the moisture pill, where a fill level comes from | +| [17-plate-template.md](17-plate-template.md) | The U1 plate template: the measured silhouette, the path the app draws, and when a plate is photographed rather than drawn | +| [printer-panel-mockup.html](printer-panel-mockup.html) | The panel, interactive: six machine states, the sync flow, the assign popover, the mode dropdown | +| [ace-visual-standard.html](ace-visual-standard.html) | The badge and its twins, the spool box, the pill — with the rejected alternates kept as the record | +| [plate-thumbnails-options.html](plate-thumbnails-options.html) | The four plates in the card, the silhouette variants that were weighed, and the advanced-mode ones noted | + +## Decisions taken — do not reopen without a reason + +- **Panel shape:** Bambu Studio's, from `bambu_studio_inspiration/`. Three cards across the + top; a bordered box per head wrapped 2×2; one `Nozzle` diameter row, not four tabs. +- **Naming:** **Toolhead N**, everywhere. Printer Settings already says it; the sidebar + said *Nozzle N* and the assignment dialog *T1–T4*. +- **No `Flow` row.** This fork deleted the control; there is no setting behind it. +- **ACE mode** is the printer's own three-way switch, mirrored as a labelled dropdown. +- **The assign popover is a choice, not a count** — two macros, so two kinds of row and a + tick. Units named as the printer names them (*ACE 2 Pro* / *ACE Pro*). +- **ACE visuals:** badge **A · Cabinet** (44×26 fill), glyph **O2 · Solid bays** (44×26 + line), square **S4 · Front face** (24×24 line). One rule: outlined chassis, solid bays. +- **Plate visuals:** one measured silhouette, drawn **Emphasised**; photograph Snapmaker's + own plates, draw everything else generically. Full spec in + [17-plate-template.md](17-plate-template.md). +- **No single-bay glyph.** Every ACE unit has exactly four slots. + +## Open — the only things still undecided + +**1. Licensing of the plate photographs.** Three of the four plate thumbnails are built +from Snapmaker's product photography, used here as design reference the way +`bambu_studio_inspiration/` holds Bambu's screenshots. Shipping them inside an +**AGPL-3.0** repository needs permission. What can ship: ask Snapmaker, photograph the +plates yourself, or draw all four the way Cool Steel already is. **This blocks the plate +card, nothing else** — and it is a swap of the fill, not a redesign: the silhouette, +sampling and sizes in [17-plate-template.md](17-plate-template.md) hold either way. + +**2. Whether the dev tooling comes over.** `.claude/tools/` lives on +`feat/ace-mmu-slicing` and is absent here. Every verification step below assumes it. See +*Traps*. + +Everything else about the panel, the ACE visuals and the plate template is decided and +written down. Where a decision was close, the alternates are kept in the mockups as the +record rather than deleted. + +## Shipping order + +Each step is one branch off `develop/add-multiace-support`, one squashed PR. + +| # | PR | Depends on | +|---|-----|-----------| +| 0 | **These docs** (this branch) | — | +| 1 | **Panel structure** — collapse the four identical nozzle tabs to one `Nozzle` row; move sync out of the title bar onto a labelled card | — | +| 2 | **Topology in the preset** — `ace_head_capacity` / `ace_head_unit`, the Multimaterial settings page, `sync_ace_topology` | — | +| 3 | **The panel's ACE row** — badge, assign popover, ACE mode dropdown | 1, 2 | +| 4 | **Sync info, two-step** — nozzle + topology in one press, chaining to the filament sync | 3 | +| 5 | **Per-unit capacity pool** — the shared-unit fix. Must land before a user can share a unit | 2 | +| 6 | **Combined mode** — the emitter's slot → (unit, slot) map. Until then the mode is listed and disabled | 2 | +| — | **Plate card** — assets plus a card. Independent of everything above | a decision | + +### PR 1, concretely + +Both changes are in `src/slic3r/GUI/Plater.cpp` and need no new config. + +1. `Sidebar::update_nozzle_settings` — check whether every `nozzle_diameter` value is + equal; build **one** page named `Nozzle` when they are, one per head named + **Toolhead N** when they are not. Safe: every existing use of + `m_nozzle_diameter_lists` iterates the whole list and writes the same value, so a + single entry is fine. +2. Move `m_printerinfo_syncbtn` off `m_panel_printer_title` onto a `StaticBox` card beside + the printer card, with a `Sync info` label and the whole card as the click target. Keep + the handler and the U1-only show/hide — retarget the show/hide to the card. + +This was written once and reverted; it is straightforward, but it was **never compiled or +run**, so treat it as a sketch, not a patch. + +## Facts established here — measured, not inferred + +- **The live printer** at `192.168.2.242` reports `mode: "head"`, `device_count: 1`, one + connected **ACE 2 Pro** (`protocol: "v2"`) at 39% RH feeding **Toolhead 4**, holding four + Kingroon/Generic PETG spools (`#83AFFF`, `#8FA7C8`, `#632C2C`, `#C47053`). +- **The mode switch is real firmware:** `SET_ACE_MODE MODE=normal|multi|head [HEAD=n]`, + with `ACE_SET_HEAD_ACE` / `ACE_SET_HEAD_FEEDER` documented "(head mode only)". Read from + `/printer/gcode/help`. +- **One unit may feed several heads.** `ACE_SET_HEAD_ACE` binds a head to one ACE and says + nothing about the reverse; `head_ace` is a map from head to unit. +- **A slot has no remain field.** Quantity comes from Spoolman via `spool_binding` + (`{"0_0":"15","0_1":"10","0_3":"16"}` → `weight_g` 500.1 / 997.7 / 843.1). One of the + four slots is unbound. A *percentage* is not derivable — the initial weight is not in + the payload. +- **Icon SVGs go through nanosvg** (`BitmapCache.cpp:18`): paths and gradients only, no + filters, no ``, no CSS. Anything photographic must ship as PNG. +- **The repo is AGPL-3.0**, so shipped assets must be licence-compatible. Snapmaker's + product photography is not. +- **The U1 connects as a `PrintHost`** through the webview, not as a `MachineObject`, so + the panel cannot use `MachineObject::poll_ace_ams()`. Resolve a host with + `AceMmuProvider::resolve_connected_host()` and read on demand. +- **Two defects found in existing code**, both in `15-printer-panel.md`: a shared unit + double-counts capacity in `AceMmuPlan.hpp`; Combined mode emits the wrong `ACE=`/`SLOT=` + in `GCode.cpp`. + +## Traps on this branch + +- **`develop/add-multiace-support` has no ACE code and no `docs/ace-mmu/` tree.** It is + upstream v2.3.6. Everything from `feat/ace-mmu-slicing` — the provider, planner, + dialogs, docs 01–14 — is absent. +- **`.claude/tools/` is absent too.** The headless-X harness, crash catcher and page + checker live on `feat/ace-mmu-slicing`. Bringing them over early is worth its own PR: + every step below is verified with them, and GUI claims made without them have been wrong + three times in this feature. +- **Switching branches invalidates the build** — the first build after a switch is a full + 622-target rebuild, not an incremental one. Budget for it. +- **Profile edits need a version bump**, or the app keeps its cached copy in + `~/.config/Snapmaker_Orca/system/` and the change silently does nothing. + +## How to verify anything in the GUI + +Reproduce, don't theorise. Three crashes in this feature were misdiagnosed from reading +code; each was settled in one run with the headless harness. Once `.claude/tools/` is on +this branch: + +``` +./.claude/tools/start.sh headless # Xvfb :99 + Orca, crash catcher armed +./.claude/tools/start.sh shot x.png # screenshot the virtual display +./.claude/tools/start.sh click X Y # click on it +./.claude/tools/start.sh trace # resolve the last crash to file:line +``` + +It runs against a copy of `~/.config/Snapmaker_Orca`, so it cannot disturb real presets. diff --git a/docs/ace-mmu/README.md b/docs/ace-mmu/README.md new file mode 100644 index 00000000000..07ae78c85da --- /dev/null +++ b/docs/ace-mmu/README.md @@ -0,0 +1,59 @@ +# multiACE on the Snapmaker U1 — design docs + +Design and research notes for running one or more Anycubic **ACE Pro / ACE 2 Pro** +filament changers on a **Snapmaker U1** from this slicer, via the printer-side +[multiACE](https://github.com/decay71/multiACE) service. + +Each document is written against **verified reality** — read from the running app, the +live printer at its REST endpoint, or the firmware's own macro help — rather than from +the code alone. Where something is unverified, it says so. + +## Start here + +**[NEXT.md](NEXT.md)** — what has been decided, what is still open, the shipping order, +and the traps on this branch. Read it before touching anything. + +## Documents + +| # | Document | Contents | +|---|----------|----------| +| 15 | [15-printer-panel.md](15-printer-panel.md) | **The U1 printer panel** in Prepare/Preview: the five defects, Bambu Studio's shape applied to four heads, the ACE mode switch, two defects it uncovered, and the shipping order | +| 16 | [16-ace-visuals.md](16-ace-visuals.md) | **The ACE visual standard**: one way to draw an ACE, taken from Orca's own AMS widget geometry — badge, glyph, spool box, moisture pill | +| 17 | [17-plate-template.md](17-plate-template.md) | **The U1 plate template**: the measured silhouette, the emphasised path the app draws, and when a plate is photographed rather than drawn | + +## Mockups + +Self-contained HTML, interactive. Open directly, or all at once with +`./.claude/tools/start.sh mockups`. + +| Mockup | For | +|--------|-----| +| [printer-panel-mockup.html](printer-panel-mockup.html) | [15](15-printer-panel.md) — the panel, every machine state, the sync flow and the assign popover | +| [ace-visual-standard.html](ace-visual-standard.html) | [16](16-ace-visuals.md) — the badge, its outlined and square twins, the spool box, the moisture pill | +| [plate-thumbnails-options.html](plate-thumbnails-options.html) | [17](17-plate-template.md) — the four plates in the card, the silhouette options that were weighed, and the advanced-mode ones noted | + +Each mockup is the specification the code is built against: when the two disagree, the +mockup is updated in the same commit, not left to drift. + +## Status + +**Design only. No code has landed on this branch.** Every implementation step is listed in +[NEXT.md](NEXT.md). + +## Numbering + +Documents are numbered in the order they were written, not in reading order — the number +is a stable handle for cross-references. **15 and 16 are the first of this set to land on +`develop/add-multiace-support`**; documents 01–14 cover the provider, data model, +slicing, planner and dialogs, and arrive with the PRs that implement them. + +## Conventions + +- **Measure, don't infer.** Three crashes in this feature were misdiagnosed from reading + code; each was settled in one run with `.claude/tools/start.sh` (headless X, crash + catcher, `THROW_LOG=1`). GUI claims are made from screenshots, printer claims from the + printer. +- **Status vocabulary:** *done* = observed working end to end · *built* = written and + compiles, not yet observed · *gap* = not written. +- **Say what is not known.** A doc that hides an unverified assumption costs more than + one that names it. diff --git a/docs/ace-mmu/ace-visual-standard.html b/docs/ace-mmu/ace-visual-standard.html new file mode 100644 index 00000000000..d0320afd531 --- /dev/null +++ b/docs/ace-mmu/ace-visual-standard.html @@ -0,0 +1,1006 @@ + + +The ACE visual standard + + +
+ +
+

The ACE visual standard

+

An ACE is drawn four different ways today. The device page gives it 60 px circular + spools; the assignment dialog gives it 96 px cards in a teal-banded box; the new + printer panel gives it 7×15 px bars in a rounded strip; and the filament-mapping + popup — which reads the ACE through amsList — already gives it + Orca's real AMS widgets. Four languages for one object.

+

That last one is the way out. The ACE is projected onto Ams/AmsTray + already, so the AMS widgets are the standard — the geometry below is lifted from + src/slic3r/GUI/Widgets/AMSItem.hpp rather than invented, which is what stops it + drifting again. Everything is drawn here at true size: 1 px = 1 DIP.

+

Four states are the ACE's own and have no AMS equivalent — an inferred spool + identity, a configured but absent unit, the toolhead a unit feeds, and a + temperature reading. Each is marked ACE where it appears.

+
+ +
+
+ Badge + + + + + + + +
+
+ Outline + + + + + + +
+
+ Square + + + + + + +
+
+ Slot 3 + + + + + + + +
+
+ Unit + + + + + +
+
+ Remaining + + + + + +
+
+ Moisture + + + + + + +
+
+ + +
+
1The badge — four spools in a box
+
+

Five ways to draw it — all 44×26

+

The icon Bambu puts beside AMS in a nozzle box is not + AMSPreview — not a row of cubes but a little cabinet seen head-on, and + Orca ships no equivalent (ams_icon.svg is a 155×128 illustration). So here are + five candidates, from the faithful copy to the ones that lean on what this fork already draws. + Pick one and the whole page follows.

+
+

Each is drawn to the same 44×26 box and the same + four bays, so they are interchangeable in code — one function, one argument. Pick with + the Badge row in the deck and the rest of this page follows, including the states below. + Every one is shown twice: enlarged, and at true size in the row it actually lives in.

+

A is the faithful distillation of Bambu's icon — hood, bays, base + drawn over them. B keeps that silhouette but draws the chassis in line rather than fill, + so the colours carry and the grey mass goes away. C drops the chassis entirely and stands + the bays on AMSPreview's own ground, which is the least new invention of the five. + D is the ACE's front face: four bays cut into one body. E uses spool ends, which is + what the U1 + multiACE page already draws — picking it would make that page the + standard rather than the exception.

+
+

The outlined twin — the same cabinet, in line. + Where the badge says what is in it, the outline says what it is: it names an + ACE in a popover row, a settings label, a menu. So it is not a separate drawing — it is + A's own silhouette, one stepped path with the hood's shoulders on top and the base + stepping out at the bottom. Four ways to treat the bays inside it:

+
+

And a square twin, for icon slots. The cabinet is + 44×26 — it cannot go where the app wants a square: a tab, a menu row, a + ScalableButton. Squaring it is a real trade, because the ACE's four bays sit in a + row, and a row is wide. Four ways to spend the square, each shown at 48, at 24 and 16 + true size, and in the tab it would most likely appear in:

+
+

The trade, plainly. S1 changes nothing and + pays for it in size — at 16 px the bays are under a pixel. S2 fills the square + but the bays thin out. S3 adds an outline that competes with the cabinet's own. + S4 is the most legible small, at the cost of the hood-and-base step.

+ +
+

Settled — three forms, one rule

+

The picks turned out to share a rule, + which is a better outcome than three unrelated shapes: + outlined chassis, solid bays, at one stroke weight.

+
+

What the square costs, stated. S4 drops the + hood and the base step, so the square is not the same silhouette as the wide glyph + — the family is carried by the bay treatment and the stroke, not by the outline. That is + a deliberate trade: the two live in different places (a tab or menu icon versus a popover row + or label) and the square has a third of the width to say the same thing in. If they ever end + up side by side and the mismatch shows, S1 is the fallback, because it is literally the + wide drawing scaled down.

+

Three definitions, not eight. The alternates stay on this page as the + record of what was weighed; the code ships + ace_badge(), ace_glyph() and ace_glyph_square() + and nothing else.

+
+

There is no single-bay variant. Bambu needs one + because an AMS Lite holds one spool; every ACE unit has exactly four slots — + /api/state returns "slots": [/* exactly 4 */] and + SLOT_COUNT = 4 is a constant, not a configuration. A one-bay glyph would depict a + machine that does not exist, so the family has four bays or none (O4), and nothing + between.

+
+
+ + +
+
2Moisture and temperature
+
+

The pill — 93×26 with a percentage, 60×26 without

+

AMSHumidity, unchanged: a pill (radius = half the height) on + AMS_CONTROL_DEF_BLOCK_BK_COLOUR, the hum_level1..5 droplet at 16 px, + then a 1 px #C2C2C2 divider and the dryer glyph when the unit can dry. + All of it already exists — icons, sizes, sentinel values.

+
+

The ACE reports a raw percentage where the AMS often reports only a 1–5 + bucket, and AMSinfo already handles exactly that split: humidity_raw = -1 + selects the numbered droplet, anything else selects the plain droplet plus the number. Your unit + reports humidity: 39, so it takes the second form. Bucket it as + 1 = ≤20, 2 = ≤35, 3 = ≤50, 4 = ≤65, + 5 = >65 to pick the glyph.

+

Temperature ACE is the one addition. The AMS carries + current_temperature in its info struct but never draws it in this widget; the ACE + reports temp per unit and it matters while drying. It goes in the same pill behind a + second divider, so there is still one chip to look at rather than three. When the unit reports no + temperature the segment is absent, not zeroed.

+

Drying swaps the sun (ams_drying) for the animated glyph + (ams_is_drying) exactly as support_drying() does, and the remaining time + belongs in the tooltip, not the pill — the pill is a glance, not a readout.

+
+
+ + +
+
3The box the spools sit in
+
+

Four spool objects in a light grey box

+

This is the AMS shape: a light grey box with four colour columns + standing in it. The column is AMSLib — 58×80 + (AMS_CAN_LIB_SIZE), a well inset by 4, and the filament colour drawn + from the bottom up to how much is left. Not a swatch on a card: a level in a tube, so a + row of them reads as an inventory at a glance.

+

Three greys, all from the AMS palette, each doing one job: #EEEEEE is + the band and also the empty tube, #F8F8F8 is the box the tubes + stand in. Selection is 2 px in the filament's own colour, which is + AMSLib's rule rather than the brand teal — hover is the teal.

+
+
+ A · Strip — 82×27 +
+ AMSPreview · inline: a head box, a mapping row, a list item +
+
+ B · Unit box — band + ground +
+ the ACE as an object: identity, the head it feeds, moisture, four slots +
+
+ C · Spool objects — 58×80 each +
+ AMS_CAN_LIB_SIZE · the column is how much is left +
+
+

The band carries identity, the ground carries contents. Left to right the band + is: unit number in a brand-coloured square, the model name the printer gives it + (protocol: "v2"ACE 2 Pro, "v1"ACE Pro), the + toolhead it feeds ACE, and the moisture pill hard right — which is + where Bambu puts it on the AMS.

+

Where the level comes from — and the one thing to settle. The AMS has + material_remain 0–100 and draws it directly. An ACE slot has no such + field: /api/state's slots[] carries material, brand, colour and + source, and nothing about quantity. But your printer runs spool_mode: "spoolman", + and spool_binding maps slots to Spoolman ids — + {"0_0":"15", "0_1":"10", "0_3":"16"} — each carrying a real + weight_g: 500 g, 998 g and 843 g. So three of + your four slots can drive the column honestly; S3 is not bound, which is why it is drawn + full but hatched and labelled amount unknown rather than pretending to be full.

+

What is not available is a percentage: Spoolman knows the initial weight, + this payload does not, so a column scaled to 1 kg would call an 843 g spool 84% when it + may be a full 850 g one. Show the grams, and treat the column as a gauge rather than a + measurement — or fetch remaining_weight from Spoolman directly and scale + it properly, which is its own small piece of work. + AceSlot parses none of this today ACE, so wiring the + binding through is the prerequisite for the column meaning anything.

+

A unit that is configured but not answering ACE has no + AMS equivalent: an AMS is only reported when present, whereas an ACE lives in the preset and the + printer may be off, on cloud, or short of a unit. It takes + AMS_CONTROL_DISABLE_COLOUR through the same Enable(false) path the AMS + widgets already have — grey cubes, grey badge, grey text — so it is legibly there + but unreadable, rather than absent or, worse, empty.

+
+
+ + +
+
4The numbers, and where they come from
+
+

One source, two implementations

+

The ACE is drawn in native wx (the sidebar, the mapping popup) and in webviews + (the assignment dialog, the U1 + multiACE page). So the standard is one spec with two + implementations, and the numbers are pinned to the existing macros so the two cannot drift.

+
+ + + + + + + + + + + + + + + + + + + + +
Thingwx macroValueCSS token
ACE badge— (new)44×26 fillace_badge()
ACE glyph— (new)44×26 line, stroke 1.6ace_glyph()
ACE glyph, square— (new)24×24 line, stroke 1.6ace_glyph_square()
Slot cubeAMS_ITEM_CUBE_SIZE14×14, r2internal to AMSPreview — never drawn alone
StripAMS_ITEM_SIZE82×27, r3, pad 7, gap 5.strip
Strip + moistureAMS_ITEM_HUMIDITY_SIZE120×27.strip + .pill
Slot cardAMS_CAN_LIB_SIZE58×80.lib
Moisture pillAMS_HUMIDITY_SIZE93×26, r13.pill
… level onlyAMS_HUMIDITY_NO_PERCENT_SIZE60×26.pill.short
Band groundAMS_CONTROL_DEF_BLOCK_BK_COLOUR#EEEEEE--ams-block-bk
Spool groundAMS_CONTROL_DEF_LIB_BK_COLOUR#F8F8F8--ams-lib-bk
SelectionAMS_CONTROL_BRAND_COLOUR#009688, 2px--ams-brand
UnreadableAMS_CONTROL_DISABLE_COLOUR#CECECE--ams-disable
Pill divider— (literal in AMSHumidity)#C2C2C2, 20px--ams-rule
Dropletshum_level1..5_{light,dark}16px SVGsame files
Dryerams_drying / ams_is_drying16px SVGsame files
+
+

One arithmetic snag to settle in code: padding 7 plus four 14 px cubes + plus three 5 px gaps is 85, not the 82 the constant states. The AMS gets away with it because + callers size the preview themselves. For the ACE, fix it once — gap 4 lands exactly on + 82 — rather than letting each surface pick.

+
+
+ + +
+
5What changes where
+
+

Every surface that draws an ACE

+
+ + + + + + + + + + + + + + + + + + + +
SurfaceDraws nowBecomes
Filament mapping popup
AmsMappingPopup.cpp
Orca's AMS widgets, via the amsList projectionNothing. It is already the standard — this is the reference.
Printer panel
Plater.cpp sidebar
7×15 px bars in an ad-hoc rounded stripA — Strip (82×27), four 14 px cubes. Same width as the AMS row it mirrors.
U1 + multiACE page
resources/web/multiace
60 px circular spools with a hub; 36 px circular swatchesB — Unit box with C — slot cards. The circles are the biggest + departure and the one worth losing: nothing else in Orca draws filament round.
Assignment dialog
resources/web/aceplan
96 px .pos cards in a teal-banded .aceboxB + C, keeping the drag targets. Closest already; mostly re-tokening.
Device / AMS tab
AMSControl, AmsItem
Orca's AMS widgets, fed by the projectionNothing, beyond naming the unit ACE 2 Pro rather than AMS.
+
+

Order I would take it: the strip ships with the printer panel, since that PR + is drawing one anyway and it is the cheapest place to prove the tokens. The unit box and slot cards + then land as one restyle PR across the two web pages, which is where the four languages actually + collapse into one. The two native surfaces need no work at all — which is the argument for + this standard rather than a new one.

+
+
+ +
+ + diff --git a/docs/ace-mmu/plate-thumbnails-options.html b/docs/ace-mmu/plate-thumbnails-options.html new file mode 100644 index 00000000000..56925c051a7 --- /dev/null +++ b/docs/ace-mmu/plate-thumbnails-options.html @@ -0,0 +1,415 @@ + + +U1 build plates in the UI + + +
+
+

U1 build plates in the UI

+

Snapmaker sells three plates for the U1 — Textured PEI, Smooth PEI and Graphic + Effect — and both the EU and US stores list exactly those, one variant each. Their product + photography is below, sampled at the plate's centre so what you see is the surface + rather than the silhouette.

+

And a fourth, from elsewhere. Cool Steel Plate is in the U1's default list but + Snapmaker does not sell it separately, so there was no photo for it. BIQU's + CryoGrip + Pro for the Snapmaker U1 fills that slot: a double-sided 7-layer composite in two + finishes — Frostbite (coarse) and Glacier (fine) — and, for Glacier, five + colours. Same U1 mount, so the measured silhouette carries over unchanged.

+

Scope: these three, plus Cool Steel. The app can offer more — turning on + support_multi_bed_types swaps the U1's list for a longer one that includes Cool + Plate, Engineering Plate and the rest of the Bambu-lineage set. Those are + deliberately out of scope here; §3 records what they are and what they would need, so + the decision is on paper rather than rediscovered later.

+
+ +
+
1Three photographed, one drawn
+
+

Photographed, cropped to surface

+

The first three sample the middle of Snapmaker's own flat product shot; Cool + Steel is drawn, because Snapmaker does not sell one. Worth noting because I had guessed + wrong before looking: Smooth PEI is matte black, not amber — only Textured PEI + is the bronze people picture when they hear "PEI".

+
+
+

The shape is measured, not traced. My first + attempt was drawn by eye and was wrong in every dimension — deep crenellations where + the plate has small nicks. So the product PNG was decoded to raw pixels and the top and + bottom edges sampled per column. The plate is 391×413 (aspect 0.947); the three + top notches sit at x 26 / 50 / 74, each about 6 wide and 2.9 deep; the + bottom has a tongue from x 23 to 77.5 protruding 2.9 below the sides; + corners are radius ~2. All as percentages of the plate's own box.

+

How literal to draw it was a real choice. A notch 2.9% deep on a + 40 px-tall thumbnail is just over one pixel — drawn truthfully, the plate + is a rounded square with three nicks nobody will see. Exaggerating is a normal icon + convention but it is a decision, so it was made deliberately: Emphasised, the + measured notches roughly doubled. The alternates stay as the record of what was weighed.

+
+

Only Snapmaker's own plates are photographed. The first three are + first-party products for their bed types, so a photo is simply what the plate looks like. + Cool Steel is drawn instead — Snapmaker does not sell it separately, and the + nearest real product is a third party's (BIQU's CryoGrip Pro, which does fit the U1). Using + that art would brand a bed type with a vendor the app never otherwise mentions, and + a user selecting Cool Steel Plate may own any plate or none. So it is a generic cool + plate: a cool blue with a soft sheen, no maker's marks, no invented texture pretending to be + a particular surface. The same rule applies to the advanced-mode plates if they are + ever added.

+

Shape as well as surface. A square crop showed the material but could + have been any plate on any printer. These are clipped to the U1 plate's own outline + — three shallow notches along the top and a wide tongue along the bottom — so + the three plates share a shape that says they belong to the same machine, which is most of + what a thumbnail can usefully carry.

+

Aspect is preserved, not stretched. The plate is square, the card slot + is 44×40, so the drawing letterboxes rather than squashing — the notches stay the + shape they are on the real plate. The texture underneath is still sampled from the middle of + the photo, so no background or perspective creeps in at the edges.

+
+
+ +
+
2In the panel
+
+

The plate card, and the picker behind it

+

The card is 92 px — the width Bambu uses — so the label clips to + Textur… and the picture carries the identification. Click a plate below to change + the card.

+
+

This is why the card can be narrow. With a picture, a clipped label is + a caption; without one it is just clipped text, which is why the row stays full-width until + the art exists.

+
+
+ +
+
3Noted, not now — the advanced-mode plates
+
+

What else the enum can offer, and why it waits

+

PrintConfig.cpp holds three bed-type lists, not one: the + generic Bambu set of six, the U1's own set (// U1 only 4), and a seven-entry + set used when support_multi_bed_types is on (// U1 use 7 …). + Only the first three rows below are plates Snapmaker sells for the U1 — the rest appear + only in that advanced mode, and are left alone for now.

+
+ + + +
EnumName on the U1Name genericallyThumbStatus
+
+

The trap to remember when they are picked up. The same + BedType value is named differently depending on the printer: + btPTE is Smooth High Temp Plate generically but Smooth PEI Plate + on the U1, and btSuperTack is Cool Plate (SuperTack) generically but + Cool Steel Plate on the U1. So a thumbnail must key off the enum value, never + the label — otherwise the U1 shows a Bambu plate under a Snapmaker name, or nothing at all.

+

Cool Steel is the awkward one and worth flagging now: it sits in the + U1's default list of four, yet Snapmaker does not sell it separately — it ships + with the printer, so there is no product page to photograph from. If the U1's default set + should be complete, that is the one plate you would have to shoot yourself.

+
+
+ +
+
4Before any of this ships
+
+

These images are Snapmaker's. They are used here + as a design reference, the same way bambu_studio_inspiration/ holds Bambu's + screenshots. Shipping them inside an AGPL-3.0 repository is a different question and + the answer is probably no without permission — so the options that actually ship are: ask + Snapmaker, photograph the plates yourself, or draw them. + decide before PR

+

And a format note. Two of the three sources are .webp, + which Orca's icon path cannot read — BitmapCache.cpp goes through nanosvg for + SVG and wxWidgets handlers for raster. Whatever is chosen ships as PNG at 1×/2×, or + as SVG if drawn.

+
+
+
+ + diff --git a/docs/ace-mmu/printer-panel-mockup.html b/docs/ace-mmu/printer-panel-mockup.html new file mode 100644 index 00000000000..bb63b2927ce --- /dev/null +++ b/docs/ace-mmu/printer-panel-mockup.html @@ -0,0 +1,954 @@ + + +The U1 printer panel + + +
+ +
+

The U1 printer panel

+

Prepare and Preview share one sidebar, so the Printer section at the top of it is a single + widget seen in two tabs. This rebuilds it to Bambu Studio's shape: three cards across the top, + a bordered box per head, a green corner tick where the app agrees with the machine, an edit + popover behind the ACE row, and the two-step Sync info flow that ends by offering to sync + filaments.

+

The panel below is interactive, and the Your U1 scenario carries real values — + the ACE, its mode and its four PETG spools, read from 192.168.2.242 on 21 Aug 2026. + They are a snapshot, baked into this page: it is a static file and does not talk to the + printer, and as a published artifact it could not reach your LAN even if it tried. Press + Sync info, open a head's ACE widget, choose an ACE mode, and switch the machine + underneath it. Every screenshot further down is the Bambu original the corresponding piece is + copying.

+

One row has no Bambu equivalent, because the U1 needs it: ACE mode. The printer has its + own three-way switch — SET_ACE_MODE MODE=normal|multi|head — and it + decides whether per-toolhead wiring means anything at all. The panel mirrors it, and Sync info + reads it. That switch is also the answer to “can one unit feed more than one head”: + in Per toolhead mode, yes — tick the same unit on two heads.

+
+ + +
+
ProposedBambu's panel, for four heads
+ +
+
+ Machine + + + + + + + + +
+

+
+ +
+
+
+
Plate 1
+
+
+
+ + +
+
ReferencePiece by piece, against the original
+
+ +
+
+
+ Bambu Studio printer cards +
+

Bambu Studio · H2D

+
+
+

Three cards, and a tick that means something

+

Printer, plate, and Sync info sit side by side at equal height; the printer card + carries its thumbnail above the preset combo, the plate card an , and the + green corner triangle marks a card that agrees with the connected machine.

+

Ours is the same three. The plate card takes over today's Bed type row, + which frees the whole row it used. The corner tick appears on the printer card when the + selected preset matches the machine's reported model and nozzle size — and on a head + box when its ACE wiring matches what the printer reports. That is a claim we can actually + make, because sync_ace_topology already computes exactly that diff.

+
+
+ +
+
+
+ Bambu Studio nozzle boxes +
+

Bambu Studio · per-nozzle boxes

+
+
+

A box per head, two across

+

Bambu draws Left Nozzle and Right Nozzle as two bordered panes, each with an + AMS row, a Diameter combo and a Flow combo. The AMS row shows a small + thumbnail of the loaded spools when a unit is attached, and a chevron when none is.

+

Ours is four of the same box, wrapped 2×2. Same label position, same row + grammar, same widths — the ACE row shows the unit's spool colours as a strip, + or a chevron on a stock feeder. Flow is absent: this fork deleted it deliberately and there + is no setting behind it.

+
+
+ +
+
+
+ Bambu Studio AMS count popup +
+

Bambu Studio · AMS popover

+
+
+

The popover that sets what is attached

+

Clicking the pencil beside AMS drops a panel: a sentence, then a grey inset listing + each kind of unit with a spinner — AMS (4 slots), AMS (1 slot).

+

Ours keeps the sentence and the inset, and swaps the spinner for a tick. A count + is the wrong control here: multiACE binds a head to one named unit + (ACE_SET_HEAD_ACE HEAD=n ACE=u) or puts it on its own feeder + (ACE_SET_HEAD_FEEDER), so the list is a choice — one row per macro, + one tick. Units carry the printer's own names, ACE 1 · ACE 2 Pro, with slots, + connection and humidity beneath. Between them the two rows write exactly + ace_head_capacity and ace_head_unit. Open Toolhead 4's + ACE widget in the panel above to use it.

+
+
+ +
+
+
+ Bambu Studio sync confirmation +
+

Bambu Studio · after Sync info

+
+
+

Sync in two steps, not one

+

Bambu's Sync info reads nozzle and AMS-count information, then says so and offers + Continue to sync filaments beside Cancel — the count sync and the + contents sync are separate presses, chained by an offer.

+

Ours chains the two that already exist. Step one is today's nozzle query plus + sync_ace_topology in one press; step two hands off to + Sync Filament Information, which already lists the four toolheads and every ACE slot. + Press Sync info in the panel above to walk it, including what it says when the + printer is off and when the preset turns out to be wrong.

+
+
+ +
+
+
+ Bambu Studio project filaments +
+

Bambu Studio · the section below

+
+
+

And the half of the screenshot below the fold

+

The same screenshot continues into Project Filaments: a numbered, colour-coded badge + per filament in two columns, a menu on each, add/remove/sync/settings in the + sub-header, a Purging volumes pill on the title bar, and a corner tick on each + filament that matches what the AMS holds.

+

That is a different section and a different PR. This fork already has it as + Filament Management — badges, combos, per-filament menus, flushing volumes and + Color Mixing — so it is a restyle rather than a rebuild, and it is the natural + follow-on once the printer section lands. The panel above ends on its title bar to show + where the seam is.

+
+
+ +
+
+ + +
+

The four places it cannot follow Bambu, and what it does instead

+
    +
  1. Four heads, not two nozzles. Bambu's two boxes sit side by side across the sidebar. + Four at that width would be 110 px each — too narrow for a labelled combo. So the same + box is wrapped 2×2, which keeps Bambu's proportions and costs one extra row of + height. That row lands in Preview too, where the sidebar competes with the sliced preview: + the head boxes are the section to collapse first if it proves too tall.
  2. + +
  3. An ACE is not an AMS, and the popover is a choice rather than a count. Bambu counts + interchangeable units by kind, so a spinner fits. multiACE binds a head to a named unit + with ACE_SET_HEAD_ACE HEAD=h ACE=a, or puts it on its own feeder with + ACE_SET_HEAD_FEEDER HEAD=h ENABLE=1 — two macros, so two kinds of row and a + tick rather than a number. Units are named as the printer names them: ACE 1 · ACE 2 + Pro from protocol: "v2", ACE Pro from "v1", with slot + count, connection and humidity underneath.
  4. + +
  5. No Flow row. Bambu's third row picks a flow calibration; this fork removed the control + and there is no setting behind it. Adding a dead combo to look like the screenshot would be + worse than the gap. The head box has two rows, not three.
  6. + +
  7. Contents are LAN-only. Bambu reads AMS state over its cloud, so its panel is populated + whenever the printer is online. The multiACE endpoint answers only on the local network, so over + a cloud connection there is no snapshot at all. The panel then draws the preset's topology + — which is real, and is what offline slicing uses — with contents muted rather than + blank, so it does not change height when a printer appears.
  8. +
+
+ +
+

One unit, several heads — and the two bugs it uncovers

+

Read from the printer's own firmware + (/printer/gcode/help on 192.168.2.242), not inferred:

+
    +
  1. The mode is the printer's, so the panel should not invent one. + SET_ACE_MODE MODE=normal|multi|head. Normal is stock feeders and no ACE; + head wires each head individually; multi pools units onto one ACE head. Only in + head mode does per-toolhead assignment mean anything — which is why the mode row + sits above the head boxes and greys them out in Normal. The live machine is in + mode: "head".
  2. + +
  3. Sharing is legal, and the popover is where it happens. ACE_SET_HEAD_ACE + says each head is wired to exactly one ACE — it says nothing about each ACE + feeding exactly one head, and head_ace is a map from head to unit, so several + heads may name the same one. In the panel: tick ACE 1 on Toolhead 4, then tick it on + Toolhead 1. Each row then reads also feeds Toolhead 4, and a warning appears + under the boxes. Try the Shared unit scenario.
  4. + +
  5. Bug 1 — a shared unit double-counts capacity. AceMmuPlan.hpp sums + capacity per head (total_cap += cap[h]) and enforces it per head + (if (++load[h] > cap[h])). Two heads on one 4-slot unit therefore read as + 8 places when there are 4. The infeasible-plate refusal — the whole point of which + is to catch exactly this — would wave through a plate that cannot be laid out. The fix is + a per-unit pool constraint beside the per-head one; the panel already computes and shows the + honest number.
  6. + +
  7. Bug 2 — Combined mode cannot be emitted today. ace_head_capacity + already offers ACE – 6 slots and ACE – 8 slots, but + GCode.cpp's unit_of_head() returns the single + ace_head_unit[h], and the plan's slot is an index within the head. So slot + 5 of an 8-slot head emits ACE=<first unit> SLOT=5 where the machine needs + ACE=<second unit> SLOT=1 — wrong unit, wrong slot, wrong colour. Those + two enum values are not safe until the emitter maps slot → (unit, slot).
  8. +
+

So the sequencing I would take: + ship the panel with Normal and Per toolhead, and leave Combined in the list + but disabled with the reason on it, until the emitter fix lands. Sharing can ship with the panel + — it is drawn honestly and warns — but the planner's per-unit pool should be the very + next PR, because a wrong capacity is a silently wrong plate.

+
+ + +
+

What already exists

+
+ + + + + + + + + + + + + + + + + + +
PieceWhereState
The panelPlater.cpp:2199–2565Title bar, preset card, Bed type row, nozzle notebook — built once in the Sidebar constructor. The three-card row replaces the first two.
The head boxesSidebar::update_nozzle_settings, Plater.cpp:8682Already rebuilds one page per nozzle_diameter entry. Becomes a 2×2 grid of boxes instead of a notebook.
Sync, step one (nozzles)Plater.cpp:2214–2350Queries the machine, opens NozzleDiameterSelectDialog on mixed diameters, selects the matching preset. Keep as-is; it becomes half the press.
Sync, step one (topology)TabPrinter::sync_ace_topology, Tab.cpp:4652Reads /multiace/api/state, diffs per head, writes both options and reports what changed. Lift out of TabPrinter so the sidebar can call it too.
Sync, step two (filaments)Sidebar::show_sync_filament_dialog, Plater.cpp:8467The non-destructive filament sync, already listing U1 toolheads and ACE slots via append_ace_filament_list. This is what Continue to sync filaments opens.
The topologyace_head_capacity, ace_head_unitPer-head coInts in the printer preset, so the panel and offline slicing share one source.
Live contentsAceMmuProvider, AceSnapshotUnits, slots, colours, materials, humidity, per-head ace/slot bindings. One fetch_once().
+
+

One thing to know before building: the U1 connects as a + PrintHost through the webview, not as a MachineObject, so this panel + cannot lean on MachineObject::poll_ace_ams() the way the AMS UI does. It resolves a + host with AceMmuProvider::resolve_connected_host() and reads on demand — which + is the other reason Bambu's press-to-sync flow fits the U1 better than a background poll.

+
+ +
+ + From 3bbb943e5cc0682d2e432df1d7bb59dd00b054f6 Mon Sep 17 00:00:00 2001 From: physicsG Date: Fri, 21 Aug 2026 20:30:33 +0200 Subject: [PATCH 02/18] docs(ace-mmu): keep third-party reference imagery out of the repo The mockups embedded Bambu Studio's screenshots and Snapmaker's product photos as base64, which put third-party imagery into an AGPL-3.0 repository to make a design document render. Reference material is worth keeping; redistributing it is not ours to do. The snapshots move to ui-snapshots-inspiration/, which is gitignored and carries a README saying what is in it and where to re-download it. The mockups now reference those files by relative path, so with the folder present they render exactly as before, and without it each frame shows a caption naming the folder rather than a blank. The panel mockup drops from 344 KB to 51 KB and the plate mockup from 631 KB to 26 KB. Nothing about the designs changes. The drawn cool plate was already ours and is untouched, and it is the model for replacing the photographs if permission is not sought - the silhouette, sampling and sizes in 17-plate-template.md hold either way. Co-Authored-By: Claude Opus 5 --- .gitignore | 4 +++- docs/ace-mmu/15-printer-panel.md | 2 +- docs/ace-mmu/17-plate-template.md | 2 +- docs/ace-mmu/NEXT.md | 4 ++-- docs/ace-mmu/plate-thumbnails-options.html | 16 +++++++++++----- docs/ace-mmu/printer-panel-mockup.html | 19 ++++++++++++------- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 695cb8f3b33..7bb24ce4951 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,6 @@ resources/profiles/user/default deps_src/build/ .claude/ .hermes/ -CLAUDE.md \ No newline at end of file +CLAUDE.md +# UI reference snapshots — third-party imagery, design reference only (see the folder's README) +ui-snapshots-inspiration/ diff --git a/docs/ace-mmu/15-printer-panel.md b/docs/ace-mmu/15-printer-panel.md index fedf3dbaeae..decad355dc5 100644 --- a/docs/ace-mmu/15-printer-panel.md +++ b/docs/ace-mmu/15-printer-panel.md @@ -28,7 +28,7 @@ Measured by running the app, not by reading it (`.claude/tools/start.sh headless ## The shape: Bambu's panel, for four heads -Taken from `bambu_studio_inspiration/Nozzle_and_filament_info/`, piece by piece. +Taken from `ui-snapshots-inspiration/Nozzle_and_filament_info/`, piece by piece. - **Three cards across the top** — printer (thumbnail over preset combo), plate (texture swatch + ⓘ, absorbing today's `Bed type` row), and **Sync info**. diff --git a/docs/ace-mmu/17-plate-template.md b/docs/ace-mmu/17-plate-template.md index 8c71450a080..5be30f16f58 100644 --- a/docs/ace-mmu/17-plate-template.md +++ b/docs/ace-mmu/17-plate-template.md @@ -112,7 +112,7 @@ row stays as it is until these exist. ## Open **Licensing.** The three photographs are Snapmaker's, used here as design reference the way -`bambu_studio_inspiration/` holds Bambu's screenshots. Shipping them in an **AGPL-3.0** +`ui-snapshots-inspiration/` holds Bambu's screenshots. Shipping them in an **AGPL-3.0** repository needs permission. What can ship: ask Snapmaker, photograph the plates yourself, or draw all four. The drawn cool plate has no such problem and is the model for anything that has to be replaced — the silhouette and the sampling rules are unaffected either way, diff --git a/docs/ace-mmu/NEXT.md b/docs/ace-mmu/NEXT.md index fca49203632..d2417ea9633 100644 --- a/docs/ace-mmu/NEXT.md +++ b/docs/ace-mmu/NEXT.md @@ -16,7 +16,7 @@ ## Decisions taken — do not reopen without a reason -- **Panel shape:** Bambu Studio's, from `bambu_studio_inspiration/`. Three cards across the +- **Panel shape:** Bambu Studio's, from `ui-snapshots-inspiration/`. Three cards across the top; a bordered box per head wrapped 2×2; one `Nozzle` diameter row, not four tabs. - **Naming:** **Toolhead N**, everywhere. Printer Settings already says it; the sidebar said *Nozzle N* and the assignment dialog *T1–T4*. @@ -35,7 +35,7 @@ **1. Licensing of the plate photographs.** Three of the four plate thumbnails are built from Snapmaker's product photography, used here as design reference the way -`bambu_studio_inspiration/` holds Bambu's screenshots. Shipping them inside an +`ui-snapshots-inspiration/` holds Bambu's screenshots. Shipping them inside an **AGPL-3.0** repository needs permission. What can ship: ask Snapmaker, photograph the plates yourself, or draw all four the way Cool Steel already is. **This blocks the plate card, nothing else** — and it is a swap of the fill, not a redesign: the silhouette, diff --git a/docs/ace-mmu/plate-thumbnails-options.html b/docs/ace-mmu/plate-thumbnails-options.html index 56925c051a7..5cd2103a64c 100644 --- a/docs/ace-mmu/plate-thumbnails-options.html +++ b/docs/ace-mmu/plate-thumbnails-options.html @@ -74,8 +74,12 @@ .pl.miss{background:repeating-linear-gradient(45deg,var(--inset),var(--inset) 5px,transparent 5px,transparent 10px); display:grid;place-items:center;color:var(--faint);font-size:9px;text-align:center;line-height:1.1;} /* whole-plate view, for the record */ - .pw{border-radius:6px;border:1px solid var(--line);background:#fff;background-repeat:no-repeat; - background-position:center;background-size:contain;} + /* Source shots are third-party and deliberately not in git; with + ui-snapshots-inspiration/ present they load, without it this caption shows. */ + .pw{border-radius:6px;border:1px solid var(--line);background-color:var(--inset); + background-repeat:no-repeat;background-position:center;background-size:contain; + position:relative;display:grid;place-items:center;text-align:center;padding:10px; + font-size:10px;line-height:1.45;color:var(--faint);} .sb{width:462px;max-width:100%;background:var(--sb-panel);border:1px solid var(--line);border-radius:8px; overflow:hidden;color:var(--sb-text);font-size:13px;box-shadow:var(--shadow);} @@ -238,7 +242,7 @@

What else the enum can offer, and why it waits

4Before any of this ships

These images are Snapmaker's. They are used here - as a design reference, the same way bambu_studio_inspiration/ holds Bambu's + as a design reference, the same way ui-snapshots-inspiration/ holds Bambu's screenshots. Shipping them inside an AGPL-3.0 repository is a different question and the answer is probably no without permission — so the options that actually ship are: ask Snapmaker, photograph the plates yourself, or draw them. @@ -254,7 +258,9 @@

What else the enum can offer, and why it waits