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>
6.2 KiB
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 for instance ownership and capture policy. The overlay implementation is 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:
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:
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 TweenHosts 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:
- Read
tweak final. If annotations produced apng, inspect it; the strokes are part of the user's feedback. - Resolve each dotted widget path to its
script_mod!declaration. Skip anonymous-segments when searching.dumpshows the same ids. - Write properties at the most specific existing instance declaration. Create an instance override only if no appropriate site exists.
- Preserve typed-property merging with
+:. Plain walk/layout properties are assigned directly with the correct typed value. - Preserve returned source spellings, adding the Rust-macro
#xcolor escape where required. - Rebuild and relaunch. Verify values through reflection or snapshots, and inspect a new frame when the visual result matters.
- 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/.