makepad/docs/agents/tweaker.md
Admin 012e6f7df5 tools, libs and the rest
cargo-makepad, makepad-builder (with an Android step on every OS), CI tools
and tiles, and the remaining libraries.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

122 lines
6.2 KiB
Markdown

# Tweaker: live styling and source write-back
Read this when the user is giving visual feedback or when applying a live
style change. Follow [AGENTS.md](../../AGENTS.md) for instance ownership and
capture policy. The overlay implementation is
[widgets/families/tweaker/src/tweaker.rs](../../widgets/families/tweaker/src/tweaker.rs).
## Interaction and commands
Toggle with Shift+F10 or `tweak on=1`. The overlay adds a property
sidebar and intercepts pointer events over the app body: selecting a button
outlines it without firing its action. Turn it off before testing ordinary
widget clicks.
| Command | Result |
|---|---|
| `tweak on=1` or `on=0` | Enable/disable the overlay |
| `tweak annotate=1` or `annotate=0` | Enable/disable freehand annotation; Alt-drag also draws |
| `tweak state` | Selection, reflected properties, hover, edits, and annotations |
| `tweak apply` | Apply one property or a Splash chunk and wait for relayout |
| `tweak diff` | Ordered edit log |
| `tweak clear` | Clear edit log and annotations |
| `tweak final` | Coalesced initial/final values and annotations; may include a PNG |
| `tweak grab` | App-owned grab including the overlay |
`tweak apply` can name one property:
```sh
makepad-remote app $P tweak apply path=main_window.body.panel prop=padding 'value=Inset{left: 20}'
```
Or merge a Splash chunk onto the selected instance:
```sh
makepad-remote app $P tweak apply path=main_window.body.panel 'splash={draw_bg +: {border_radius: 8}}'
```
Use the selected widget's reflected property names; not every draw type
exposes the same radius/color fields. In `tweak state`, `set:1` means a
property was explicitly applied.
Sidebar edits emit `TWEAK sidebar <path> <prop> <old> -> <new>` in the app
log. Listen through `log since=N`; do not poll `tweak state` for changes.
Read state when inspecting a selection or verifying an applied value.
## Structural edits: the designer
The Build tab's design session edits the Splash source of the file that
declares a widget: insert, move, delete, wrap, rename and set properties.
Each edit is a byte-range hunk inside the `script_mod!` body, previewed
live in the running app. The app never writes the file; the agent applies
the patch. The same session is reachable through `design <op>`, and a person's Build
tab edits and an agent's commands share one undo history.
| Command | Result |
|---|---|
| `design open path=P` | Start a session on the file declaring `P` (default: the pinned widget) |
| `design state` | File, edit count, status, `can_undo`/`can_redo`, `landing`, hunk labels |
| `design palette` | Insertable types with their default bodies |
| `design insert path=P place=before\|after\|inside type=T body=B` | Insert `T` (body defaults to the palette's); answers the new widget's path in `select` |
| `design move path=P to=Q place=...` | Move `P` next to or into `Q` |
| `design delete`, `duplicate`, `wrap`, `up`, `down`, `out` `path=P` | Structural edits of `P` |
| `design rename path=P name=N` | Name, rename or (empty `name`) unname a literal |
| `design set path=P key=K value=V` | Write a property into the literal (`+:` for a new typed property) |
| `design bake` | Write every value-ledger tweak on this file's widgets into the source |
| `design undo`, `redo`, `reset` | Step the source edits |
| `design patch`, `design commit` | The unified diff; `commit` adds `base_hash`, `new_hash`, `base_matches_disk` and the hunks |
| `design verify` | Every drawn widget of the file and whether its literal is found |
| `design close` | End the session; writes `local/design/<file>.patch` |
Edits answer after the frame that shows them, so a `grab` right after sees
the change; send `if_user_seq` like any other mutation. An edit whose
preview the runtime rejects is rolled back and reported in `status`. An op
on a `#(...)` placeholder is refused (it needs a rebuild), and so is an
edit to a widget declared in another file. To persist: read
`design commit`, check `base_matches_disk`, apply `diff` to the file, then
rebuild, relaunch and verify as below.
## Motion: the tween inspector
The Motion tab lists every animation the app's `TweenHost`s play (the
Splash `tween` driver, stack navigation, the widgets and stories built on
the tween engine) and shows the chosen one on a timeline: its labels on
the ruler, one lane per child indented by depth, and the playhead. Drag on
the timeline to scrub (the animation pauses, callbacks stay quiet, and it
plays on at release if it was playing); the chips pause, restart, set
the speed, loop (repeat forever) and yoyo; the divider between the
lane names and the timeline drags. Hosts publish only while the tab is up.
`tweak op op=motion` answers the same data as JSON: `open`, and per host
`id`, `name`, `age` and `roots` (`name`, `kind`, `len`, `time`, `paused`,
`linked` (0 once a kept animation completed), `repeat`, `yoyo`, `scale`,
`lanes`, `labels`). Add `host=<id> root=<k>` with one of
`seek=<seconds>`, `pause=1`, `resume=1`, `restart=1`, `scale=<x>`,
`loop=1|0` (repeat forever, or none) or `yoyo=1|0` to
control the k-th top-level animation of that host; the host applies it on
its next event, so read again after a frame. `open=1` publishes without
the tab.
## Persist the result
The overlay never writes source. With a design session open,
`design bake` turns the value tweaks into hunks and `design commit`
returns the patch; without one, at the end of a styling session:
1. Read `tweak final`. If annotations produced a `png`, inspect it; the
strokes are part of the user's feedback.
2. Resolve each dotted widget path to its `script_mod!` declaration.
Skip anonymous `-` segments when searching. `dump` shows the same ids.
3. Write properties at the most specific existing instance declaration.
Create an instance override only if no appropriate site exists.
4. Preserve typed-property merging with `+:`. Plain walk/layout properties
are assigned directly with the correct typed value.
5. Preserve returned source spellings, adding the Rust-macro `#x` color
escape where required.
6. Rebuild and relaunch. Verify values through reflection or snapshots,
and inspect a new frame when the visual result matters.
7. Finish your test instance through `gq`, or the cleanup fallback in
the runbook.
Use these commands directly; this workflow does not require a helper
under `local/`.