# 000 — Create the shared `craft` crate - **Status**: TODO - **Commit**: d50006e - **Severity**: infra (prerequisite for 001–005) - **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) -> f64` → `over*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.