Squash of 55 work commits (Sep 1–12):0fd356dwindows: the vendored bindings are generated from a checked-in filter79882b5fabric: a photo or a live camera to a fitted sewing pattern1e93309AGENTS.md: designs stay local; no OS screenshots; focus and hidden-window lawsaa96dbdcargo-makepad wasm: package the bin target's wasm and create dirs before minifying14d0723cargo-makepad wasm: production packaging — strip, small profile LTO, optional binaryen, size report79e7526sqlite: a page-store seam — the file backend as before, an in-memory backend, and open_memory / open_with60ee978cargo-makepad: package artifacts carry a content hash so a re-upload is a new URL611c9ebcargo-makepad: production packaging stays off fat LTO; script VM under LTO investigatedab8febccargo-makepad: fonts packaged from the app's font manifestf6bbee9wasm bridge: shared memory asks for the 4 GiB wasm32 ceiling and steps down where the engine refusesfb1416dcargo-makepad: the threaded wasm module is linked with the 4 GiB wasm32 memory ceilingfd5d70ccargo-makepad: the app's own resources are packaged under its bin name, which is how self:// resolvesf51ca07workspace: the wasm interpreter's tests build at opt-level 1 — its own profile setting is ignored inside a workspace, and opt-level 0 overflowed the script eval stack942ff86sqlite: the browser store has one owner — its locks never wait on a clock82d0cfaweb path: the trace helper keeps its doc, the journal nonce steps a counter where there is no clock or pid6f8c08fweb-server: POST /api/crash stores crash reports in a rotating log on both servers106b38cwasm bridge: the imported memory honours the module's declared limits94b8726dj-pack: tracks in, stems through the hub, a site store snapshot outd9f04fcdj-pack: pack reads caches, never creates them; dry-run writes nothinge6a305cai-hub + dj-pack: a whole track fits a stems job; long tracks split into spansd1910b8web-server: a store snapshot's extensionless routes are served with the types the exporter recordedc1f7b53asset-client + dj-pack: a long description never rejects a snapshot; the packer writes one bounded line453197ddj-pack: analyse produces the beat grid, overview and loop-splat caches the demo cache ships9b4a3canetwork: every completion raises the UI signalfad1c49web server: audio and text files are served, and models/ is immutable like maps/569b4a7dj-pack: every CC BY and CC BY-SA version and the public domain mark are redistributable licencesdc9cce6workspace: no std clock on the web in any crate the web apps link — the last start-up worker death is gonec7639f0clippy: timed std waits (sleep, recv_timeout, wait_timeout, park_timeout) are disallowed — they read the std clock and panic on wasm workersd748753wasm bridge: the page environment carries js_worker_wait so the module links — the pool landing added the import for workers onlyec40fdbvj + widgets: double-click a knob or fader to reset it to its default — the Slider handles tap_count 2 and emits its normal Slide action; the deck controls carry their neutral defaults (pitch 0, gain/EQ/stems 1, filter centre, crossfader centre)fe23e06AGENTS.md: the execution policy — zero locking on the UI thread as one mechanism for native and wasm, no temporary threads (the pool), the standard operating flow (Codex codes, Fable designs and reviews, Grok tests), and the tweaker on Shift+F10e689aeaweb_server + geodata + route: live radar, wind and weather on makepad.nl/api — one bounded poller per feed, hourly, disk-backed cache served from an Arc snapshot (a restart never re-polls early), 503 warming until the first result, health reports ok/warming/unavailable with timestamps; KNMI key from --knmi-key-file, the documented anonymous open-data key otherwise; libs/geodata fetches through the platform HTTP client instead of shelling out to curl; the client retries 503 after 30 s and disables a layer only on 404cd33943web_server: radar and weather run on KNMI's documented anonymous key when no --knmi-key-file is given; without --live-cache the pollers keep an in-memory cache and say so once2f3e393web_server: a directory path without its trailing slash (/score) redirects to /score/ instead of 404, query preserved9a31d21flow-ui + widgets: a chosen model shows no node list, and a closed ComboBox shows the start of a long label 22b2c78 docs: streamline agent runbook and extract reference guides 6058284 terminal: add hostable session multiplexing via tools/screen 8a9345b tools: migrate Cargo.toml lookups to segment-path keys 8749b91 counter: keep app state across Splash reloads 3ffd485 tools: add agent launcher and AIHub node update and smoke scripts c33a9d3 screen: add bypass and resume menu options c40d234 AGENTS.md: current delegation hierarchy (Grok mechanical, Codex hard, Fable manages) 4184455 Workspace: scope lives at apps/scope (clone of makepad/scope) 27844c9 makepad arch usb builder dd967eb Workspace: drop nine members that are not in the repository 1961768 AGENTS.md: hierarchy 2026-09-11 — Fable builds, Codex reviews, Grok proves 9cd9f94 AGENTS.md: rendering is verified on the real GPU backend, headless is for logic tests only 5f53254 AGENTS.md: GPU proofs may run hidden; only the headless CPU backend is out e950b08 docs: app-remote — hidden GPU runs vs the simulated-GPU backend, measured grab cadence, remote hazards 9c94a77 arch: the platform plan names the simulated-GPU backend gpusim 3009257 micro_serde: serde_json-style JsonValue accessors, pretty printer, depth limit and strict parse 134cd76 gitignore: alternate target directories, root scratch dirs and stray logs are never source 60ba86e arch: the render node refs name platform/src/os/gpusim/mod.rs 1dc571a tools/arch_usb: Wi-Fi, Intel GPU firmware, the AI hub service and game-hardware udev rules on the Arch image; the WM session script picks the saved compositor GPU cc3b05a tools/arch_usb: a polkit rule lets the arch account start, stop and restart the WM service Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7.9 KiB
Splash and widget reference
Use this for current script_mod! work. Repository policy is in
AGENTS.md. Check the implementation closest to your task
before copying a signature; the archived live_design! tree is not the
reference for current APIs.
Working sources
| Task | Reference |
|---|---|
| Small app and startup | Counter example |
| Broader widget examples | Splash example |
| Widget registration and exports | widgets/src/lib.rs |
| Styling and animation | Button |
| Widget lookup and updates | Widget API |
| Virtualized list templates | PortalList |
| Tree drawing and open state | FileTree |
| Generated widget APIs | Widget derives |
| Shader instance memory | DrawVars |
| Script/compiler regression cases | Script test crate |
Use the widget exports and source for availability and feature gates instead of maintaining a separate widget catalogue here.
App structure
A compact pattern using the current counter example's startup and lookup APIs follows. Keep the registration style of the app you are editing.
pub use makepad_widgets;
use makepad_widgets::*;
app_main!(App);
script_mod! {
use mod.prelude.widgets.*
startup() do #(App::script_component(vm)){
ui: Root{
main_window := Window{
window.inner_size: vec2(420, 220)
body +: {
flow: Down
status := Label{text: "Ready"}
press := Button{text: "Press"}
}
}
}
}
}
#[derive(Script, ScriptHook)]
pub struct App {
#[live] ui: WidgetRef,
}
impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {
if self.ui.button(cx, ids!(press)).clicked(actions) {
self.ui.label(cx, ids!(status)).set_text(cx, "Pressed");
}
}
}
impl AppMain for App {
fn script_mod(vm: &mut ScriptVm) -> ScriptValue {
crate::makepad_widgets::script_mod(vm);
self::script_mod(vm)
}
fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty());
}
}
For a new example crate, use an adjacent crate's Cargo configuration and
update the workspace and makepad.splash. Startup helpers and app traits
can change; the source links above are the reference.
Object syntax, scope, and registration
- Properties use
name: value; named child/template instances usename := Type{...}. - Assigning a module export uses
mod.widgets.Name = .... This is an assignment, not the old property syntax. - App scripts import
mod.prelude.widgets.*. Widget implementations usemod.prelude.widgets_internal.*and other required modules. letbindings are local to the script module. Export shared definitions throughmod.*, then import that module. Rust'scrate.*is not a Splash module path, and Rustpubis not used on Splash assignments.- Register widgets with
#(Type::register_widget(vm)), other components with#(Type::script_component(vm)), and draw shaders with#(Type::script_shader(vm)). - Register dependencies before modules whose UI instantiates them. Preserve the host's existing app/module registration sequence.
- Derive fields and attributes depend on the type. Copy the nearest current
implementation;
#[source]is not a universal requirement for every Script-derived struct. Inspect the derive parser if a field type fails.
A widget's styled default commonly has this shape:
script_mod! {
use mod.prelude.widgets_internal.*
mod.widgets.MyButtonBase = #(MyButton::register_widget(vm))
mod.widgets.MyButton = set_type_default() do mod.widgets.MyButtonBase{
width: Fill
height: Fit
draw_bg +: {color: theme.color_bg_app}
}
}
This assumes a matching Rust widget and draw fields are registered; it is a pattern, not a standalone widget implementation.
Values and property merging
Use +: for a partial override of an inherited typed object:
draw_bg +: {color: #f00}
padding: Inset{left: 10 top: 4}
align: Align{x: 0.5 y: 0.5}
Replacing a typed object can discard its other fields or methods. Walk and layout values should use the constructor expected by the property.
Runtime property updates interpolate Rust values with #(expr):
script_apply_eval!(cx, item, {
height: #(height)
draw_bg +: {color: #(color)}
});
Use theme.* for theme values. Resource references use crate_resource;
copy a nearby current resource path rather than translating an old
dep("crate://...") example mechanically. Cursor values use the exposed
enum, such as MouseCursor.Hand. If an enum is not exposed, inspect its
registration rather than silently discarding a required property.
Rust tokenizes code inside script_mod! before Splash sees it. Use escaped
colors such as #x2ecc71 and #x1e1e2e where a digit followed by e or
E would otherwise be parsed as an exponent.
For Rust action enums, use #[derive(Default)] and #[default] on the
default variant, not the old DefaultNone derive.
Templates and lists
Script objects distinguish ordinary key: value properties in their map
from named name := Type{...} items in their vector. List widgets collect
the latter as templates during application.
list := PortalList{
width: Fill
height: Fill
Item := View{
height: 40
title := Label{text: "Default"}
}
}
The current PortalList keeps templates as rooted ScriptObjectRef values,
collects them outside eval-only application, and updates instantiated items
on reload. Preserve those lifetime rules in custom list widgets.
During list drawing, use the current set_item_range, next_visible_item,
and item APIs. Widget lookup includes the context:
let item = list.item(cx, item_id, id!(Item));
item.label(cx, ids!(title)).set_text(cx, &format!("Item {item_id}"));
item.draw_all(cx, &mut Scope::empty());
For Dock-local templates, use a script-level let or module export when a
component must be reused outside that Dock. For custom widgets, turtle
drawing, FileTree traversal, and full animation state definitions, follow
the linked implementations instead of maintaining duplicate tutorials.
Shaders and animation
- Per-draw shader values use
instance(value); shared values useuniform(value). A varying hover color must not accidentally be uniform. - Texture declarations use
texture_2d(float). - Shader functions use
pixel: fn() {...}and method calls use., not Rust::. Chainedcolor.mix(other, amount)is a useful styling idiom. - Use
modf(a, b)for float modulo andatan2(y, x)for the two-argument arctangent.atan(x)andfract(x)are also available. - Animator states use id values such as
default: @off. Use the current Button implementation for state definitions and transition constructors. - Prefer enum
matchwith a catch-all. A failure in supported shader enum matching needs a compiler regression case and fix, not an integer-branch workaround in the widget.
Custom draw shaders need #[repr(C)]. Keep non-instance fields before the
draw base and shader instance fields after it:
#[derive(Script, ScriptHook)]
#[repr(C)]
pub struct MyDrawShader {
#[rust] cached_state: bool,
#[deref] draw_super: DrawQuad,
#[live] tint: Vec4f,
}
DrawVars::as_slice() reads across the base into trailing instance fields.
Putting non-instance state in that region corrupts the GPU instance buffer,
including when another draw shader extends yours. Follow the base shader's
current layout and registration.