- bundle_crate_secondary_dex: merge OUT_DIR/classes.dex from dependency
build scripts (robius-sms/trigger/ussd javac+d8 Java for manifest
receivers/services) into the APK as classesN.dex. Without it the
manifest declares BootReceiver/SmsReceiver/AccessibilityService that
are missing at runtime (ClassNotFoundException on boot).
- has_explicit_lib_target: a crate with src/main.rs containing app_main!
is an app, not a lib — generate the android wrapper ([lib] path =
src/main.rs) so the JNI entry (activityOnCreate) is linked. Fixes
UnsatisfiedLinkError for app crates that also ship src/lib.rs.
Nine agent skills for building Makepad/Rust games, ported from
majidmanzarpour/threejs-game-skills. Same director-routed workflow and
premium bar; runtime rewritten for this fork's game crates.
- makepad-game-director entrypoint, routing, continuity, asset probe
- makepad-gameplay-systems loop, movers vs rigid bodies, input, camera, netplay
- makepad-aaa-graphics-builder lighting, shaders, budget, visual scorecard
- makepad-game-ui-designer HUD, menus, touch and XR UI
- makepad-debug-profiler defect bisection and profiling
- makepad-qa-release verification ladder, evidence, packaging
- makepad-3d-generator CC0 model search, casts, procedural geometry
- makepad-image-generator texgen textures, palettes, sky, icons
- makepad-audio-generator sample bank, mixer, material impacts, 3D audio
Written against the real APIs in libs/game/*, libs/sim and apps/arcade:
the game.* verb table, GameRenderer adaptive quality, the packed 6-float
GameMeshVertex layout, script_mod! splash styling, makepad-test driving,
and the BUDGETS.md numbers. No paid generation API is required - the CC0
library plus seeded makepad-game-gen replaces them.
Includes install.sh (Codex/Claude), validate-skills.sh and a repo-aware
probe_assets.sh; both scripts verified against this checkout.
Use cached transparent 2D and cube textures for unallocated optional samplers without bypassing invalid-resource, target, or framebuffer-feedback guards.
Require actual glyph draws in release smoke tests and keep shader compilation asynchronous in probe instrumentation.
Bound drawable, geometry, texture, image, map and radar work; validate WebGL submissions and retire GPU resources safely. Treat context loss as terminal without re-entering Wasm after worker termination.
Add explicit Route location consent and regression coverage, including software-WebGL release probes for six deployed demos.
Reintroduce apps/arcade and the ten game crates that were ripped out of
the fork (assets, audio, blocks, coedit, gen, net, pkg, render, script,
session), from makepad-internal/dev. Reconcile against the fork's layout:
- makepad-game-sim/math come from the fork's existing libs/sim + sim/math;
the copied internal libs/game/{sim,math} are dropped and the kept game
crates plus arcade point at ../../sim and ../../sim/math.
- arcade AI is rewritten off the removed makepad-ai agent API onto the
makepad-ai-hub headless ChatProvider worker (example/cad pattern):
AiWorker{send,cancel,poll}, ai_worker_loop driving
ClaudeApiChatProvider(ClaudeCli), AiWorkerEvent availability/delta/
done/error mapped into the chat feed and authoring land_edit, with
main.rs send_message/cancel_request/event-drain rebuilt around it.
- the game-script sandbox is adapted to the fork's jailed splash storage:
every isolate gets mod.fs = splash_storage jail; splaes splash_storage
set_root_for_heap is now public so the ScriptHost (or Splash) can grant
a per-game jail root. ENT font: build.rs/dispatch.rs entities fill new
fork sim Entity/Part fields via ..Default::default(); world_raycast now
borrows mutably and returns the material id.
cargo check -p makepad-arcade and the game + arcade test suites pass.
Host or attach the asset service, archive generated and terminal outputs, and provide image/video/audio/text/3D viewers with fullscreen and gallery navigation. Load only visible bounded previews, generate video posters and text excerpts, and normalize legacy thumbnails off the UI thread.
Expose video frame counts and Sandbox chat providers, make failed queue cleanup idempotent, compact the panels, and correct short-wire direction. Replace App view with a movable, resizable CodeEditor overlay with debounced source saves, live graph updates, invalid-source preservation and close/reopen geometry.
Validation: release Flow, Flow UI and flowgraph suites passed 335 tests (two ignored). Updated Flow UI suite passed 107 tests; asset route suites passed nine tests after legacy preview fixes. The rebuilt release app passed remote editing, dragging, resizing, invalid-source, close/reopen and App removal checks; final All assets scrolling measured 16.5 ms median and 18.3 ms maximum over 12 inputs. Test instances were closed through the remote protocol.
Update deck and mixer synchronization, apply matched deck rates to splats, and queue remote stem extraction through the fleet. Refresh catalog and creator pipeline integration.
Validation: release VJ suite reports 890 passed, 10 failed, nine ignored. Eight mixer failures reproduce in serial execution (gain, transitions, sample alignment and video fades); two asynchronous media tests also failed in the full run. The new matched-rate splat test passes. These remaining failures are not claimed as fixed.
Bundle the recovered numbered scene bank, support sixteen slots, and keep editable current state and overrides in the local overlay. Validate legacy control mapping.
Validation: 27 release tests passed.
Use output/presentation timestamps instead of AVPlayerItem.currentTime on the UI thread. Consume only fresh frames and stop polling paused players after their poster arrives. Balance Objective-C ownership and make native cleanup idempotent.
Validation: release Flow playback smoke and process sampling; the previous currentTime mutex hotspot is absent in the updated sample.
Find numeric completion actions reliably and restore menu focus using tracked areas. Handle touch dismissal and focus changes without leaving menus open.
Add sandbox authoring effects and character/composite creation, improve creator submission handling, and extend publishing/search metadata. Update importer conversions and the asset UI integration.
Validation: 31 store search tests, ten composite tests and two author-policy tests passed in release mode.
Account for missing and partial model files per volume, reserve headroom, and reject disk-constrained workers before accepting a job. Preserve typed admission failures so callers can choose another peer, and make activity gating and cancellation recover cleanly.
Validation: 592 release hub tests passed, one ignored; required-CUDA builds deployed to six idle Windows workers.
* wayland: stop inverting the scroll direction
Wayland's wl_pointer axis values already carry Makepad's scroll
convention -- positive vertical means scroll down, i.e. the viewport
moves down. The backend negated them, so wheel and touchpad both
scrolled backwards relative to X11, macOS, Windows and web.
The spec pins the sign in wl_pointer::axis_relative_direction, whose
`identical` case is a user's fingers moving down producing a
"vertical_scroll down" axis event. libinput, which produces the values
compositors forward, documents the same: "the positive direction being
down or right". Makepad's own convention matches -- ScrollBar applies
`scroll_pos + e.scroll.y` against a position clamped to
[0, view_total - view_visible], and the turtle draws content at
`origin - layout.scroll` inside a clip rect fixed at the unshifted
origin, so a positive delta moves the viewport down.
The negation came from #875, which read a positive axis value as content
sliding down and cited winit's negation as precedent. But winit's
MouseScrollDelta is documented as positive = content moves down, the
inverse of Makepad's convention -- winit's own comment reads "Wayland
sign convention is the inverse of winit" -- so copying it was a double
negation. Whether a toolkit negates is decided by its own convention,
not by anything about Wayland: GTK, which shares Makepad's convention,
passes the values through; SDL and Chromium negate because theirs are
inverted, and SDL negates vertical only, which is self-consistent just
in case Wayland's +y is down and +x is right. #875 also cited the web
backend as agreeing, but web forwards DOM deltaY unnegated, and deltaY
is positive when scrolling down.
The AxisDiscrete and AxisValue120 handlers added later inherited the
sign, so all six sites flip together; the spec states each expresses its
direction along the same axis as the coupled axis event.
Natural scrolling needs no client-side handling. libinput applies it in
evdev_notify_axis_*, below the compositor, so the delivered axis value
already reflects the user's setting -- the negation was not implementing
that, it inverted both settings equally. AxisRelativeDirection stays
ignored, which is correct for scrolling content; it exists so widgets
that should track the physical wheel regardless of the setting (the
spec's example is a volume slider) can recover the direction.
Fixes#1173
* wayland: classify the scroll source, and choose each axis's delta on its own
Five defects in the wl_pointer frame handler, adjacent to the sign fix in
the previous commit but independent of it.
The detent-vs-pixel choice was made once for both axes, so a frame
carrying detents on one axis and only a smooth value on the other scaled
that second axis by a zero detent count and silently dropped it. Each
axis now chooses on its own.
`scroll_is_wheel` collapsed a five-valued classification into "Wheel vs
everything else", and its false default meant "finger gesture". So a
wheel tilt discarded its detents, a continuous source — a trackpoint, or
button-held scrolling — was reported as a touchpad gesture, and so was a
frame from a compositor that sent no axis_source at all, the event being
optional and sent only when the source is known. That default is the one
classification that can strand a widget: ScrollPhase::Ended is what
springs a stretched rubber band back, only a finger source is guaranteed
an AxisStop, and the spec tells clients to treat every other source as
unterminated by default. The bool gives way to the source itself, and a
sourceless frame is classified by whether it carried detents.
A bare AxisStop no longer dispatches for a source with no gesture to end.
Compositors stop an axis whenever its value reaches zero, whatever the
source, and a zero-delta ScrollPhase::None clears a widget's overscroll
and cuts short a running bounce.
Nor is a stop arriving alongside live motion treated as lift-off. Per the
frame event: "When a wl_pointer.axis and a wl_pointer.axis_stop event
occur within the same frame, this indicates that axis movement in one
axis has stopped but continues in the other axis." And because
axis_source is per-frame and optional, a gesture in flight now carries
its classification forward, so a lift-off frame that omits the source
still ends the gesture instead of losing the terminator.
The raw-pixel fallback for an axis without detents stays unscaled, which
is a deliberate non-change rather than an oversight. No units-per-detent
constant exists to scale it by — compositors disagree, and hwdb ships
wheels from 10 to 30 degrees per click — and a physical wheel never
reaches it: the fallback is for virtual pointers, whose axis value the
protocol already defines as a distance.
Finally, the claim that ScrollPhase::Ended lets widgets run their own
momentum fling was wrong. Widgets start their fling on
ScrollPhase::Momentum, which only macOS emits, so Wayland touchpads have
no kinetic scrolling at all; the comment now says that rather than its
opposite.
The frame decision moves into `frame_scroll`, which puts every case above
under a unit test instead of leaving it to be re-derived by reading.
Makepad windows on Wayland had no drop shadow, which on GNOME reads as
broken next to everything else on the desktop. Mutter implements no
server-side decoration protocol at all -- it advertises neither
zxdg_decoration_manager_v1 nor any KDE equivalent, and its shadow code
(MetaShadowFactory) lives in src/x11/ and isn't even in the
introspection surface. Every shadow on that desktop is drawn by the app
that owns the window.
So draw one, out of eight wl_subsurfaces hung outside the toplevel: four
corner tiles and four edge strips, backed by one memfd wl_shm pool and
sized with wp_viewport, with xdg_surface.set_window_geometry keeping them
out of the window's logical bounds. GTK instead oversizes its own surface
and paints the shadow into a transparent margin. Subsurfaces keep the GL
surface exactly window-sized, so the shadow costs no per-frame GPU fill,
and no margin ever crosses the platform/widget boundary -- which is the
entire class of off-by-a-margin bugs the other approach invites.
The profile is libadwaita 1.9's, computed rather than sampled. A
rectangle's Gaussian shadow is separable, so each box-shadow layer's 2-D
coverage is the product of two 1-D normal CDFs, and evaluating that for a
*square* rectangle is what makes the corners hug the window: sampling a
rounded window's shadow gives 14/255 where a square corner needs 44/255,
and fades the edge out over the last 20px before every corner. The
straight-edge profile this produces matches a capture of the real
libadwaita output to within 1/255, which is what the test pins. Corner
tiles reach 16px along each edge, far enough that they join the strips
bit-identically at any scale.
Resizing happens in the gutter, the way it does for every native app.
The shadow surfaces carry input regions whose union is the window rect
grown by 12px -- the same halo libadwaita gives its toplevels -- and each
piece maps to exactly one edge, so landing on a surface is the hit test.
Window controls no longer compete with the corner grabs for the pointer,
which is what let the close button swallow the top-right corner.
Server-side decorations are requested wherever a compositor offers them,
overridable per process with --wayland-decoration= or
MAKEPAD_WAYLAND_DECORATION, and fall back to the frame above. KWin and
wlroots grant them; GNOME cannot.
Alongside, the caption bar gains double-click-to-maximize, a right-click
window menu, resize cursors keyed off the wl_pointer.enter serial the
protocol actually asks for, and tiled/constrained edges that suppress the
grabs they cannot service -- degrading a corner to its free axis rather
than dropping it.
Finally, declare the toplevel's opaque region, under the same
`!transparent && backdrop == None` condition macOS already uses for its
layer's opaque flag. The buffer is ARGB8888, so without that promise a
compositor cannot learn the alpha is uniformly solid short of reading
every pixel: it must blend the whole window, cannot cull what the window
covers, and cannot scan a fullscreen buffer out directly.
Verified against a WAYLAND_DEBUG trace: over 67 committed frames the
shadow issues no protocol traffic at all, and set_window_geometry,
set_opaque_region and the nine wl_regions are each sent and destroyed
exactly once.
Clocked piano/ironfish/drum rack, program-bus mix, splat/mixer/music
updates. Silence the unused warnings that show up in `cargo check -p
makepad-vj --release`.
ViewSplat gains a typed set_scene_bytes so a viewer inside a face isolate never needs a script apply; MeshView gains visible.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The picker's own label counts the ready nodes, so the GPU list under a
chosen model was clutter; it stays only for a model no node can serve,
where it names why. A closed ComboBox reset its text field to the tail of
the label after set_text; the cursor now sits at the start.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Model and format pickers, the inspector's one-of rows, the Ask face's
choice and face-declared pickers all render as ComboBox; the popup and
its input map through the canvas zoom. ComboBoxRef gains changed_label
and set_selected_by_label so the bindings did not have to change shape.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The straight run out of a port is 10 px (8 px minimum) with the endpoint
fillets shrinking to fit, and the first and last vertical runs keep only
the narrow 6 px envelope from the wire's own card; other cards keep the
two-tier clearance and parallel wires keep their cable spacing.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The generator's own preview was clutter next to the Output card's
picture. The Image face drops its preview and generator cards are no
longer full-bleed; the two picture tests follow the picture to the
Output card.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The host wrapped every bound face control in a labelled row, so the
prompt card showed a "value" label beside a fixed-height box. A
multi-line text area is now its own row and follows the card's size.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A 54 px width chip left the "w" label one pixel column, which rendered
as a stray dot beside the number.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Routed mode never falls back to a curve: a wire with no corridor takes the
least-collision orthogonal path. Clearance is two-tier: the comfortable
12 px card clearance with 16 px fillets first, then 6 px per side with
8 px fillets, so a routed wire passes a 20 px gap. Bezier mode is a pure
cubic per wire. View → Wires switches the mode (in-process until the app
has a settings store).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>