iOS: VideoFileDecoder::open_audio guarded its Apple path with macOS alone, so iOS fell through to UNSUPPORTED, a constant no Apple target has. It takes the same split as every other entry point in that file.
tvOS: libs/apple_sys opened with a crate guard of macOS or iOS, so on tvOS the crate compiled to nothing and every msg_send! user lost the macro; the crate guard and its 27 inner guards of that shape now name tvOS, and MTLCopyAllDevices is macOS only, which is where it exists. The platform's Apple video playback, player and YUV modules, the 17 guards of the Metal NV12 video path and the texture-pool imports follow, and the tvOS app gains try_metal_device, the lookup the texture adopt path already calls on iOS.
wasm: the window manager's dylib host needs a process, a linker and a loader, so it is native only; the web gets a stand-in with the same surface that refuses every compile through the queue the native host answers on, and libloading is a non-wasm dependency.
Windows: three Unix-only uses in apps/wm/src/clients.rs (Cx, CancellationToken, the grace argument) are guarded to match where they are used, tests included.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The CEF follow-up (libs/cef, widgets/src/browser.rs, apps/browser): BrowserOptions with software frames, evaluate_javascript answered as JSON or the exception text, console messages taken by the embedder, editable_focus, with_cef_browser on the widget, the profile flushed on Event::Shutdown, and a repr(C) mismatch in the FFI fixed.
platform/video: VideoFileEncoder::new_fragmented lays the container down in movie fragments (AVAssetWriter's movieFragmentInterval), proven by tests/fragmented_growing.rs: 90 of 120 frames readable before finish, all 120 after. Windows and Linux write one movie as before. The Apple backend's plain constructor went with it: nothing called it once the fragment-aware one existed.
platform: the audio output fence is seated in the one seam (media_api.rs), so a panic in an app's output closure costs that closure and its buffer, not the device thread, and the taps are fed the silence so a recording keeps its place; its tests adapted to this tree's tap registry. /midi routes inject a message as if a device sent it, declare ports for the app to adopt, read back what the app sent, and reset (platform/src/midi.rs, remote.rs).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Taken from vjroger/work. A full merge of that fork fights this work branch
in widgets; this is the stems crate, vocal mel-band, span-cache lanes,
log_ring, output fence, midi inject, effect_doc, mp3 sniff, mp4 audio
edit, and audio-only file open. Stage on origin/main cargo-checks again.
Squash of 7 work commits (Sep 2–12):
95fd7d6 platform: a hosted window with a dpi override lays out in its own points and gets the host's pointer remapped
c2c7f51 platform: a hosted window on Windows draws again — the depth buffer matches the shared target's allocation
3b1a8c2 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
5ff7397 platform: typed geometry uploads on OpenGL; the typed gate names only the backend that still lacks it
80bf3d3 platform: Linux hosted GPU transport and routing, hosted tick pacing, WGSL packed vertex members, Vulkan typed geometry
e2d8a0a platform: the Linux GL and gpusim cfgs build warning-free again
c8c757a vulkan: honor tile draw inputs and retire submitted frames correctly
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Squash of 3 work commits (Sep 2–12):
debd8c1 rename: the mp prefix goes — apps/wm, files, terminal, browser, task, sheets, image, video, pdf; libs/wm_api and wm_theme
6dcca00 workspace: no timed std waits on web-reachable paths — the clippy gate covers every web demo's dependency set
9d8e314 platform: drop two in-band coordination notes that were committed with the tree
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Squash of 38 work commits (Sep 2–6):
ed5b2fa web: wasm32 portability in libs and web startup geometry deferral
0ccd384 platform web: focus dispatch, window-zero geometry and generation-correct ids after the startup deferral
a7af3ea platform + mpfiles: platform clock instead of std::time on the web, unwind-safe event dispatch
52251b7 platform: a namespaced async key/value storage API on Cx — files natively, IndexedDB on the web
84b46c1 mbtile reader: file-backed readers are native-only so the map stack builds for wasm
6b661bf web: crashes report themselves — panic text, breadcrumbs, memory, workers; a dead instance stops pumping
372bfd7 asset-store: browser durability — generation extents over cx.storage, chunked CAS, quota and GC
0f967ce web path: the stream trace and the sqlite pager never wait on a clock the browser does not have
4e58ab9 vj: the output window exists only once opened — never on the web
93232a2 platform: two pool workers on wasm until the allocator is per-thread
c7fe851 vj: effect thumbnails render, encode and persist in browser storage on the web
5b33781 platform: thread-caching allocator for the threaded wasm build
463de64 web: shaders compile per draw list, link in parallel
e7be0e3 vj + platform: the browser UI thread never waits on a lock, and the web hot paths log only errors and summaries
7b33f7b vj + platform: a loaded deck actually plays on the web vj + platform: a loaded deck actually plays on the web
dc85eb0 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
b39d301 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
1e2dcd0 web: a pass without a draw list is skipped instead of taking the app down (F12 layers overlay)
0ef0311 web audio: a throw inside the worklet's process() is reported with its real text instead of a bare ErrorEvent
97e0701 vj + platform: the web audio thread never waits on a lock — a loaded deck plays
58d3fd5 web audio: the output is created inside the first gesture, and a stalled worklet module load is retried on a fresh context
410acd0 web + vj + route: the console carries failures and one-line summaries, nothing per request, per tile or per hiccup
a3248d1 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
9e2d65b pdf + photos + task + wm + video + automate + widgets: no per-job threads — pool jobs and start-up workers
639887d 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
2aa0780 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
de9aba3 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
f615054 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
0d7ddee 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
e48b056 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"
b043332 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
3c2530d 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
303458d 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
1801e38 Harden web renderer and make Route location opt-in
09fa1f0 Restore WebGL text with complete fallback samplers
9e61553 Keep Route 3D buildings under bounded web memory pressure
b005c6e Preserve complete Route geometry within measured web memory budgets
0832b35 platform: support float GI targets and retained mesh snapshots
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Squash of 9 work commits (Sep 1–5):
929f822 video: the single-frame mp4 encode exists on every platform
294cb9e video: the single-frame mp4 is written on every platform, not stubbed
730b5b8 video: the Windows H.264 stream decoder pulls output before it knows the format
c1febc7 windows h264 stream decoder: low-latency mode, output type before first ProcessOutput, real MF_E codes, trace file
d6cc49a windows mft: PROVIDES_SAMPLES is bit 0x100, not bit 0
dcf7d21 windows h264 decoder: ICodecAPI low-latency, per-pump trace, access-unit dumps, and the stream tests run on Windows
d1e7a6f windows h264 decoder: AVLowLatencyMode is a VT_UI4; the round-trip test tolerates the MF encoder's access unit delimiters
aa816ed windows h264 decoder: pictures come out one access unit later — rewrite the SPS level so the DPB is one picture deep
2f44d20 apple: avoid blocking video clocks and release native players once
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Measured on the body node: the Microsoft H.264 decoder accepts MF_LOW_LATENCY and
CODECAPI_AVLowLatencyMode and ignores both; it holds pictures until the DPB it
derives from level_idc is full (six access units in, nothing out until DRAIN), and
appending access unit delimiters changes nothing. With level_idc rewritten to 1.0
in every SPS the DPB is one picture and each picture is emitted as the next access
unit arrives (5 of 6 while streaming, the last on flush). flush() now sends
COMMAND_DRAIN. The captured-stream test replays dumped access units and requires
the pictures while streaming; the keyframe-request check is its own test.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Microsoft H.264 decoder answers a VT_BOOL CODECAPI_AVLowLatencyMode with
"VT_UI4 != pValue->vt" (seen on the body node), so send the number. The
Media Foundation encoder opens each access unit with NAL 9, which the
keyframe check now skips.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Trace every ProcessOutput HRESULT/status, keep the first access units beside the
trace so a stream can be replayed offline, ask for CODECAPI_AVLowLatencyMode through
ICodecAPI as well as the MF_LOW_LATENCY attribute, and let the round-trip test plus a
captured-stream replay test run on a Windows box.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Microsoft H.264 decoder reports output stream flags 0x107 (whole samples,
single sample per buffer, fixed size); reading bit 0 as "the MFT allocates its
own samples" handed ProcessOutput no buffer and every call failed with
E_INVALIDARG — seen in the MAKEPAD_H264_DEBUG trace on the body node.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The live decoder never produced a frame on the body node: MF_E_TRANSFORM_STREAM_CHANGE
was hand-derived as 0xC00D6D60, which is MF_E_TRANSFORM_TYPE_NOT_SET; the real stream
change (0xC00D6D61) was treated as a hard error, the output type was only negotiated
lazily, and without MF_LOW_LATENCY the decoder holds a reorder window a 2-3 frame live
pipeline never fills. Set MF_LOW_LATENCY on the transform, commit NV12 before the first
ProcessOutput, re-negotiate on TYPE_NOT_SET/STREAM_CHANGE/BUFFERTOOSMALL, drain on
NOTACCEPTING, and stamp packets with monotonic 100 ns timestamps. MAKEPAD_H264_DEBUG=<file>
traces packets, HRESULTs, negotiations and frames for headless services.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The decode loop returned before ProcessOutput until the output type was
negotiated — but the MFT only reports MF_E_TRANSFORM_STREAM_CHANGE, the
event that starts negotiation, FROM ProcessOutput. A node fed Annex-B
access units never yielded a frame. Now the pump always pulls, a stream
change picks NV12, sets the type and refreshes size and stride, need-
more-input ends the pump, and rows are de-strided on the way out. The
decision is a pure function with a regression test.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Packages are makepad-<name> with the short name as the binary. Env vars
follow (MAKEPAD_WM_*, MAKEPAD_FILES_*, MAKEPAD_TERMINAL_*), config moves
under ~/.makepad/<app>/, the theme namespaces are mod.wm_theme and
mod.browser_theme, the hosted AI envelope key is wm_ai. platform/video
becomes makepad-platform-video so the video app can be makepad-video.
Carries the Score entries that were pending in the WM's curated table.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
encode_intra_frame_mp4 on Windows and Linux now goes through the
platform file encoder (Media Foundation sink writer, GStreamer): one
keyframe-only stream, one frame, a scratch file read back and removed.
It pays the container machinery the Apple session path avoids, but a
tile tape baked on any machine reads on any other, which is what the
image-tiles library sits on. A round-trip test encodes a frame and
decodes it through the platform decoder on whichever platform runs it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
encode_intra_frame_mp4 was macOS-only, and libs/image_tiles imports it
unconditionally, so image-tiles, its example and source-library did not
build for Windows (found by a Windows-target cargo check sweep of the
workspace; every other crate checks clean). Other platforms now get the
same signature answering with an error, the way the rest of this file
stubs what it cannot do yet.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Squashed from work:
- video: hardware first-frame decode straight from RAM — no temp files
- video: the encoder transform is reported once, not once per encoder
- video: a single still does not need a whole AVAssetWriter
Squashed from work; the fine-grained history is under tag archive/work-2026-08-26:
- vj: thumbnails become mp4 — hardware-coded sheets at measured-4K cells, and the bake stops racing the GPU
- vj: reverse earns a memory, and the effects stop aging
- vj: video goes NV12 end to end, and the GPU does the unpacking
- windows: the paint beat becomes the swapchain's own beat, and /g learns to see
- platform: the time repaint stops resurrecting passes their owner left behind
- metal: a fresh texture forgets nothing it never had — reallocated vec textures upload whole
- fab: a 3D creation shell and the viewer built on it
- raytrace: the traced pane starts coarse and doubles to native, with the raster underneath
An app built with `--remote` now serves a localhost HTTP control surface:
window list, per-window PNG grabs, real mouse/key/text injection, widget
rects, a log ring buffer, and `/gq` (grab every window, then quit). It exists
so a test or an agent can DRIVE a running app instead of reasoning about it
from source — the protocol is documented in AGENTS.md. Grabs are targeted per
window (`/g?w=N`), so a multi-window app is captured window by window rather
than whichever pass happens to present first, and `log!` mirrors into the ring
buffer without anyone owning the app's stdout.
platform/video grows a streaming half beside the file half. StreamEncoder /
StreamDecoder with Apple VideoToolbox and Windows Media Foundation backends,
Annex-B framing, and all-intra bound through pEncodingParameters on Windows —
the only control that MFT actually honors, as the readbacks claim success for
everything else. The file decoder can now be asked for a SPECIFIC frame rather
than only the next one, which is what frame-exact seek and bounce playback
need. Tests cover file seek and the stream round trip.
Draw shaders gain `Rgba16F` and `Rgba32F` color formats to pair with the
float render textures: blending off, whole-texel writes, meant for GPU
simulation state (particle position/velocity, fluid fields) rather than
pictures.
Windowing and dialogs:
- `CxOsOp::SetChromelessWhenMaximized` drops the native maximized border
strip on Windows, so a maximized window reads as a clean picture.
- `Cx::open_select_folder_dialog` opens the native folder picker with a
title and start location, answered by a `FileDialogAction` in the actions
pass; cancelling is a first-class outcome, not an error.
- Windows reports a user close the way macos.rs already did.
- macOS swaps the titlebar container so WindowDragQuery alone decides window
drags, and the delegates carry a panic shield.
- `Windows::id_iter()` enumerates window slots generation-correctly.
Headless: the virtual GPU and its rasterizer are substantially rebuilt around
the shader runtime preamble, making `MAKEPAD=headless` render-to-PNG a real
test surface rather than a smoke check. `PerfMonitor::frames_painted()` lets a
scripted driver pace itself to PRESENTED frames instead of queueing passes
faster than the GPU retires them.