Commit graph

670 commits

Author SHA1 Message Date
Arena Agent
fe5b75d92d Merge latest makepad work while preserving fork game crates and apps 2026-09-05 20:55:35 +00:00
Admin
a75fe914ff layout: extend turtle sizing and add Grid 2026-09-05 17:21:48 +02:00
Admin
09fa1f080c Restore WebGL text with complete fallback samplers
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.
2026-09-05 14:39:06 +02:00
Admin
1801e38453 Harden web renderer and make Route location opt-in
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.
2026-09-05 12:13:36 +02:00
Admin
2f44d20b51 apple: avoid blocking video clocks and release native players once
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.
2026-09-05 01:42:39 +02:00
Admin
2a064d3928 workspace: add loader, haptics, voice, and runtime fixes 2026-09-04 17:39:41 +02:00
Admin
bf9418e2bc vj: ironfish / synth rack, program mix, and a clean release check
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`.
2026-09-04 14:54:07 +02:00
Admin
303458d07a webgl: a 2D texture pass builds its camera through set_ortho_matrix like every other backend, so the exploded z-layer view's camera reaches the GPU — the hand-built ortho branch uploaded an identity view and clipped every exploded draw, leaving the tweaker's layers view a bare window on the web; the Y flip for render-to-texture is one helper shared with the keep-camera branch
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-04 00:18:58 +02:00
Admin
3c2530d000 web memory diet: the 805 MiB at load was the ocean-high archive's 13 M-entry leaf directory decoded to 407 MiB per lookup round and evicted at once — leaves now parse streaming into a window around the waiting tile ids (LeafParseLimits); a phone policy on the web (deviceMemory, UA, touch + short side) caps wasm at 512 MiB with a 320 MiB budget; archive leaf/range caches, reads and bakes in flight follow the budget; packed tile bytes stay packed until the bake decodes them; terrain scratch sized to the viewport and dropped with the layer; Cx::memory_report by owner. Phone viewport 1334 → 308 MiB after a minute of pans, desktop 1208 → 588
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 23:45:22 +02:00
Admin
ddc4709b32 map: touch gestures — one-finger pan and double-tap zoom, two-finger pinch zoom around the midpoint, rotate with a 5° dead zone, and a parallel vertical slide for tilt, one state machine native and web; the web page keeps browser pinch-zoom out (non-passive touch listeners, touch-action none, maximum-scale 1)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 21:58:36 +02:00
Admin
01e77d99c0 map: the shimmer clock is one pass-level uniform (draw_pass.shiny_time, a map-owned slot, never draw_pass.time) written once per heartbeat tick instead of patched into every retained draw call's block — the settle tail stops re-uploading 600 uniform blocks per tick
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 21:09:44 +02:00
Admin
b04333265e webgl: uniform blocks upload only when their generation moved — one global monotonic counter on Cx hands out every generation (draw call create/dirty/zbias, draw list allocate/transform/re-record, pass allocate/time/dpi/ortho/camera and the web flipped copy, shader scope writes), so a reused pool slot can never match a cached generation; clear_draw_items, pool reuse and VAO recreation reset the caches; the JS caches key on the generation alone. Proven on a local build: the pan screenshot keeps every tile, the settle tail drops 20.5 → 12.8 MiB/s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:59:55 +02:00
Admin
e48b056df1 Revert "webgl: a uniform block is uploaded only when its generation moved — per draw call (uniforms_gen), per draw list (uniforms_gen, recording_gen), per pass (pass_uniforms_gen) and per shader scope block; the JS side caches (ptr, len, gen) per uniform buffer and re-records/recompiles reset it; direct camera writers (vj effects, render scene, the web flipped copy) bump the pass generation"
This reverts commit 0d7ddee3f7.
2026-09-03 20:37:35 +02:00
Admin
1f244282b1 map bake: a face-band triangle is a face only when all three records pack (a mixed triangle stays on the road path); a panicking pool job no longer takes the worker down — caught, reported once, the tile fails; the bake panic that blacked the native map and killed the web workers
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:29:04 +02:00
Admin
0d7ddee3f7 webgl: a uniform block is uploaded only when its generation moved — per draw call (uniforms_gen), per draw list (uniforms_gen, recording_gen), per pass (pass_uniforms_gen) and per shader scope block; the JS side caches (ptr, len, gen) per uniform buffer and re-records/recompiles reset it; direct camera writers (vj effects, render scene, the web flipped copy) bump the pass generation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:22:56 +02:00
Admin
bb49fe6989 map + platform: retained per-tile draw lists — each resident tile owns one DrawList2d per carto pass (fill, casing, stroke, icon, icon-high, shadow) and the label glyph batches are retained the same way, recorded when the bake, LOD ring, fringe/icon gates, flat/tilted or clip change and re-attached otherwise; a pan/zoom/tilt frame pushes this frame's uniforms onto the retained calls (DrawVars::update_uniforms_on_area, resolved slot table) and uploads zero instance bytes; the tilted per-pass depth is a pass_depth uniform; a held list's zbias resolves at entry (zbias_hold in every backend); the shimmer heartbeat patches shiny_time in place without a redraw; a freed/reused sub-list id is skipped by every draw-tree walker and the mask list re-records empty on the flat transition (contract test). Web pan tail 1,098 → 20 MiB/s, flat pan 2.4 → 0.43 MiB/frame; Metal grabs within the run-to-run noise floor
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:04:18 +02:00
Admin
f615054dab tweaker + webgl: click-to-climb continues only from the widget the climb started on, so a press on a sibling picks that sibling (the empty draw_bg was a bare View being pinned); the Shader tab says when a layer has no live draw call; the WebGL paint walk no longer resets every draw list's view_transform — the magnified material well drew at the window origin on the web
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 18:55:42 +02:00
Admin
de9aba3d83 vj + web: the Layer button works on the web — a second Window is a queried capability (OsType::is_single_window; the web creates none and reports it once), so the output becomes an in-page full-canvas layer with browser fullscreen (Esc, the browser's own fullscreen exit, or a double-click leave it); a pass without a draw list settles its dirty flag instead of erroring every frame; exitFullscreen fixed; fullscreenchange feeds the window geometry
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 18:53:02 +02:00
Admin
976ea0ed04 tweaker: Shift+F10 toggles it on every platform (KeyEvent::is_tweaker_toggle, one call site; the web page swallows exactly Shift+F10 so the browser never sees it); the exploded z-layer view has no keyboard shortcut any more — it is a button in the tweaker
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 18:38:26 +02:00
Admin
8d542feea7 platform: a child pass orphaned by its attaching draw list is no longer painted — the window's gauss_scene pass stayed a live_with_parent child after the map went flat and re-encoded a frozen 400-item list every pan frame with stale geometry ids (new tile meshes × old instance counts, tens of millions of triangles into a texture nobody read); make_child_pass records the recording list + redraw id, stale passes are skipped, a cached View re-attaches on a cache hit; tests for the orphan gate and the pool generation contract
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 18:22:02 +02:00
Admin
1980c24973 platform: a draw call whose geometry id went stale is skipped, not drawn with whatever mesh now sits in the reused slot — the runaway triangle count that took a web map pan to 1 fps; reported with a power-of-ten backoff, never per frame
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:01:27 +02:00
Admin
2aa0780d0a webgl: BGRA uploads become RGBA at upload and sample_as_bgra is a plain sample on the web, as on every native backend — the tilt-shift's sharp band showed red/blue-swapped water
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 17:49:38 +02:00
Admin
639887dda0 webgl: texture passes get their depth target — the tilted map (and every 3D scene drawn into a texture) was draw-order only: hollow buildings, no roofs, landmarks buried
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:32:55 +02:00
Admin
862f3bd298 asset widgets + chat ui + render: fan-outs and jobs on the runtime pool, the transcript read without a lock on draw
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 16:41:34 +02:00
Admin
9e2d65b50b pdf + photos + task + wm + video + automate + widgets: no per-job threads — pool jobs and start-up workers
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 16:38:24 +02:00
Admin
6dcca0088b workspace: no timed std waits on web-reachable paths — the clippy gate covers every web demo's dependency set
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 16:15:08 +02:00
Admin
5184340565 platform + vj + map + files + widgets + image_tiles: the runtime owns one warm two-lane task pool — jobs never spawn threads
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 16:06:44 +02:00
Admin
4e61e44fca route + map: the desktop app streams the makepad.nl archive through a persistent on-disk range cache, chosen in settings
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 13:47:14 +02:00
Admin
83a8d4f69d fonts: the web demos start with the Latin set — CJK and emoji faces load on the first glyph that needs them
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 10:40:48 +02:00
477421e314 nigig: NIGIG test-mode forwarding, custom manifest hook, ortho camera support
- makepad_test/runtime.rs: forward NIGIG_TEST_MODE from host env to the
  Android app via 'am start' intent extra; add wait_timeout (60s) used by
  wait_visible/wait_hidden/wait_count; make query_widgets tolerant of
  snapshot timeouts; grant READ_CONTACTS during adb setup
- makepad-platform android_jni.rs: read makepad.NIGIG_TEST_MODE intent
  extra and surface it as the NIGIG_TEST_MODE env var via apply_studio_env
- cargo_makepad compile.rs: support verbatim custom AndroidManifest.xml in
  addition to the templated variant
- makepad-xr xr_root.rs: add ortho camera controls (ortho, ortho_height,
  min/max), derive Debug on XrCamera
- docs: ANDROID.md and DESKTOP_VISIBLE.md for makepad_test
2026-09-03 10:55:00 +03:00
bc55ff94aa android: send BeforeStartup/AfterStartup over websocket
The Android platform never sent BeforeStartup or AfterStartup messages
via the studio websocket. Desktop platforms send these through their
stdin event loops, but Android uses websockets instead of stdin.

Without AfterStartup, the hub never broadcasts AppStarted to UI
clients, causing makepad-test to time out waiting for app startup.
2026-09-03 10:54:59 +03:00
dae59f1422 feat(test): extend protocol for touch, long-press, paste, IME composition
Add RemoteTouchState, RemoteTouchPoint, RemoteTouchUpdate, RemoteLongPress,
RemoteTextPaste, RemoteIMEComposition wire structs to StudioToApp enum.

Dispatch new events through cx_shared.rs (TouchUpdate→Event::TouchUpdate,
LongPress→MouseUp+MouseDown, TextPaste/IMEComposition→Event::TextInput).

TestApp: touch_down/move/up, long_press, paste_text, ime_composition.
Locator: touch_down/move/up, long_press, paste, ime_composition.
2026-09-03 10:54:59 +03:00
4c94531456 feat(test): Android makepad_test via adb + in-process hub (legacy Java path)
Adds the Android test runtime to makepad_test: builds the APK with
cargo-makepad's standard Java path, installs and launches via adb with
makepad.STUDIO_* intent extras (incl. STUDIO_BUILD), connects the app to an
in-process hub over adb reverse, and waits for startup + responsiveness.
Adds clean in-process hub shutdown (HttpServerHandle + GatewayHandle Drop)
and the STUDIO_BUILD intent parsing on the app side. No native-activity or
NDK APK compilation code is included.
2026-09-03 10:54:58 +03:00
Admin
a3248d1c51 web audio: the worklet gets the audio access pointer as its context — the thread-stack call gained a request id and the audio start was still passing the pointer in its place
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 08:56:04 +02:00
Admin
410acd0eaa web + vj + route: the console carries failures and one-line summaries, nothing per request, per tile or per hiccup
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 08:54:21 +02:00
Admin
58d3fd5d5d web audio: the output is created inside the first gesture, and a stalled worklet module load is retried on a fresh context
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 08:34:59 +02:00
Admin
aa907cab9c platform: a frame trace on both desktop backends, and a window that cannot present stops ticking at 600 Hz
MAKEPAD_TRACE=frames prints, every two seconds per window, what woke
each tick (the waitable beat, a timeout, a message, a timer, a drain,
the display link), the NextFrame gap histogram, the present gap
histogram, the flip lead and refused presents — one bool check per
tick when off, readable over --remote. It was written to chase the DJ
beat wave's judder on Windows and found the measurable defect on the
way: when no window could present (minimised, hidden, or a disconnected
RDP session where the compositor refuses every present), the paint
tick slept a millisecond and re-ran, dispatching NextFrame and
redrawing at about 600 Hz for frames nothing would show. That case is
paced at 8 ms now, the same cadence as video pacing, the idle beat and
a hidden macOS window; a visible window that drops a frame keeps its
1 ms retry.

The judder itself could not be measured hidden — a disconnected RDP
session presents nothing at all — and the reading is that a connected
RDP session's bursty ~30 fps frame delivery is what the person saw;
the trace settles it in one visible run. platform 153 tests; both
desktop targets check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 00:18:25 +02:00
Admin
97e0701ff8 vj + platform: the web audio thread never waits on a lock — a loaded deck plays
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 00:17:00 +02:00
Admin
0ef0311812 web audio: a throw inside the worklet's process() is reported with its real text instead of a bare ErrorEvent
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 00:10:10 +02:00
Admin
1e2dcd0da8 web: a pass without a draw list is skipped instead of taking the app down (F12 layers overlay)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 00:03:23 +02:00
Admin
b39d301ee2 web audio: the worklet links the whole module — every platform import the audio thread does not serve is stubbed, clocks and the UI wake are real
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 23:55:07 +02:00
Kevin Boos
493d23a763
Put the F10/F12/Shift+F12 dev overlays behind an opt-in (#1209)
* remote: honor MAKEPAD_REMOTE in requested(), and hush the close notices when the bridge is off

`requested()` only scanned argv, while `requested_bind()` also reads
MAKEPAD_REMOTE. So `MAKEPAD_REMOTE=1` started the bridge but everything
keyed off `requested()` still said no. Just delegate, so there's one
answer to "did this process ask for the remote bridge".

Also stop printing `[makepad-remote] user closed window ...` to stdout
from every app on every window close -- that line is for the agent
driving the app, so only print it when the bridge is actually up. The
log ring still gets it either way, for /log.

* devtools: put the F10/F12/Shift+F12 overlays behind an opt-in

Three dev tools are currently wired into every app with no way to turn
them off, each on a bare function key:

  F10        the exploded draw-list view. Intercepted in
             Cx::call_event_handler *before* the app's handler, and once
             it's up it also eats Escape, the arrows, +/-/0, I and H --
             no modifier needed -- plus every drag outside the flat band.
  F12        the design tweaker, a child of every Window. Once it's up it
             swallows every pointer event over the body, so the app looks
             frozen to the mouse.
  Shift+F12  the screen recorder, which starts writing mp4s to disk.

None of that is something a shipped app wants a user to find by accident,
and there was no flag, env var or property to stop it.

So: one gate, platform/src/devtools.rs. `--devtools`, or
MAKEPAD_DEVTOOLS=1, and --remote implies it since the /snap + /click loop
drives the tweaker. An explicit MAKEPAD_DEVTOOLS=0 wins over all of it,
which also keeps the off path testable under --remote.

Only the hotkeys are gated, not the tools. Cx::sploded_toggle,
set_tweak_on and ScreenCap::toggle are untouched and still public, so an
app that wants any of this puts it on a key of its own choosing -- that's
the app deciding, rather than a key nobody knew was bound.

Gating F10 and F12 is enough to reach all of it: everything else these
two claim sits behind `sploded.active` / `tweak_is_on()`, and with the
hotkeys gated the only remaining ways in are the /tweak routes (already
--remote, which implies devtools) and an app's own call.

* text_input: drop the Ctrl+Enter submit clause again

`|| mods.control` made Ctrl+Enter submit a multiline input. On
Linux/Windows that's already what is_primary() means, so it changed
nothing; on macOS it turned Ctrl+Enter from "insert a newline" into
"send", which is a surprise in the middle of a chat app's composer.

The comment right above it already described the old behavior, so this
puts the code back in line with it.
2026-09-02 23:41:39 +02:00
Admin
dc85eb0ed3 web + vj: render-to-texture passes keep their 3D camera on WebGL, thumbnails wait for shader compile, bundled tiles re-ask — effect thumbnails match native
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 23:36:53 +02:00
Admin
a2cbe38330 map, platform: the tile budgets follow the platform's one memory number
Cx::memory_budget_bytes() is set once at startup from the device
(ProcessInfo on macOS/iOS, ActivityManager on Android, GlobalMemoryStatusEx
on Windows, /proc/meminfo on Linux, the wasm maximum on the web) through
one policy: desktop keeps 1536 MiB unless RAM is under 8 GiB (then RAM/4),
mobile takes RAM/4 clamped to 384..1536 MiB. The map's four byte budgets
are fractions of it (upload 1/64, pending 1/4, tile cache 25/32, HTTP
cache 5/32; the tile cache caps at 1/2 on web heaps under 1 GiB) instead
of constants. At 1536 MiB they are the binary sizes 24/384/1200/240 MiB,
about 5 % above the old decimal constants. Harness totals unchanged; Metal
grab and web GPU gate within noise (BUDGET1 lane).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:48:11 +02:00
Admin
7b33f7bec6 vj + platform: a loaded deck actually plays on the web
vj + platform: a loaded deck actually plays on the web

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 22:43:14 +02:00
Admin
3b1a8c264f platform: an in-app drag works without an OS drag session (web, Linux) — effect tiles drop into the channels on the web
platform: an in-app drag works without an OS drag session, so effect tiles drop into the channels on the web

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 22:41:46 +02:00
Admin
e7be0e31dc vj + platform: the browser UI thread never waits on a lock, and the web hot paths log only errors and summaries
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 22:13:26 +02:00
Admin
463de64b33 web: shaders compile per draw list, link in parallel
The first WebGL frame compiled every registered program synchronously;
on ANGLE-Metal that is 8.6 s of from_wasm dispatch for the DJ app (35 ms
of wasm), during which no timer, fetch completion or animation frame can
run. SwiftShader hid it by compiling at first draw. Programs are now
queued only when a draw list references them and linked with
KHR_parallel_shader_compile; the first draw waits only for the programs
it needs. DJ app on the GPU: localhost fetches 8.7 s -> 0.2 s, 39
programs ready in 300 ms; route first draw at 224 ms (STARTUP1 lane).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00
Admin
9b4a3cac3e network: every completion raises the UI signal
A runtime the platform did not create (the asset client builds its own)
has no wake fn, so on the web its responses sat until an unrelated timer
pumped the event loop. EventSink::emit now sets the UI signal as well;
the DJ app polls its store session on Event::Signal instead of waiting
for the next poll tick.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00
Admin
5a5eda2979 map: road, fill and roof streams on the typed vertex formats, u16 indices
Roads move from eight f32 lanes to a 28-byte RoadVertexTyped (i16 anchor
at 1/64 tile unit, f16 offset / depth / uv pairs, unorm8 colour, f16
params, exact f32 deck), ground fills and roofs to 16 bytes (i16 anchor,
unorm8 colour, f16 params; u16 depth ticks for fills, exact f32 height for
roofs); indices are u16 whenever a stream has fewer than 65,536 vertices.
The three shaders read the typed POD fields directly (the fetch converts),
uploads go through Geometry::update_typed with the shader's layout, the
space-warp subdivision decodes / interpolates / re-encodes the typed
records, and a tile that lands before its shader has drawn waits in the
pending queue instead of panicking. The shader compiler types a packed
field access as vec2f / vec4f, and the Metal name table gains the packed
short / ushort / uchar / char vector names.

Harness: 249.6 -> 215.5 MiB for the 25 start-view tiles, 384 ms/tile.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00