makepad-ports/plans/000-craft-crate.md
andodeki 3cfeaa289c Add implementation plans for makepad-ui-craft (Emil's improve-animations plan format)
plans/README.md: index, execution order 000->005, executor ground rules (test gate, DSL landmines)
000: shared craft crate (easing/duration/color tokens, Pressable, CraftToast, motion math + units)
001: HIGH press contract - feedback on down, commit on up-if-over, 0.96 scale (all 3 crates)
002: MEDIUM toast enter/exit, interruptible, reduced-motion aware (all 3 crates)
003: MEDIUM insurance sheet momentum projection + velocity-handoff settle, rubber-band
004: MEDIUM koboyo drawer slide, origin-aware popovers, animated camera fit
005: LOW polish - color tokens, concentric radii, real icons, tabular figures
2026-09-01 18:50:05 +00:00

4.7 KiB
Raw Permalink Blame History

000 — Create the shared craft crate

  • Status: TODO
  • Commit: d50006e
  • Severity: infra (prerequisite for 001005)
  • Category: Cohesion & tokens
  • Estimated scope: 1 new crate (~5 files), 1 patch edit, 3 Cargo.toml edits

Problem

Three crates re-implement chrome independently with zero shared motion language: no easing tokens, no shared pressable, three copy-pasted toast blocks, brand hex repeated per widget (insurance/src/app.rs:31,108,122,170#7b5cf6, #8a74ff, #f7a982…). Every subsequent plan needs one home for the house values, or the fix itself becomes three drifting copies.

Target

New workspace member makepad-ports/craft/ (crate name makepad-example-craft, copied to examples/craft by setup_makepad.sh, same layout as the other three), exporting:

  1. script_mod tokens stored on the mod object (the only cross-file sharing mechanism):
    • mod.craft.ease_out_strong = Ease.Bezier {cp0: 0.23, cp1: 1.0, cp2: 0.32, cp3: 1.0}
    • mod.craft.ease_in_out_strong = Ease.Bezier {cp0: 0.77, cp1: 0.0, cp2: 0.175, cp3: 1.0}
    • mod.craft.ease_sheet = Ease.Bezier {cp0: 0.32, cp1: 0.72, cp2: 0.0, cp3: 1.0}
    • mod.craft.ease_polish = Ease.Bezier {cp0: 0.2, cp1: 0.0, cp2: 0.0, cp3: 1.0}
    • durations: dur_press_release: 0.15, dur_hover: 0.1, dur_popover: 0.2, dur_drawer: 0.25, dur_toast_in: 0.3, dur_toast_out: 0.2
  2. Pressable widget (Rust: #[derive(Script, ScriptHook, Widget, Animator)]) — full spec in plan 001; defined here, adopted there.
  3. CraftToast widget — full spec in plan 002.
  4. reduce_motion: pub fn play_or_cut(reduce: bool, cx, w: &mut impl AnimatorImpl, st) helper (RECIPES.md §6) + a #[rust] reduce_motion: bool convention documented in the crate docs. Default false.
  5. src/model.rs-style pure module motion.rs with unit-testable math:
    • pub fn project(v_px_per_s: f64, rate: f64) -> f64(v/1000.0)*rate/(1.0-rate)
    • pub fn rubberband(over: f64, dim: f64) -> f64over*dim*0.55/(dim+0.55*over.abs())
    • pub fn settle(from: f64, target: f64, v0: f64, lambda: f64, t: f64) -> (f64 /*pos*/, bool /*done*/) — exponential settle: x = (d + (v0 + λd)t)·e^(λt), done when |x| < 0.5 && |v0·e^(λt)| < 10.0

Repo conventions to follow

  • Crate skeleton: copy makepad-ports/insurance/ structure (src/{lib,main,app,model}.rs, tests/), Cargo.toml identical shape (makepad-widgets = { path = "../../widgets", version = "2.0.0" }).
  • Workspace registration: extend patches/makepad-dev-headless-linux.patch where it already inserts members (+ "examples/rider", etc.) with + "examples/craft",; keep the patch applying cleanly against dev @ b41e740 (git apply --check).
  • Consumers add makepad-example-craft = { path = "../craft" } and call makepad_example_craft::script_mod(vm) before their own script_mod in App::run.
  • Widget registration exemplar: the let ChatList = #(ChatList::register_widget(vm)) {…} pattern noted in makepad-ports/README.md bug 3.

Steps

  1. Create craft/Cargo.toml, src/lib.rs (exports script_mod, motion, widgets), src/motion.rs with the three functions + #[cfg(test)] unit tests (below).
  2. Create src/widgets.rs: Pressable + CraftToast Rust structs and their script_mod! block registering mod.craft.* tokens and both widgets.
  3. Edit the patch: add "examples/craft" to workspace.members; update setup_makepad.sh copy step to include craft.
  4. Add the dep + script_mod call to rider, koboyo, insurance (no behavior change yet).
  5. Unit tests in motion.rs:
    • project(1000.0, 0.998)499.0 (±0.5); project(0.0, _) == 0.0; sign follows v.
    • rubberband is monotonic, < over, and rubberband(0.0, d) == 0.0.
    • settle reaches done with pos within 0.5 of target for (from=200, target=0, v0=800, λ=12) before t = 1.0; position is continuous at t=0 (pos(0) == from).

Boundaries

  • Do NOT move any existing UI into the crate yet (that's 001/002).
  • Do NOT touch reference/, uploads/, or the three apps' model.rs.
  • Do NOT add third-party dependencies.
  • If the patch no longer applies to dev @ b41e740, STOP and report — do not rebase upstream.

Verification

  • Mechanical: cargo test -p makepad-example-craft --lib green (new tests); cargo test -p makepad-example-{rider,koboyo,insurance} --lib --test integration still 21/9, 29/14, 28/14; git apply --check passes on a fresh checkout.
  • Done when: all four crates build, tokens are reachable from a consumer script_mod! block as mod.craft.ease_out_strong, and the 140-test baseline is intact.