openpencil/crates
Kayshen-X d8d6e127cd feat(shell-web): Phase B3 — wire WidgetHost into mount path
Replaces the Phase A red-rect demo with the Step 1b inspector
composition: WebShell now owns a `WidgetHost` and `mount()` paints
the four shell-core widgets (Tree / PropertyRow / Dropdown /
TextInput) into a 280-px column on a white-cleared canvas.

What's added:
- `crates/openpencil-shell-web/src/widget_host.rs` — the only file
  in shell-web that calls into `openpencil_shell_core::widgets::*`,
  per spec §1.4 boundary. Module doc anchors the invariant; the
  paint signature carries the `// glue:` marker that the Phase B4
  boundary check script (`tools/check-widget-boundary.sh`) will
  grep for.
- `WidgetHost { tree, width, dropdown, text_input }` owns one of
  each kind; `WidgetHost::new()` populates them from the B2 sample
  / new constructors. `Default` forwards to `new()`.
- `WidgetHost::paint(&self, backend, available_width)` builds a
  `LayoutCx`, iterates a `[&dyn Widget; 4]` array, places each at
  x=16 with 12-px vertical gaps. Reborrows backend each iteration
  (`&mut *backend`) so subsequent iterations don't fail
  borrow-check on the moved `&mut WebBackend`.

shell-web/src/lib.rs:
- Adds `mod widget_host;` cfg-gated to the `skia` feature.
- WebShell gains `host: WidgetHost`.
- Renames `paint_phase_a` → `paint_inspector`. Body clears the
  canvas to white, dispatches via `self.host.paint(...)`, then
  surfaces `take_present_error()` as JsValue exception. Same
  panic-safe + canvas-type-check + present-error-propagation
  pattern as Phase A C-hard.2 (codex Phase A gate review approved).
- The stub mount entry (no skia feature) is unchanged — the
  kickoff §1.2 wasm32-clean compile guard CI still uses it.

Plan-vs-implementation deviations (deliberate):
- Plan B3 step 2 simplifies `mount()` in a way that drops the
  panic hook + canvas-type-check + present-error propagation.
  Preserved all three because the codex Phase A gate review
  explicitly approved them as "panic-safe mount". Plan body's
  `mount` block is treated as historical sketch.
- Plan body's `let mut cx = PaintCx { backend };` would move the
  reference and fail borrow-check on the second iteration.
  Changed to explicit reborrow `&mut *backend`. This is the
  plan's intent, just with the borrow-checker subtlety made
  explicit.

Verification:
- `cargo build -p openpencil-shell-web --target
  wasm32-unknown-unknown --features skia --release` — green
- `cargo check -p openpencil-shell-web --target
  wasm32-unknown-unknown --no-default-features --features web` —
  green (compile guard)
- `bash tools/check-wasm-bundle.sh` — PASS
  - 0 env.* imports (bundle still LinkError-free)
  - 615 764 bytes gzip = 58% of 1 MiB ceiling
  - +2 KiB vs Phase A C-hard.2 (~613 KiB) — widget code is small
- `cargo check -p openpencil-shell-native` — green (no regression)

Codex iterate review: 1 round → GO with 2 NITs (script name
singular vs plural, stale "Phase A red-rect" phrase) — both
fixed in this commit.
2026-05-09 21:47:00 +08:00
..
openpencil-app feat(openpencil-app): skeleton crate (Stage F entry placeholder) 2026-05-03 22:05:00 +08:00
openpencil-shell-core feat(shell-core): Phase B2 — four static inspector widgets 2026-05-09 21:46:00 +08:00
openpencil-shell-native fix(shell): drop orphan pub mod event refs after Step 1b §3.2 merge 2026-05-08 22:35:00 +08:00
openpencil-shell-web feat(shell-web): Phase B3 — wire WidgetHost into mount path 2026-05-09 21:47:00 +08:00
pen-codegen chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-core chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-engine chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-figma chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-types feat(pen-types): skeleton crate (bucket A) 2026-05-03 22:35:00 +08:00
wasm-libc-shim feat(shell): add wasm-libc-shim crate for wasm32-unknown-unknown skia bundle 2026-05-09 21:07:00 +08:00