Commit graph

642 commits

Author SHA1 Message Date
091712f55a Merge upstream origin/dev c86415ef6 (30 commits) into nigig fork - preserve work content, game crates, nigig protocol, widgets layout 2026-09-27 01:53:53 +03:00
Admin
6c5c71f92e maps: tiles ship only what the renderer draws, and a frame draws only what is on screen -- one detail contract in mbtile_reader::map_tags (detail_feature_used, micro_icon, the tag allowlist) is shared by the renderer (MvtSink::wants_feature skips rejected osm_* features in the detail pass before any id is allocated), the base bake (non --full drops them and stamps makepad_detail_contract=features-v1) and the repacker (a DATA_POLICY row; the verifier accepts exactly the contract's drops): address-only nodes (85% of detail points), plain road/building lines duplicated by the base and polygon layers, and relation points go; icons, trees, bridge corridors, platforms and detail buildings stay. Hosted city tiles shrink ~24% (Amsterdam z14 608 -> 465 KB). makepad-map-render-check builds each tile from the original and the rewrite at buckets 14-18 in 2D and 3D and requires identical buffers (bitwise digest, NaN-safe) and equal baked-face hits: ~3000 builds over local and hosted world tiles, 0 mismatches. Found on the way: base, detail and overlay polygon ids all started at 1 and the fill pass groups rings by id, so unrelated polygons of one colour fused; they now use disjoint ranges. makepad-map-repack --in-place converts an archive over itself shard by shard (cross-shard blobs stashed first, each partial verified tile by tile against the still-present original, journaled, renamed; root last; resumable), and --remote user@host:/dir runs it from this machine over parallel ssh streams against a sparse local mirror with SHA-256 checks. GPU/memory: only visible tiles are drawn (the prefetch ring, a whole z14 tile wide past z14, was drawn every frame), building outlines, flat-road fringes and roof edges move to the compact 28/16-byte formats, the shadow pass skips unlifted road chunks and off-screen terrain cells are skipped; z16 flat 6.3 -> 3.8 ms GPU, 123 -> 36 draws, 151 -> 94 MB resident; z17.5 7.3 -> 3.6 ms, 158 -> 26 MB; max tilt 5.5 -> 2.8 ms; pixels unchanged. New traces gpu.shaders, map.streams, map.frame
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 23:41:52 +02:00
Admin
036fa2fd86 apps, examples: the window manager on Android and Windows, the phone layouts, the task manager, director, mail and the rest; Flow, the asset UI and VJ move to Stage
App and example changes, with the apps that moved to the Stage repository (apps/vj, apps/asset-ui) removed here.

Covers work 6f1e44649..2b1a41df4 for apps examples:

- wm: the Android super-app compiles tiles on the phone against the host engine
- cargo-makepad: the super-app APK is packed by `android dyn-pack`, in Rust
- widgets, storybook: the widget catalogue app, some eighty new widgets, a theme store with mixable style sheets, and the rule that a press belongs to
- wm, widgets: the style tween starts with all eight weights, and the new style sheet takes the last number instead of macOS's
- platform: the Android desk swipes at 120 Hz — offscreen render passes and framebuffers cached, SVG meshes kept, font families that complete
- flow: the flow-ui app and the flowgraph canvas return to the workspace, with staged progress in libs/flow
- app_main!: only ship the fonts an app declares (#1247)
- platform, widgets, wm: every Vulkan pass renders through a negative-height viewport again, so a Wayland or X11 window stands upright, and no capture
- calendar: its own colour contrast is named explicitly, now that the theme store exports one under the same name through the widgets glob
- platform, wm, director: a hosted app's software frame arrives as a top-left texture and the window manager and the director carry no flip term at al
- wm: the desktop style menu lists each style once
- cef, video, platform: what Stage's browser needs from the shared layers
- platform, wm: work builds again on iOS, tvOS and wasm, and the window manager is warning-free on Windows
- ci: tools/ci, a Splash runtime that watches a branch and runs every ci.splash it finds
- ci: the terminal gets its pty helper, director is a desktop tool, and a refused input is asked again
- apps: what the CI box found
- Remove Flow, asset and VJ applications moved into Stage
- ci: a quiet header, a build that visibly moves, and scripts that leave the machine alone
- tests: the workspace suite, run as a whole for the first time, passes outside the example UI tests
- examples: the UI tests pass, for the reasons they failed
- tests: the last three failures of the CI box's night
- tools: makepad-screen is makepad-agents, and its binary is `agents`
- tests: the three binaries over ten seconds in release come under it
- wm: the shell menu says what it did, and the CI waits for that
- mail: the phone layout lines up
- clock: the phone layout fits both orientations
- calendar, reminders, calculator, sheets: the phone layouts fit their space
- platform, widgets, wm: a touch that is taken away is cancelled, never released
- weather, notes, finance, photos, route: the phone layouts tidy up
- files: the phone layout tidies up
- wm: the phone shell's surfaces match the app and the grid
- wm on Android: every app is its own process
- clock: a cancelled release neither opens an alarm nor switches tab
- platform, wm: hosted apps ask the WM for what they cannot do themselves
- wm on Android: apps build on the phone
- wm on Android: app transitions and gestures feel like the phone's
- android: rotated Vulkan windows stop rebuilding their swapchain every frame, and hosted children get touch
- android: hosted children hand frames over with GPU fences and draw only when they have work
- wm on Android: gestures and surfaces settle like the phone's
- widgets: touch lists scroll with Android's physics
- wm on Android: the shell follows the Pixel launcher's motion
- wm on Android: Recents shows the apps over a receding home, and the home screen switches looks
- wm on Android: the look switcher stays put, the iOS dock shows its icons, background apps follow a look change
- task, cargo-makepad, widgets, audio: the task manager chooses its columns, graphs every process' network and disk traffic and installs itself as a D
- files: the tile view's three projections are toolbar buttons
- mail: the local view takes a theme-derived palette and line icons, search pages share records
- director: agent lanes form a tree and Grok joins the usage bar
- widgets, draw: skeuomorphic surfaces light each other through an optional relief buffer
- widgets, platform: a texture can light the relief buffer, menus take colour chips, and a style reload recompiles changed shader functions
- platform, widgets, audio_route, ai: window crossfades and whole-frame presents, caption controls that click, themed menus, a stereo-pair audio tap,
- builder: the Builder TUI matches the new terminal design, Windows executables carry app icons, and every app has one
- files: the Files app deletes nothing and never overwrites
- director: coding agents ask before acting unless you choose otherwise
- sheets, score, git, home: saves cannot cut a file short or overwrite another one, and checkouts cannot write outside the repository
- widgets, builder: the big widget families are features, all on by default, and the Builder takes none of them
- ai: Claude Desktop drives any app with the F10 panel
- wm: starts on Windows
- wm: children open no console windows on Windows
- wm: the whole deck out of a Builder's source, compiled only when the person opens an app
- ai: Connect hands the .mcpb to Claude Desktop itself
- wm: the clock and calendar know the date on Windows
- wm: opening an app rebuilds it when its binary is out of date; warm instances never build
- civil-time: one local wall clock for every app, and it knows the zone on Windows
- platform + wm: a hosted child redraws at its tile's new size
- calendar: the Calendars sheet is an opaque panel, and the wide layout does not float one over its sidebar
- platform: an app's package dir, icons and bundle name rebuild only that app
- build: the AI stack, csg, Scope and Source Library join the one workspace
- ai chat: the chat's backends are the CLI, MCP and cloud providers; the local model is the `localai` feature
- apps: every app that hosts the chat has a `localai` feature for the local model, off unless the app's own job runs one
- widgets: every widget family is a crate of its own under widgets/families, and makepad-widgets links, re-exports and registers the ones its features
- aichat, widgets: the chat reads the design feedback through the tweaker's hook, so linking the chat no longer needs the tweaker
- apps, examples, libs: each crate builds only the widget families it uses, and the design overlay is each app's own default feature
- ai chat: a build without local AI starts on the first provider that answers here, not on "No model"
- repo: no third-party comic archive, generated models or sample asset in the tree
- remove big example media files
- wm: in a Makepad Builder installation apps build through the Builder, however wm was started

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 20:10:58 +02:00
Admin
014bbc343c remove big example media files
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 13:32:23 +02:00
99ca24dbbc Merge upstream origin/work 5f99533 into nigig fork alongside dev 2026-09-25 17:32:26 +03:00
a0f46b7d83 Merge upstream origin/dev fda40f56 into nigig fork - preserve nigig hub/web_server, take upstream dev updates 2026-09-25 17:25:35 +03:00
Admin
e047d2a790 platform, widgets, audio_route, ai: window crossfades and whole-frame presents, caption controls that click, themed menus, a stereo-pair audio tap, and the AI chat on local Claude Code / Codex with images -- a window can snapshot its presented frame and crossfade it over the next one (0.25 s, Metal; other backends cut), and can hold a frame until everything in it is on the GPU so a relayout appears in one step; app controls in the caption bar answer the window's drag query as client so real clicks reach them; menus scroll within the window and keep a readable text/background contrast, drop-downs take their popup look from the host; relief surfaces gain a texture light knee, spill tint and screen colour maps. audio_route taps a player's output on the device's own stereo pair (no system downmix, device rate and channel order) and reports its format and permission without prompting. The AI chat can use a logged-in Claude Code or Codex CLI as its model (tools as tagged text blocks), attach dropped images, and pick its model; the speech lib gains opt-in GPU pacing, a shorter audio context and a token cap; audio tags expose bpm. The remote bridge gains window resize and drag-query probes
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:48:31 +02:00
Admin
149138afc7 widgets, platform: a texture can light the relief buffer, menus take colour chips, and a style reload recompiles changed shader functions -- relief_texture_light makes any texture a light source for neighbouring surfaces: the relief pass runs after the texture's producing pass in the same frame and repaints only when that producer painted, with a soft knee (and damping of near-white frames) so a flash does not flood every bevel; the buffer gained a fifth, widest blur level so spill washes the near half of a neighbouring face, surfaces take a style-wide spill tint and ceiling, and ReliefView caps can follow a held button. MenuRow::swatch(fill, dot) puts a colour chip before a row's label. A style reload re-evaluates Splash modules under the names they had, so the object- and function-address shader caches handed back the previous shader or another template's (changes landing a reload late, or on the wrong surface); a pending style reload now clears those two caches like a file-change live edit does, keeping the code-keyed cache so unchanged shaders do not recompile. examples/skeuomorph gains an animated plasma screen lighting the keys beside it. glass renders pixel-identical, hello_world differs only in its animated GIF
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 01:11:51 +02:00
Admin
1c64cfdfeb widgets, draw: skeuomorphic surfaces light each other through an optional relief buffer -- mod.sdf.Material shades a widget from its own SDF (height profile, normals, key light, inner shadow, AO, rim, gloss, cast shadow, revolve-profile knobs, a ±1 LSB screen dither and optional grain); widgets that opt in register lit shapes (rounded box or disc with a height and an emissive colour) keyed by their draw list, and the window renders them once into a quarter-resolution f16 height+emissive buffer with its own blur chain, rebuilt only when the shapes change, so a lit LED spills onto its neighbours' bevels, raised parts cast AO between widgets, and nothing renders at rest. Material draws bind the same textures, so batching is unchanged (39 draw calls with and without). A window with no lit shapes allocates and records nothing; hello_world and glass render pixel-identical to before. examples/skeuomorph shows a Bluetooth key, lit ON/OFF buttons, a knob with an LED ring and a segmented control
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 23:49:22 +02:00
Admin
3e8eba0122 examples: the UI tests pass, for the reasons they failed -- the dock reports a tab header clipped to its visible tab bar, and leaves out a tab that is wholly scrolled out of view: the splash example's left panel has more tabs than room, "Toggles" is cut off at the panel's edge, and the centre of its unclipped rect lay on the neighbouring panel's first tab, so a test (or any automation) that clicks a tab by its rect opened the wrong one; the splash test then scrolls the Toggles page to the dropdown that sits below its fold, the way the media test beside it already scrolls; and the render-to-texture test captures until the child pass composite is there (at most three seconds) instead of judging the first frame after the pane has a rect, which is one frame before the composite lands -- what it pins is that every quadrant arrives in its own corner, not on which frame
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:55:46 +02:00
Admin
9788b827eb tests: the workspace suite, run as a whole for the first time, passes outside the example UI tests -- each failure was settled from history as a stale test or a regression. Stale, expectation updated to the change that overtook it: draw's road pack tests fed a z-bias tick outside the exact f16 range; network no longer reserves Accept (906f94a94); the log ring test waits for the asynchronous sink (2e27ce2ff) and the audio tap test no longer assumes it owns the shared registry; xatlas compares the irregular oracle within the official tool's float precision instead of bit for bit; xr's four-wheel car exposes the chassis query plus one per wheel (080794781) and the depth mesh plan follows the 0.32 m chunk (ddec6fc60); score's DSL test sets up the OS context clock it reaches; hello_world's GIF test describes the fixture that is actually embedded. Regressions, code fixed: the tweaker could not print layout enums as whole values because the derive never emitted the __enum companion it looks up; the workspace style picker never learned about the Black orange style put at the front of DesktopStyle::ALL, and per the decision that Black orange is not offered in pickers it lists ALL without it, maps indices accordingly and loads a stored "blackorange" without a selection; xr's car controller no longer scales engine force by 1/dt a second time (same force at the fixed step) and a scaled vehicle's suspension is stiff enough to carry it at its shortened rest length. The two xr tests that need a local-only reference dump (xr/dump is git-ignored) say so and return
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:41:03 +02:00
Kevin Boos
5e9a697940
app_main!: only ship the fonts an app declares (#1247)
Every manifest `app_main!` emitted carried three fonts no theme role uses:
`NewCMMath-Regular.otf` for `MathView`, and `Inter.ttf` / `RobotoFlex.ttf` for the opt-in
iOS and Android platform styles. That was 3.6 MB in every package, and it only existed
because a font an app forgot to declare failed silently: `FontFamily::update_font_definitions`
skipped a member whose bytes never arrived, so the text showed as boxes with no log line.

* Drop the forced extras. The manifest is now the font set's fallback chain plus whatever
  the app puts in `font_assets`, which is what makepad's own apps already did for `Inter`.
* `font_assets` takes expressions, and `INTER_FONT_ASSET` / `ROBOTO_FLEX_FONT_ASSET` join
  `MATH_VIEW_FONT_ASSET`, so an app declares a font by name instead of by path.
* A font that never loads now logs one `error!` naming the path and the fix. A missing
  member still degrades gracefully: the family keeps its remaining members.
* The apps that use those fonts declare them: the `wm` family binds both platform faces,
  `clock`, `weather` and `director` draw with Inter and can select any style, `terminal`
  and the builder use Inter for symbols, `splash` and `aichat` use `MathView`.
2026-09-19 20:35:58 +02:00
Admin
12d223737a tools, arch, docs, workspace, examples, sqlite, wasm_bridge
Squash of 55 work commits (Sep 1–12):
  0fd356d  windows: the vendored bindings are generated from a checked-in filter
  79882b5  fabric: a photo or a live camera to a fitted sewing pattern
  1e93309  AGENTS.md: designs stay local; no OS screenshots; focus and hidden-window laws
  aa96dbd  cargo-makepad wasm: package the bin target's wasm and create dirs before minifying
  14d0723  cargo-makepad wasm: production packaging — strip, small profile LTO, optional binaryen, size report
  79e7526  sqlite: a page-store seam — the file backend as before, an in-memory backend, and open_memory / open_with
  60ee978  cargo-makepad: package artifacts carry a content hash so a re-upload is a new URL
  611c9eb  cargo-makepad: production packaging stays off fat LTO; script VM under LTO investigated
  ab8febc  cargo-makepad: fonts packaged from the app's font manifest
  f6bbee9  wasm bridge: shared memory asks for the 4 GiB wasm32 ceiling and steps down where the engine refuses
  fb1416d  cargo-makepad: the threaded wasm module is linked with the 4 GiB wasm32 memory ceiling
  fd5d70c  cargo-makepad: the app's own resources are packaged under its bin name, which is how self:// resolves
  f51ca07  workspace: 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 stack
  942ff86  sqlite: the browser store has one owner — its locks never wait on a clock
  82d0cfa  web path: the trace helper keeps its doc, the journal nonce steps a counter where there is no clock or pid
  6f8c08f  web-server: POST /api/crash stores crash reports in a rotating log on both servers
  106b38c  wasm bridge: the imported memory honours the module's declared limits
  94b8726  dj-pack: tracks in, stems through the hub, a site store snapshot out
  d9f04fc  dj-pack: pack reads caches, never creates them; dry-run writes nothing
  e6a305c  ai-hub + dj-pack: a whole track fits a stems job; long tracks split into spans
  d1910b8  web-server: a store snapshot's extensionless routes are served with the types the exporter recorded
  c1f7b53  asset-client + dj-pack: a long description never rejects a snapshot; the packer writes one bounded line
  453197d  dj-pack: analyse produces the beat grid, overview and loop-splat caches the demo cache ships
  9b4a3ca  network: every completion raises the UI signal
  fad1c49  web server: audio and text files are served, and models/ is immutable like maps/
  569b4a7  dj-pack: every CC BY and CC BY-SA version and the public domain mark are redistributable licences
  dc9cce6  workspace: no std clock on the web in any crate the web apps link — the last start-up worker death is gone
  c7639f0  clippy: timed std waits (sleep, recv_timeout, wait_timeout, park_timeout) are disallowed — they read the std clock and panic on wasm workers
  d748753  wasm bridge: the page environment carries js_worker_wait so the module links — the pool landing added the import for workers only
  ec40fdb  vj + 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)
  fe23e06  AGENTS.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+F10
  e689aea  web_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 404
  cd33943  web_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 once
  2f3e393  web_server: a directory path without its trailing slash (/score) redirects to /score/ instead of 404, query preserved
  9a31d21  flow-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>
2026-09-15 13:40:33 +02:00
Admin
3b8cd8a69a apps: WM, wm-all, phone apps, files, route, sheets, photos, image-tiles; the mp prefix rename
Squash of 59 work commits (Sep 1–12):
  b0380ba  image-tiles: the picture-wall engine as a library — tape atlases, a baker CLI, and the TileGrid widget
  83d8eac  mpsheets: demo feature and the SheetDocs seam
  daff390  finance: demo feature — generated ledger, SQLite target-gated, import hidden
  13b4c48  mpfiles: demo build — procedural fake filesystem, still-image thumbnails, chat feature
  58e1f72  mpsheets: review fixes for the demo seam
  3203e32  finance: review fixes — id remapping on persist, structural determinism tests, one cfg seam
  0537687  mpfiles: distinct repo-owned pictures for the demo thumbnail pool
  fe920c8  files: review fixes — demo scan exclusions, Zipf sizes, trash root guarded, depth bound, tests
  4144dc4  files: the spy test filesystem implements the clock
  1940f3d  fonts: leave apps/wm untouched — its font-set declaration waits for the aichat lane to land
  b0e34c2  wm: the AI pane and its bus — the aichat child seated in the slot, F10, the os service with the typed open
  de937ac  route: the web build is a one-to-one recompile — native UI, service seams behind it
  2f5a984  files: the file browser on the AI bus — four read-only tools through a correlated, cancellable runner
  2b035ff  route: the navigation session keeps time on the platform clock — the std clock traps on wasm
  1b70899  files: the space view is where a tab starts
  412b3c9  files: the space view rescans through the virtual filesystem — the web has no other disk
  0105fa5  files: the space view opens in 2.5D
  5d007e0  files: an unset projection preference means 2.5D
  6857d86  files: the projected treemap clips boxes at the near plane and keeps the camera above them
  d3cd233  wm: one desk for every target — the host seam, the assistant seated in-process, the web profile, and the assistant up at boot
  6d47c3f  wm: the omarchy themes moved to omacom/omarchy — the importer follows
  82def6b  wm: every app under the desk — the chat keeps the keyboard through an automatic refocus, a pool that gives up, polite closes for browser, sheets and aichat
  6105b61  sheets + files: the assistant reads and writes cells, makes folders, renames and trashes
  82ac768  photos: the picture wall as an app — the SMBC archive on the tile engine, a module from its first line; fabric in the launcher
  190062e  route: the maps app exposes its tool table to the desktop assistant
  3768653  image_tiles: the wall is box-packed — justified rows keep every picture's own shape and fill the width
  3691875  wm: launcher icons — a photo for Photos, a shirt for Fabric, a globe for Route, a play badge for Video, a pulse for the task manager
  8625076  aichat + photos + image_tiles: make me a picture and it lands on the wall; the wall filters as you type, tiles flying to their places
  1dcca41  wm: a theme with no wallpapers fetches them on its own
  ff6cfec  wm: minimise, maximise and close in the bar's top right on Windows and Linux
  62f38a5  route: --hour=N pins the theme hour for harness grabs
  362ac59  wm: the checkout is found from the working directory too, and a sibling binary is an .exe on Windows
  0fdfba7  files: the web's makepad home is a fixed virtual path — std's temp_dir panics there
  daf88e1  route demo: the tiles come from the repacked world archive at its own never-cached path
  15c3b11  ai-services: what the pubsub review found — modules get a subscription seam and a publish sink through both WM paths, lease end flushes unsubscribes to hosted services, the subscription cap counts closing rows, an endpoint's queue is dropped after Unregister, the prompt drops a subscription on final
  d852699  route: no tile-source dropdown — makepad.nl is the tile source through the local range cache; a world.mkmap in the saved maps folder is the only override; the stale preference file is removed on start
  aa271c3  map + route + geodata: the Terrain layer through the archive plane — TerrainSource (hosted .mkmap elevation shards fetched by range through the shared reader, a local MBTiles only as a dev override), the hillshade rendered on the pool's heavy lane with reused TerrainScratch buffers (web capped at 2048×1536 at DPR 1, native DPR-aware), one request in flight; the demo checkbox now renders terrain like native
  dbc7838  route: the maps-folder field and its save button are gone from the settings panel; the maps root is automatic
  a53d9b6  route: no clock-driven night theme — the theme is the user's toggle, remembered in cx.storage, default day (the hour rule fired on the web for the first time once wasm had a clock and darkened the map after 19:00)
  ca92ff9  route: the open sea on the web — the ocean-low/ocean-high overlays are an always-on group in the shared hosted overlay table, read through the archive plane (makepad.nl, cached); native keeps the local ocean files only as a dev override; the native-only OCEAN_MBTILES path is gone
  4cd24c4  route demo: the first location fix flies the map to the user at zoom 14, as native does; Amsterdam stays the default until a fix arrives
  2e869f8  route: the ocean-high overlay comes from the re-sharded archive (58 shards of at most 16 MB, one small leaf directory each) instead of two shards whose directories decoded to 407 MiB
  8021bb0  Add Clock and Weather with shared mobile tile views and persistent alarms
  77b8309  Make application layouts and custom widgets follow desktop and mobile themes
  b357164  Add desktop and mobile compositor shells with OS switching and dock transitions
  11dec2e  Keep hosted app output readers off the shared task pool
  c4002c5  Round complete desktop surfaces and add Windows snap layouts
  a5f8dd8  Frame home photo tiles and clip the picture wall below app controls
  678721d  Give mobile app libraries real search focus and hosted keyboard input
  4794cdf  Keep window title fills opaque at the application surface join
  2cc584e  Match Windows 2000 and NeXTSTEP window chrome to original screenshots
  4a876a8  Give Files navigation and storage tools a clearer hierarchy
  7821c90  Keep prewarmed browsers in the active desktop appearance
  5bfe694  Compact the Files toolbar and repair navigation and selection actions
  44fef36  Preserve Photos subjects and zoom across host view and aspect changes
  ae20efc  Draw larger macOS traffic lights with centered hover symbols
  2bc4d89  wm: the WM is a library plus a desktop binary, Linux controls, hosted tick pacing
  d643eb4  apps: the in-process app wave — mail, notes, calendar, reminders, calculator; clock, weather, finance, photos and route as modules; civil time, read-only sqlite, Linux CEF
  56c1dee  wm: a timer beat missed while the child renders is serviced on its acknowledgement

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:40:28 +02:00
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
199be9eb1d map + route: the six overlays (EV chargers, transit, nature, districts, building age, population) read through the same archive plane as the base tiles — OverlaySource {name, TileSourceConfig}, hosted .mkmap archives on makepad.nl fetched by range through the shared archive reader and disk cache, a local .mbtiles only as a dev override; one layer table (apps/route/src/overlays.rs) for the native and demo builds, the demo checkboxes now set overlays like native
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:41:27 +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
697215e1d9 route + converse + example-map: every worker comes from the runtime pool or a start-up worker
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 16:21:17 +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
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
232909d16a script: the VM reaches std and its slot through one host — no aliased references
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 14:31:15 +02:00
Admin
19cf377238 platform: the thread runtime contract — spawner, tasks, pools, scheduler, UI waker
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 14:14:15 +02:00
Admin
6981e9052b fonts: manifest generated from the chains, app-level font assets, a symbol fallback, deprecated i18n aliases
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 13:22:42 +02:00
Admin
b0380bac34 image-tiles: the picture-wall engine as a library — tape atlases, a baker CLI, and the TileGrid widget
The Source Library wall's pixel engine, extracted for anyone's pictures:
libs/image_tiles carries the NV12 slot pyramid, the 32x32 shard atlas
geometry and the one-HEVC-intra-frame-per-file tape codec (tape.rs), a
small SQLite index (db.rs), a priority decode pool (store.rs), and the
TileGrid widget — instanced tiles batched per atlas page, anchor-locked
wheel zoom with log-space glide, continuous per-shard LOD with
crossfades, full-resolution promotion under byte budgets with LRU
eviction, and uniform-only re-presents inside the pad of the last build.
image-tiles-bake downloads a manifest of URLs (fetch pool free to be
wide, encode pool hard-capped — concurrent VT session churn has panicked
the encoder's IOMMU) and bakes a library; examples/image_tiles views one.
No JPEGs on disk; decode and encode are the hardware's.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-01 20:19:56 +02:00
Admin
0257d6c6dc engine libs: render and sim for a strategy round, the per-unit decision hook, the mp4 sample index, stitch and xatlas quieted, example refresh
Squashed from work:
- docs: button shader annotations — widgets/button.rs complete + splash demo buttons
- tweaker: the Shader tab shows the pinned widget's ANIMATOR STATES as little posed swatches under the well — one per tr
- widgets: the glass stops reading draw_pass.time, so glass apps idle again
- render, sim, platform: what a strategy round needs underneath
- draw, platform: overlays now composite above content that uses draw_depth
- asset: mp4 sample index for range-streaming, chat tools, import profiles
- platform: native file and save dialogs, in-house on all three desktops
- sim: a per-unit decision hook — one commandable unit can think for itself, before the kit steers
- makepad_ai is deleted — every backend is a hub pipe, the agent seam lives with its consumers (aicore §14, decided 2026
- libs: the zero-warning sweep — stitch casts say what they mean, xatlas keeps upstream's surface quietly
- zero-warning sweep, round two — the first full-workspace pass
- zero-warning sweep, round three — the model lanes and the deep examples
- zero-warning sweep, round four — the last stragglers
2026-09-01 16:46:35 +02:00
Admin
e37c263b9c ai backbone: the hub era — makepad_ai deleted, every backend is a hub pipe; machine residency elections, job leases, ETA placement; the store only stores; creator pipelines run in the app (aicore)
Squashed from work:
- asset-ai: FastH3 4-step fast video backend; clip keyframes on the wire
- asset-ui: loop video chains — text→image→video that ends where it began
- h3: safetensors -> pruned-Q4_K GGUF quantizer for the 24GB DiT tiers
- h3_quant_gguf verify: row-error gates calibrated to the measured Q4_K floor
- asset-ai realtime: the feedback loop — the source anchors, the drifted frame inits
- asset-ai realtime: a feedback loop survives a resize and travels by default
- asset-ai realtime: the feedback loop frees itself from the feed handshake and pauses for its listener
- asset-ai realtime: the outbound encode leaves the loop's critical path
- asset-ai ocr: the ocr domain — Chandra 2 at page resolution, and the tower goes planner-owned
- llm slots: a lane can hold an image span — embedding prefill and a rope cursor of its own
- vision tower on CUDA: the encode leg gets its two missing kernels
- llm/ocr: one M-RoPE grid encoder for both image paths, and a livelock made an error
- vision tower on CUDA: the f16 GEMM keeps the precision it was throwing away
- live: a feed that moves box takes its trip with it — one seed image
- vision tower on CUDA: the tiled attention becomes bit-exact, and tensor cores go
- llm prefill on CUDA: the MMA attention kernel gets the tile a 4-to-1 model needs
- asset-ai ocr: the CUDA encode lane joins the integration — vision-parity sits beside run's three arms, and the kernels
- Merge branch 'ocr-perf-integration' into work
- asset-ai: the live anchor can follow the trip, and text leaves the 5090
- asset-ai: the camera moves the world, and the world starts still
- asset-import: the EA strategy classics, in the one 2D contract
- rtsmap: one seeded generator for tiled strategy maps
- asset-ui: one card for the strategy classics, with a pack dropdown
- asset-ai: music3 reference-audio path, ocr/h3 backends, registry
- asset: mp4 sample index for range-streaming, chat tools, import profiles
- cnc: tiberium is twelve growth frames, not twelve empty variants
- platform: native file and save dialogs, in-house on all three desktops
- chat: the scan holds out for a lane home
- chat: a full home queues you — take the free lane
- chat: the preload has a percentage, and the boundless cap stops showing
- llm cuda: the 32x2 attention tile — even GQA ratios stay on MMA
- sa3 gets a bake path: the sfx model's tables precomputed by a diffusion-side bin
- sqlite_query: anti-join regression test
- td import: HARV's second frame block is its harvesting cycle, not a turret
- asset-ui: sprite enhancement runs on the 32B dev DiT — distillation, not the prompt, was the ceiling
- ai-hub: makepad-asset-ai becomes makepad-ai-hub at libs/ai/hub, the chat pane becomes makepad-chat-ui, the service bin
- asset-ui: test health fixtures grow the realtime field they were born without
- ai-hub: one home at ~/.makepad — weights/ run/ cache/ logs/, the service cache migrates from ai_content by a single re
- ai-hub: subprocess workers die with the node — process groups everywhere, PDEATHSIG on linux, one KILL_ON_JOB_CLOSE Jo
- ai-hub: the hub object — AiHub::in_process, pipes vocabulary, and the local LLM engine generalized out of mpfiles (aic
- strict-json: the dependency-free JSON module gets its own crate; asset-client re-exports it so nothing downstream move
- ai-hub: the machine layer — node entries, the 0600 machine token, and the residency election that IS the lock (aicore
- ai-hub: MPHUB1 — the fabric beacon only dedicated nodes can send (aicore §4)
- ai-hub: job leases — work lives only while it is renewed (aicore §8)
- asset-creator: the pipeline library is born — specs, the deps gate, and the derived-state law (aicore §9)
- ai-hub: RAM residency facts — the CPU-side twin of residency.rs (aicore §3)
- ai-hub: ETA placement primitives — relative GPU throughput, the four-term estimate, and an observable breakdown (aicor
- ai-hub: leases go live on the wire — origin fields on submit, /job/<id>/keepalive, /bye, and the reaper that cancels w
- ai-hub: the chat providers move in — fleet qwen, openai, grok, claude/codex/grok CLIs, the responses driver, and the w
- asset-creator: the engine — one pipeline run against the hub, deps-gated, spliced, cancellable, resumable-by-construct
- ai-hub: the machine node mode — --machine binds loopback, registers in ~/.makepad/run, and exits on its own once idle
- asset-creator: makepad-creator-run — the detached client for runs that must outlive a window (aicore §9)
- ai-hub: a native Claude Messages-API provider — API-key or Claude Code OAuth, bounded SSE streaming, injected tools (a
- route + converse: off makepad_ai — the Agent seam moves to converse, route's cloud dispatcher rides the hub's Claude p
- asset-creator: the preset tables move in — fifteen chain-policy constants shared by every creator app (aicore §9 / P6)
- makepad_ai is deleted — every backend is a hub pipe, the agent seam lives with its consumers (aicore §14, decided 2026
- ai-hub: loads hold the machine residency election — set_model_state claims on Loaded and publishes the service port (a
- ai-hub: chats run the machine election — route to a serving holder, wait on a loading one, claim and publish when open
- ai-hub: pick_for_domain_eta — ETA-ranked placement over the shared hard-filter core (aicore §6 / P4)
- asset-creator: the engine picks a provider per stage at dispatch time — a chain's later stages see fresh fleet state (
- ai-hub: the fabric secret gates the service HTTP surface — bearer on everything but /health and the ticketed peer path
- vj: DREAM runs execute in the app — pipelines.rs becomes the run it used to watch (aicore §9 / F1)
- asset-creator: the runner — generate one thing and put it in the catalog, one implementation for every surface (aicore
- chat-ui: the session runs in the app — no broker anywhere on the chat path (aicore P8 / F5)
- asset-store: assets.query is a first-class query endpoint — the bounded SQL surface outlives the broker (aicore P8 / F
- asset-creator: CreatorTools — the chat tool pack for a store that only stores (aicore §9 / P8)
- asset-store: the shrink — the store stores (aicore P7)
- importer + asset-server host: the coordination era ends (aicore P7)
- store config purge + asset-ui goes fleet-direct; the derive protocol gets its route proof (aicore P7)
- client + chat dispatcher: the dead wire comes out (aicore P7/P8)
- ai-hub: 0.3.0 — the health version says which era a node runs
- ai-hub: the default fleet is 'gen' — apps hear the LAN without env plumbing
- ai-hub: the preload note percents the prefill, not the job bar
- ai-hub: conversations keep their KV — the wire mirror, the lane identity, the in-turn dynamic context (aicore §7)
- ai-hub: an open-think model is thinking from its first token
- libs: the zero-warning sweep — stitch casts say what they mean, xatlas keeps upstream's surface quietly
- zero-warning sweep, round two — the first full-workspace pass
- zero-warning sweep, round three — the model lanes and the deep examples
- zero-warning sweep, round four — the last stragglers
- zero-warning sweep, round five — vj and chat-ui
- zero-warning sweep, round six — three cascades

Co-authored-by: Claude <info@makepad.nl>
2026-09-01 16:46:31 +02:00
Admin
3b4d6a4ff7 platform+widgets: sploded 3D inspect view, the tweaker design-feedback suite, script math-AOT and docs channel, pointer-pin and pixel-probe, modal layout, map warp
Squashed from work; the fine-grained history is under tag archive/work-2026-08-29:
- mp* wave: mpwm window manager + the mp app family, WM API, theme bridge, PDF engine fix
- mpwm polish wave: terminal key focus, focus-history close order, pop-back-to-origin, occupied-workspace cycling, demo
- mpwm: warm-instance pool, flat-luminance opens, flicker-free CEF resize
- work: land the sources the last commits reference
- kenney: catalogue all 50 free 3D kits; Modal dismissed() never fired
- platform: windows check green again — SetWindowTextW binding
- map: exact warp-aware inverse projections — pointer ops work folded
- mpwm: quick-look gap fixes; image cache eviction on preview unload
- tweaker: material thumbnails + vibecode popup + ctrl-space notes, undo/redo over the edit ledger, capture-semantics pi
- tweaker: vibe popup card chrome + dispatch order, ctrl-space notes verified, sploded design v2 chapter
- tweaker: tabbed side panel (Props/Shader/Tree) - shader tab with checkerboard material well + prompt, complete widget-
- sploded v2: nesting-depth z, hairline scope frames, body pass
- sploded: pin the depth convention with a test, kill the draw_depth residue
- sploded: real body-pass split (scene-pass capture, panel flat) + y-convention source of truth with anti-flip gate test
- sploded: hollow outlines, flat-band input, ray-pick unprojection
- tweaker: shader tab defaults to the selection's first draw layer, stale hint trimmed
- sploded: outlines become clipped, antialiased strips; tighter deck
- sploded: merge the lane's v2 (nesting-depth z, clipped AA strip outlines, flat-band input, unproject, SplodedStack bod
- sploded: the exploded view is a LIVE view — pointer events route through the inverse explode transform (ray -> plane -
- tweaker: tabs are real widgets (uid, tree node under the dock, own plane in 3D) and pickable; navigation-class clicks
- sploded: pinned/hover outlines render on the widget's own plane in 3D — per-widget nesting depth lives on the platform
- tweaker: the material well renders the pinned widget's actual shader — the swatch byte-copies the widget's live draw c
- tweaker: the Shader tab shows the shader as written — the layer's pixel/vertex fn source (nearest definition up the co
- sploded: I = true isometric preset (yaw 45°, pitch atan(1/√2))
- tweaker: eyedropper — the colour popover's pick button arms a pixel probe; the next press in the app samples that devi
- tweaker: the shader loop closes — /tweak/apply resolves the pinned widget by uid (anonymous path segments never round-
- vj: responsive DJ mixer + Windows drag-and-drop, cherry-picked from PR #1199 (vjroger)
- tweaker: the material well is a magnifier — the mirrored instance draws at the widget's native size in the well's own
- tweaker: per-layer material thumbnails — the Widget derive emits WidgetNode::layer_areas() (every #[live] Draw… field
- tweaker: the shader source view is the real CodeView (syntax highlighting, selection, editing) when the app registers
- tweaker: Ctrl+Enter sends on every platform (TextInput treated only Cmd as primary on macOS, so Ctrl+Enter inserted a
- Modal claims no layout slot: the DJ page fills its window again
- tweaker: every fn apply recompiles (eval_chunk ran every chunk under ONE synthetic callsite, so the script body — and
- tweaker: an apply whose draw shader fails to compile is rejected — the layer goes back (last live fns / the fn as writ
- tweaker: the Shader tab's source view owns its scrolling (the ScrollYView around the CodeView double-scrolled the care
- widgets: set_visible belongs to every widget, not just View (#1194)
- script: a dead heap's resource handles must not outlive it (#1195)
- Resources: search the executable's directory, not only the working directory (#1196)
- Windows: fit a restored window to the displays that are actually attached (#1197)
- d3d11: a failing GPU call reports the loss instead of killing the process (#1198)

Co-authored-by: Kevin Boos <1139460+kevinaboos@users.noreply.github.com>
2026-08-29 09:26:24 +02:00
Admin
d72cffd0f6 raytrace: the traced pane starts coarse and doubles to native, with the raster underneath
Squashed from work; the fine-grained history is under tag archive/work-2026-08-26:
- 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
- texcomp: the block codec and the container every texture will travel in
2026-08-26 08:49:47 +02:00
Admin
45e65e69db draw+widgets: a Splash keeps its host's walk across a body rebuild, a dock redraws its panels, boxed labels center on their ink, hsv2rgb compiles, and slider/tip/dropdown catch up
Squashed from work; the fine-grained history is under tag archive/work-2026-08-26:
- vj: the console grows real transports, and the deck stops lying about reverse
- vj: video goes NV12 end to end, and the GPU does the unpacking
- widgets: boxed labels center on their ink, not on the font's line box
- 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
- widgets: a dock redraws its panels, not just its own frame
- draw: hsv2rgb takes vector bounds, so it compiles
- texcomp: the block codec and the container every texture will travel in
- widgets: a Splash keeps the walk its host declared across a body rebuild, and logs a body that fails to evaluate instead of drawing nothing
- vj: DJ-tab scroll knobs, title-click reset, crossfade fix, stem headroom — plus the pre-Ampere CUDA fix (#1193)

Co-authored-by: Rogier de Leeuw <vjroger@gmail.com>
2026-08-26 08:49:45 +02:00
Admin
d1fb9ad8ad examples: datagrid, portallist_hit, render_to_texture, splat_bench
Four new examples, each of which is also the test surface for the thing it
demonstrates:

  - datagrid — the DataGrid widget across five tabs (sheets with a formula
    engine, big data, charts, pixels, widgets).
  - portallist_hit — PortalList hit-testing, with a UI test suite.
  - render_to_texture — the offscreen pass, with a UI test suite.
  - splat_bench — Gaussian splat sorting and drawing under load.

uizoo gains a dropdown tab; the splash example's UI test follows the splash
host-services change.
2026-08-23 01:34:36 +02:00
Admin
6d708d9391 Clean the public tree for a checkout other people can use.
Drop the archived old/ tree, root AI notes, splashgame.md (Arcade lives
in the private sandbox), widgets-dll leftovers, and LAN/oracle helper
scripts. Move download_*.sh into tools/, and move sim/math out of
libs/game/ so the public repo no longer has a game/ directory.

Also quiet first-party compile noise and skip asset-ui tests that need
sandbox kits or uncommitted fixtures.
2026-08-18 15:23:19 +02:00
Admin
5421bc71c6 Remove widgets-dll, hotload_ui, and the weezl tokio test.
hotload_ui and xr pulled a dylib widgets wrapper that made
`cargo build --workspace` fail. XR now uses normal widgets.
The vendored weezl async test needed tokio, which we do not ship.
2026-08-18 14:45:09 +02:00
Admin
3b1ed5107b Drop unused examples from the public tree.
Remove godot, scratchpad, arracing, comfyui, exf, ddgo, and git.
Flux workflow JSON used by diffusion tests moves into libs/diffusion.
2026-08-18 14:41:52 +02:00
Admin
765f4785fc Let a clean makepad checkout load and compile.
Drop the private sandbox clone from required workspace members
and Studio runnables. Finish the platform_ops VecDeque merge
(push_back / Option remove), land the mip-repeat texture API
the renderer already calls, and unbreak the Q3 importer plus
the godot example template that .gitignore had hidden.
2026-08-18 14:36:05 +02:00
Admin
f0e1f83831 Close the rik2 land: workspace, splash, and sandbox cleanup.
Point the workspace at libs/asset and libs/render. Drop Arcade
frontend, gamemaker, rig, pack registry, physics, and the old
libs/game gameplay crates. Those live in the private sandbox repo.
2026-08-18 14:24:00 +02:00
Admin
8fce54a7a8 Land the house Art-Net/DMX desk from rik2.
libs/show_control plus the automate example. Not Arcade gameplay.
2026-08-18 14:23:59 +02:00
Admin
55dde7b02a Land the 3D renderer and leftover sim/math from rik2.
libs/render (Renderer, SceneDraws, preview play) plus the Arcade
sim/math it still draws through. Gameplay crates stay out.
2026-08-18 14:23:59 +02:00
Kevin Boos
db678bdf30
new Fit bound based on the size of the line that it actually lands on (#1164)
* Windows: fix DPI-change problems: freezing, blank windows, drag-n-drop errors

- win32: do_callback queues re-entrant events (WM_DPICHANGED pumped inside
  Present, nested WM_SIZE) instead of dropping them; the drops left dpi/geometry
  stale, the window blank, and hit-testing offset after display-scale changes.
- win32: WM_DPICHANGED applies the OS-suggested rect and returns 0; removed the
  duplicate-delivery compensations the lossless queue obsoletes.
- d3d11: no unbounded Present(1) block after a timed-out frame-latency wait
  (DO_NOT_WAIT + paced retry); DXGI errors log instead of panicking.
- dnd: Drag/Drop events carry WindowId and are remapped via dpi_override_scale,
  fixing drop-zone offset under UI zoom (Windows OLE, macOS external drops,
  Wayland internal drags).
- win32: packaged-build window icons load at native shell sizes via LoadImageW.

* TextFlow: enforce `max_lines` for inline code wraps, list items, and inline widgets

`max_lines` + `text_overflow: Ellipsis` under-counted or skipped visual lines
whenever anything but a plain text run started one, so rich content (rooms-list
previews, anything with inline `<code>` or mention pills) could overflow its
line budget or hard-clip without an ellipsis.

* TextFlow: the inline `<code>` forced wrap left `is_continuation` stale, so a
  wrapped code run was granted one extra row AND reported one fewer — a 2-line
  overflow per wrap. The wrap now refreshes the continuation state and row
  budget, is refused when no line remains, and its prediction probes measure
  an unclamped layout (a clamped probe always claimed "fits on one line").
* Layouter: a non-wrapping layout truncated by `max_lines` never reported
  `is_truncated` (detection was row-count only), so `max_lines: 1` labels
  hard-clipped mid-word instead of showing "…". Width overflow on the
  surviving last row now also triggers the ellipsis.
* TextFlow: list items charged two lines each (marker run + content run); the
  marker now shares one visual line with the item's first content run.
* Inline child widgets (mention pills, images) bypassed the budget entirely:
  Html now gates them on `is_content_truncated()`, charges the rows they open
  via `track_inline_content()`, and holds a widget that lands on the last
  allowed line in place (`Turtle::set_flow_wrap`) instead of letting the
  turtle relocate it onto a row the budget can't pay for. A held widget that
  still overruns the line is hidden behind a tracked clip and replaced with a
  drawn "…" — the same contract text truncation has.

* TextFlow: fix row alignment and spacing for wrapped text beside inline widgets

On the single-batch text path (Windows/Linux), a multi-row text run never told
the turtle where its internal row boundaries were: every walk since the last
boundary — a bold sender on one visual row, a mention pill on the next — was
centered by `finish_row` against one merged row. Text sat a few px off the
pill baselines, rows around wrapped runs squeezed or overlapped, and an
up-centered pill on a padding-less first row rose above the clip and lost the
top of its rounded corners.

* DrawText: the single-walk path now allocates per visual row and runs
  `turtle_new_line_with_spacing` at each internal boundary, keeping one glyph
  instance batch. It emits a first-row walk owning the run's align entries and
  a last-row walk with an empty range, so the run is never shifted twice.
* Turtle: `FinishedWalk` carries a `RowAlignRole`. A wrapped run's rows are
  immovable (their glyphs share one batch): rows holding its visible text are
  an `Anchor` — `finish_row_center` centers every shiftable walk on the
  anchor's line, shifting a taller pill UP onto the text — while a
  whitespace-only first row (a continuation that wrapped on a leading space)
  is `Fixed`, so it cannot anchor a row to an invisible line. Anchor shifts
  are clamped so no walk's top can rise above the turtle's clip.
* Layouter: `first_row_min_line_spacing_below_in_lpxs` is now honored (it was
  stored and hashed but never read). Resumable draws pass the current row's
  height plus wrap spacing plus the centering overhang, so a continuation's
  second row lands where centered content beside it starts exactly one wrap
  gap below the previous row — zero residual shift for uniform-height pills.
  Selection capture and the `<code>` wrap probe pass the same floor so every
  layout of a run shares one cache entry.
* Turtle: an anchored row returns its bottom forgiveness — the surplus its
  allocation extends below the risen content — and `turtle_new_line`
  subtracts it, keeping inter-row gaps uniform on both sides of anchored
  rows. A turtle's final row keeps its full extent so nothing clips at the
  bottom.

* uizoo: Html fixtures for line clamping and pill/text row alignment

Repro and regression fixtures mirroring a chat client's message surfaces:
max_lines clamping with inline <code> at several widths, atomic inline-widget
(pill) relocation/hold/ellipsis under a line budget, and timeline-style
pill+text rows at 9.3pt and 11pt metrics — including a CJK-titled pill and a
padding-0 first-row case that guards against clipped pill tops.

* Layouter: fill the last permitted row by grapheme when ellipsizing

When `max_rows` is set together with ellipsis truncation, word wrapping
would move a word that didn't fit off the final permitted row before
truncation ran, leaving that row ellipsized at the last word boundary
("@…") rather than at the last glyph that fits ("@quokka:…").

Word integrity is meaningless on a row that ends in an ellipsis, so lay
the final permitted row out by grapheme and let truncation cut at the
actual width limit.

* DrawText: account for walk margins when resolving a Fit max bound

The layout bound for a Fit-width walk with a relative max bound was the
raw resolved max, but the turtle's final width — and with it the clip
rect — gets clamped to that max minus the walk's outer margins. On top
of that, a Label passes the same margined walk to its inner DrawText,
re-applying those margins inside the turtle. Text laid out near the
bound therefore extended past the clamped clip, which sliced letters
off the end of untruncated text and cut the appended ellipsis down to
a single dot.

Subtract the walk's own horizontal margins from the resolved bound, and
when the enclosing turtle is itself an unresolved Fit with a max bound
(a Label sizing itself around this text), subtract that turtle's outer
margins too, so the layout bound matches the width the clip is actually
clamped to.

* uizoo: fixture for bounded pill labels ellipsizing at the width cap

Pill-like labels bounded to a fraction of the enclosing width, at
container widths that walk across the cap, plus one inline in an Html
flow. Truncation must always end in a visible trailing ellipsis, never
a bare mid-glyph cut.

* Layouter: keep word-boundary ellipsis on continuation rows

Grapheme-filling the last permitted row is wrong when that row is an
empty continuation: grapheme layout force-places a grapheme wider than
the row's remnant past the width limit with the truncation flag unset,
drawing overflowing text with no ellipsis. Finishing the row instead
truncates within bounds, so continuation rows keep the word-boundary
behavior.

* DrawText: scale the Fit max bound into layout units

The layouter works in unscaled units and row widths are multiplied by
font_scale on output, but the resolved Fit max bound was passed through
in physical units — the same mismatch max_layout_width_for_walk already
divides away. Any font_scale above 1 on a bounded label laid text out
past the clamped clip, reintroducing the sliced-tail bug the bound is
there to prevent.

* Turtle: add Base.Line, a Fit bound relative to the available line width

A static relative bound cannot express what an inline widget's inner
text actually has room for: that depends on the line the widget lands
on, its own leading geometry (icons, padding, spacing), and the
trailing insets after the text. Base.Line resolves a Fit max bound to
exactly that, with the enclosing line's flow selecting between two
measurements that are each final at the moment they are taken:

- A wrapping line can relocate the widget whole onto a fresh row, so
  the bound is what a fresh row offers. Content sized to it either
  fits where it is, or fits the row the widget is relocated to.
- A non-wrapping line — including one held non-wrapping by the
  inline-content clamp on the last permitted row — keeps the widget
  in place, so the bound is the remnant up to the line's right edge.

The measurement runs from the current turtle's content origin rather
than its pen, because a Fit max bound is evaluated twice: before the
content is laid out, and again in compute_final_size when the turtle
closes. A pen-relative measurement would collapse the closing clamp
to the leftover width and clip the content it just laid out.

* uizoo: fixtures for Base.Line-bounded pill labels

The four behaviors the line bound guarantees: a long name ellipsizing
at a narrow container's edge, a mid-line pill relocating whole to the
next row at full row width, a pill held on the last clamped row
squeezing visibly into the remnant, and a short name in a wide
container rendering untruncated.

* Turtle/DrawText: keep tiny Fit max bounds from slicing or inverting clips

A line-remnant bound can resolve to nearly zero when the last permitted
row is already full where an inline widget's text begins. Two guards
keep that degenerate range within the whole-glyph truncation contract:

- The Fit max clamp in compute_final_size floors at zero, so a bound
  smaller than the walk's margins cannot produce a negative width and
  an inverted clip (a pill rendering as bare chrome with no title and
  no ellipsis anywhere).
- DrawText treats a bound too narrow for the truncation ellipsis
  itself as no bound at all: the layouter appends the ellipsis glyph
  unconditionally, so a narrower clip would slice it open. Left
  unbounded, the text overflows honestly, letting an enclosing flow's
  inline-content clamp hide the widget and draw the ellipsis itself.
2026-08-10 12:30:01 +02:00
Jason Yau
947f815181
Video playback fixes and improvements (#1155)
* android oes video zero-copy and gles shader fixes

* regenerate windows-rs by windows-strip

* fix windows video freezes with MF on an MTA worker

* regenerate windows-rs by windows-strip

* MTA MF video, COM notify, YUV texture reuse

* add local video file playback support to video-player example

* NV12 Metal present, seek warm-up gate, YUV full range

* fix Linux GStreamer video: A/V mute, HLS prepare, async teardown

* no-op SelectVideoTrack/SelectAudioTrack on non-Linux backends

* Linux ALSA/Pulse: bigger buffers, fix resample setup, report device rate

* fix some warnings

* Move XInput/DirectInput device discovery off the UI thread

* fix GLSL unpack4u8 for GLES 3.0 (#version 300 es)

* Linux GStreamer: DMA-Buf NV12 OES zero-copy, optional GLMemory path

* Linux MediaPlugin: DMA-Buf NV12 and GLMemory zero-copy present APIs

* Add Windows SourceReader DXGI NV12 zero-copy video path

* fix build error

* fix GLES: add highp precision for sampler2DArray in Linux shaders

* playback speed support for android

---------

Co-authored-by: jasonqiu <jasonqiuchen@outlook.com>
Co-authored-by: jasonqiu <jasonqiu@futunn.com>
2026-08-10 12:29:33 +02:00
Kevin Boos
ed3eb88d4a
TextFlow: fix max_lines clamping and row alignment for wrapped text with inline widgets (#1160)
* Windows: fix DPI-change problems: freezing, blank windows, drag-n-drop errors

- win32: do_callback queues re-entrant events (WM_DPICHANGED pumped inside
  Present, nested WM_SIZE) instead of dropping them; the drops left dpi/geometry
  stale, the window blank, and hit-testing offset after display-scale changes.
- win32: WM_DPICHANGED applies the OS-suggested rect and returns 0; removed the
  duplicate-delivery compensations the lossless queue obsoletes.
- d3d11: no unbounded Present(1) block after a timed-out frame-latency wait
  (DO_NOT_WAIT + paced retry); DXGI errors log instead of panicking.
- dnd: Drag/Drop events carry WindowId and are remapped via dpi_override_scale,
  fixing drop-zone offset under UI zoom (Windows OLE, macOS external drops,
  Wayland internal drags).
- win32: packaged-build window icons load at native shell sizes via LoadImageW.

* TextFlow: enforce `max_lines` for inline code wraps, list items, and inline widgets

`max_lines` + `text_overflow: Ellipsis` under-counted or skipped visual lines
whenever anything but a plain text run started one, so rich content (rooms-list
previews, anything with inline `<code>` or mention pills) could overflow its
line budget or hard-clip without an ellipsis.

* TextFlow: the inline `<code>` forced wrap left `is_continuation` stale, so a
  wrapped code run was granted one extra row AND reported one fewer — a 2-line
  overflow per wrap. The wrap now refreshes the continuation state and row
  budget, is refused when no line remains, and its prediction probes measure
  an unclamped layout (a clamped probe always claimed "fits on one line").
* Layouter: a non-wrapping layout truncated by `max_lines` never reported
  `is_truncated` (detection was row-count only), so `max_lines: 1` labels
  hard-clipped mid-word instead of showing "…". Width overflow on the
  surviving last row now also triggers the ellipsis.
* TextFlow: list items charged two lines each (marker run + content run); the
  marker now shares one visual line with the item's first content run.
* Inline child widgets (mention pills, images) bypassed the budget entirely:
  Html now gates them on `is_content_truncated()`, charges the rows they open
  via `track_inline_content()`, and holds a widget that lands on the last
  allowed line in place (`Turtle::set_flow_wrap`) instead of letting the
  turtle relocate it onto a row the budget can't pay for. A held widget that
  still overruns the line is hidden behind a tracked clip and replaced with a
  drawn "…" — the same contract text truncation has.

* TextFlow: fix row alignment and spacing for wrapped text beside inline widgets

On the single-batch text path (Windows/Linux), a multi-row text run never told
the turtle where its internal row boundaries were: every walk since the last
boundary — a bold sender on one visual row, a mention pill on the next — was
centered by `finish_row` against one merged row. Text sat a few px off the
pill baselines, rows around wrapped runs squeezed or overlapped, and an
up-centered pill on a padding-less first row rose above the clip and lost the
top of its rounded corners.

* DrawText: the single-walk path now allocates per visual row and runs
  `turtle_new_line_with_spacing` at each internal boundary, keeping one glyph
  instance batch. It emits a first-row walk owning the run's align entries and
  a last-row walk with an empty range, so the run is never shifted twice.
* Turtle: `FinishedWalk` carries a `RowAlignRole`. A wrapped run's rows are
  immovable (their glyphs share one batch): rows holding its visible text are
  an `Anchor` — `finish_row_center` centers every shiftable walk on the
  anchor's line, shifting a taller pill UP onto the text — while a
  whitespace-only first row (a continuation that wrapped on a leading space)
  is `Fixed`, so it cannot anchor a row to an invisible line. Anchor shifts
  are clamped so no walk's top can rise above the turtle's clip.
* Layouter: `first_row_min_line_spacing_below_in_lpxs` is now honored (it was
  stored and hashed but never read). Resumable draws pass the current row's
  height plus wrap spacing plus the centering overhang, so a continuation's
  second row lands where centered content beside it starts exactly one wrap
  gap below the previous row — zero residual shift for uniform-height pills.
  Selection capture and the `<code>` wrap probe pass the same floor so every
  layout of a run shares one cache entry.
* Turtle: an anchored row returns its bottom forgiveness — the surplus its
  allocation extends below the risen content — and `turtle_new_line`
  subtracts it, keeping inter-row gaps uniform on both sides of anchored
  rows. A turtle's final row keeps its full extent so nothing clips at the
  bottom.

* uizoo: Html fixtures for line clamping and pill/text row alignment

Repro and regression fixtures mirroring a chat client's message surfaces:
max_lines clamping with inline <code> at several widths, atomic inline-widget
(pill) relocation/hold/ellipsis under a line budget, and timeline-style
pill+text rows at 9.3pt and 11pt metrics — including a CJK-titled pill and a
padding-0 first-row case that guards against clipped pill tops.

* Layouter: fill the last permitted row by grapheme when ellipsizing

When `max_rows` is set together with ellipsis truncation, word wrapping
would move a word that didn't fit off the final permitted row before
truncation ran, leaving that row ellipsized at the last word boundary
("@…") rather than at the last glyph that fits ("@quokka:…").

Word integrity is meaningless on a row that ends in an ellipsis, so lay
the final permitted row out by grapheme and let truncation cut at the
actual width limit.

* DrawText: account for walk margins when resolving a Fit max bound

The layout bound for a Fit-width walk with a relative max bound was the
raw resolved max, but the turtle's final width — and with it the clip
rect — gets clamped to that max minus the walk's outer margins. On top
of that, a Label passes the same margined walk to its inner DrawText,
re-applying those margins inside the turtle. Text laid out near the
bound therefore extended past the clamped clip, which sliced letters
off the end of untruncated text and cut the appended ellipsis down to
a single dot.

Subtract the walk's own horizontal margins from the resolved bound, and
when the enclosing turtle is itself an unresolved Fit with a max bound
(a Label sizing itself around this text), subtract that turtle's outer
margins too, so the layout bound matches the width the clip is actually
clamped to.

* uizoo: fixture for bounded pill labels ellipsizing at the width cap

Pill-like labels bounded to a fraction of the enclosing width, at
container widths that walk across the cap, plus one inline in an Html
flow. Truncation must always end in a visible trailing ellipsis, never
a bare mid-glyph cut.
2026-08-05 19:35:06 +02:00
Admin
59ea58ee41 Gamemaker: linux build fix — GameDraws grew a firework slot
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 16:59:46 +02:00
Admin
8be3e4c561 Arcade: third-person player rig, activity button, gamepad wiring
A game gets a walkable character that can get into a car and drive it
in three lines and never mentions a camera:

    let id = Character::new(...);
    player_rigs.insert(PlayerId(0), PlayerRig::new(id));

Everything crafted is engine-side with defaults nothing has to specify:
coyote time, jump buffering, variable jump height, asymmetric accel and
decel, air control, landing recovery, a boom that snaps in and eases
out, look-ahead, speed pullback, and delayed recentring.

Script surface grows by three verbs (115 -> 118): game.player_character,
game.interactable, game.interact_prompt. Cars and doors-with-interiors
are derived affordances, so a generated game with a car and a house
declares nothing; game.interactable is only for chests and switches.
The prompt and the press share one search so they cannot disagree, and
it picks the nearest candidate in front rather than merely the nearest.

Four bugs found by looking at what ran, not by reading:

- Arcade never polled the gamepad at all. No game_input_states() call
  existed anywhere in the app, so the pad's state never entered the
  process and every binding downstream read a struct nobody filled.
- LT drove both brake and negative throttle, and brake force opposes
  reverse motion. Measured: clean reverse covers 13.8m in 2s against
  22.25m forward; with brake held, 0.63m. car.rs is unchanged -- a foot
  on the brake winning is a car behaving like a car.
- Mount cleared `hidden`, which means "solid to everything, drawn by
  nothing" -- so boarding left the driver as an invisible collider at
  the kerb. Now uses attached_to, the sim's seat pin, and saves and
  restores hidden rather than asserting a value.
- GameWorld::new() never set gravity; only reset_content() did. All 70
  new() call sites floated, and four files had each independently grown
  their own `world.gravity = 30.0`. A floating character never reports
  on_floor, so the controller silently refused to jump.

The in-vehicle boom goes 9.0 -> 13.0. The boom is a time budget, not a
length: at the car's top speed 9m was 0.37s of road ahead, too little to
plan a turn. The test states it against CarConfig::top_speed, so raising
the car's speed fails the test instead of quietly making the view tight
again. The pivot deliberately does not rise with it -- eye.y is
pivot.y + sin(pitch)*boom, so the longer boom already buys the height,
and driving should sit lower and more planted than walking.

Player rigs now survive Blocks::clear(): where you are sitting and where
you are looking are the player's state, not the game's content, so a
script edit no longer ejects the driver mid-corner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 19:38:05 +02:00
Admin
25ecf635f6 Controller prefab: character feel, follow camera, mount/dismount
Character feel went into character.rs rather than a fork — its own doc comment
argues a second controller would drift, and it was right. Acceleration and
deceleration ramps, deliberately ASYMMETRIC (starts have weight, stops are
crisp), partial air control, coyote time, jump buffering, variable jump height,
asymmetric gravity via the sim's own gravity_scale, landing damp.

New controller.rs: FollowCamera with separate position and rotation smoothing,
clamped pitch, a boom that snaps IN but eases OUT, look-ahead, speed pullback,
and delayed recentring that yields to the player's hand. Mount/Seat with camera
blending. movement_intent with deadzone and diagonal normalisation, so
diagonal WASD can't outrun cardinal.

ELEVEN FEEL TESTS, each named for the complaint it prevents: speed ramps
monotonically rather than stepping; stopping is crisper than starting; a late
jump off a ledge still registers; a jump pressed before touchdown fires on
landing; releasing early measurably lowers the apex; falling takes fewer ticks
than rising; air control is neither zero nor total; the camera cannot invert or
bury itself; dismounting puts you BESIDE the car, not inside it; the boom
recovers gradually rather than popping.

Two bugs it found in its own work, both invisible to endpoint-only tests:
- Variable-height jump broke an existing test: callers who set jump_pressed but
  never hold `jump` — the older single-flag convention, and what a generated
  game will most likely write — had their jump cut on the next tick. Now cutting
  requires evidence the button is genuinely held; full height for everyone else
- THE CAMERA BLEND NEVER ADVANCED. `blend / blend.max(eps)` is always 1.0, so t
  was pinned at 0: the rig held its old shape and then snapped — precisely the
  cut the blend exists to prevent. Tracked against blend_total with smoothstep

Four of its own tests were wrong before the code was: air control limits the
RATE, so enough air time still reaches full speed (the real claim is that the
same input builds speed slower airborne); the buffer window genuinely cannot
survive a long fall; two needed the character settled on the ground first.

NOT DONE, deliberately: the controller is not yet exposed as verbs
(game.player_character({})) and arcade still uses its own camera and WASD path.
The prefab and its defaults exist and are tested; binding is the remaining step,
and stopping beat half-wiring input routing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 18:48:03 +02:00
Admin
6623408a57 Bind the library and composition into script — and tell the model it exists
8 new verbs (table now 115): find_model (DISTINCT ids, not ranked duplicates),
find_palette (matched set from one pack), model, kits, cast, road_network,
town, dungeon. game.find was ALREADY TAKEN by entity-by-tag lookup — the
duplicate-name test caught the clash before it shipped, and find_model/
find_palette now match the agent TOOL names, so the model's knowledge
transfers between the tool it calls and the verb it writes.

Verbs run synchronously (search and layout are pure CPU); only GLB load and
draw need a host, so placements queue through the same mechanism as audio and
particles — which also means a scene composes headlessly with no renderer
attached. Tiles carry their own collider from the kit pitch, so scripted props
are as solid as hand-placed ones.

THE MOST IMPORTANT EDIT WAS A DELETION. splashgame.md said "Everything is
procedural... No image, model, or audio files" — the doc was actively telling
the model it had no models, which is why generated games were bare primitives
while 4,442 models sat unused. Replaced with an instruction to reach for the
library before game.box, three rules (never place result #1 five times; one art
pack per region; generate layouts rather than hand-placing) and a wrong-vs-
right example. A test asserts that claim cannot come back.

Two bugs found by probing the REAL library rather than reasoning:
- town() would have placed ZERO buildings, silently: it selects
  TileRole::Building, but every role-less model mapped to Prop — and
  city-kit-suburban is 40 whole buildings with no parsed roles. A role-less
  model is genuinely ambiguous (a building on a lot, or a cone at a kerb), so
  kit_from_index now takes a KitUse hint. Against the real library: 104
  buildings, 136 road tiles, 0 adjacency errors
- the index folds crossroads and T-junctions into one `junction` role, but a
  4-way cell needs four open edges; a T standing in for a crossroad leaves a
  road stub pointing at nothing. Disambiguated by name

village.splash is the scenery counterpart to racing.splash: a town, a wood of
four different conifers, a dungeon, a playable character — and not one model id
written by hand.

NOT BOUND, and why: game.tree/rock/blob and game.scatter generate MESHES, and
set_models takes an asset id, not geometry — there is no mesh-upload path for
generated meshes yet, so binding them would have meant faking it. Additive once
a generated-mesh queue exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 12:24:10 +02:00
Admin
a529923c13 Arcade render: CPU light bake, silhouette shadows, instance slimming
CPU light baker (bake.rs): per-static AO (5 face samples x 8 Fibonacci
rays), a sun-visibility term, and a trilinear probe lattice for moving
objects — all folded into instance colours the renderer already sends, so
zero extra bandwidth and zero GPU cost. Demo world, release: AO 15us,
sun 34us, probes 61us. The split is deliberate — AO is the expensive half
and is sun-independent, so a day/night cycle only pays the 34us. A ray
starting above the heightfield peak and heading up skips the terrain march
entirely: that early-out took the probe pass from 5.4ms to 61us.

Silhouette shadows (shadow_mesh.rs) replace the flat oriented quad: caster
points -> projection along the sun -> 2D convex hull -> fan triangulation,
which has no self-overlap and therefore cannot double-darken in an alpha
blend (the reason naive projected geometry bands). Draped over terrain
(vertices drop to ground height, long edges subdivide), soft rim from a
penumbra ring that widens with height, statics cached against (world edit,
sun position) — every shadow in a frame is ONE geometry, ONE draw call.
Z-fighting handled structurally: offset along the RECEIVER's normal with a
slope-scaled term (world-up slides the shadow on a slope), depth test on,
depth write off.

Instance stream 176B -> 128B (-27%), measured from the compiled shader:
sun_color/sun_sky/sun_ground/fog_color were 12 floats of identical data on
every cube and moved to uniforms. fog_density stays per-instance because
shadows switch it off individually.

RNG isolation is structural: GameWorld has no bake field and the ray set is
fixed, so there is no RNG here to share with the sim. Tape BYTE_IDENTICAL.
Deleted an unwired SDF-blob path and the dead project_box_shadow call site
rather than leaving two shadow implementations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 08:28:41 +02:00
Admin
bdbc946012 Arcade M6+M7: packaging/sharing with sandboxed installs, and the pretty pass
Committed together: both streams landed in libs/game/script, so splitting
them would produce two commits that don't compile.

M6 — packaging and sharing
- libs/zip_file gains a writer (store + deflate); real `unzip -t` validates
  our archives in an interop test. Packing is deterministic (fixed
  timestamps, sorted entries), so a package can be addressed by its own
  sha256 — which is what makes the registry's digest check mean anything
- libs/game/pkg: .arcade format (game.splash + manifest.toml + assets),
  total manifest parsing (attacker bytes always yield a Manifest or an
  error, never a panic; non-finite numbers refused rather than defaulted),
  registry client that verifies sha256 INSIDE download so tampered bytes
  never reach the extractor
- Hardened extraction: absolute paths, drive letters (C:x is absolute on
  Windows), UNC, backslashes, .., NUL/control chars, symlink members (via
  mode bits), duplicate names (the ambiguity IS the attack), declared-size
  caps checked before decompressing plus a post-decompress check, entry/
  total/archive caps, and a post-join re-check that the resolved parent is
  still inside the destination — which catches a pre-existing symlink the
  name test cannot see. 4000-round mutation fuzz with a canary file beside
  the destination; a 320 MB deflate bomb under 1 MB on the wire is refused
- Capability stripping rebinds fs/run/net to FRESH EMPTY OBJECTS rather
  than shadowing known verbs, so there is no hole the day someone adds one.
  Applied before the game handle is registered. Vacuity guard: an unstripped
  isolate genuinely reads a file, so the sandbox tests can't pass for
  unrelated reasons. Browser-installed games load Trust::Downloaded

M7 — pretty pass
- GameSun adopts draw::SceneSun (axis-converted: SceneSun is map-space
  y-south/z-up, games are y-up). Shaders compute hemisphere ambient +
  direct instead of each hardcoding its own split; defaults collapse the
  new formula to the old constants exactly, so unifying did not restyle
  existing games. write_into is the single write path — "one sun" is
  compiler-enforced
- Projected shadow geometry: the caster's silhouette along the sun, fitted
  in the sun's own (u,v) frame, so it stretches as the sun swings. Nearest
  N casters get projection, the rest blobs; one instance in the existing
  alpha batch, no extra pass. 0.6us for 24 casters
- Two pre-existing shadow bugs found via capture: the pipeline blends
  premultiplied, so unpremultiplied dark RGB ADDED light instead of
  removing it; and shadows were fogged, mixing them toward the bright
  horizon so a distant shadow came out lighter than the ground it darkened
- Particles are structurally isolated from the sim: GameWorld has no
  particle field and step_world has no particle code — the renderer owns
  simulation and its own RNG. particles_never_advance_the_world_rng
  interleaves particle verbs with real rand() draws over 32 rounds and
  asserts both the RNG state and the drawn stream are identical
- game.sfx_at with listener-relative gain/pan and a near-field ease so a
  sound at your feet doesn't flip channels; 2D verbs unchanged
- apps/arcade/BUDGETS.md: measured particle/sim costs, Quest columns marked
  as estimates (the real particle limit is fill rate, not CPU)

Tape probe BYTE_IDENTICAL. Not done: arcade has no audio backend, so
positional sound is implemented and tested but not audible there yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 03:27:09 +02:00
Admin
5817c6b0de Migrate gamemaker onto game_script: -2647 lines, tape still byte-identical
game_view.rs 4525 -> 1878. Deleted in one marker-verified cut: the 84-arm
game_dispatch chain, all arg/option/value helpers, spawn_entity/spawn_terrain
/spawn_car/spawn_plane/spawn_character/spawn_block_body/set_brain, the
GAME_API table, suggest_verb/edit_distance, and the duplicated CallbackTable.
register_game_handle now binds game_script's verb table; unknown verbs keep
the same hard-fail plus did-you-mean. Kept: run_tick and everything parity
depends on — tape input, gamepad poll, camera mailbox, perf channels, agent
RPC, save/log flush.

Rollback deliberately still gamemaker's hand-written WorldSnapshot, not
GameWorld::clone(). Clone is strictly safer and is what Arcade uses, but
eval_body is the parity-critical path and the snapshot is what the tape was
established against — swapping it deserves its own tape run, not a rider on
a 2700-line deletion.

Three pre-existing divergences fixed in game_script (sfx/beep/jingle predated
the 31-verb port and had drifted): beep's `to` defaulted to 0.0 instead of
freq, so every beep swept to silence; beep never read its wave option at all
(allowed but unused, and AudioRequest::Beep had no wave field); gain and
jingle ms were off. Audio drains host-side in run_tick and after a successful
eval so a startup jingle isn't held a frame; a failed eval discards its queue.

Regression the migration exposed: block verbs spawn through the shared box
path, which re-validated keys against the BOX allow-list, so game.car(...)
logged 8 bogus "unknown option" warnings per eval straight into the channel
the agent reads. Added spawn_entity_unchecked for the block path; a real typo
on game.box still warns. Racing fixture: 8 warnings -> 0.

Tape probe BYTE_IDENTICAL (re-run after the audio and warn changes too).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 02:43:08 +02:00
Admin
a8427cda75 Arcade M2b: multiplayer — players in the sim, tiered replication, host/join
A room of devices now plays one game: host simulates, clients send input
and render replicated truth.

- libs/game/sim/player.rs: Players roster on GameWorld, slot 0 is always
  this device. Player 0's input stays in the world's original held/pressed/
  pad/cam_yaw fields and is mirrored into the roster, which is what keeps
  single-player numerics bit-identical (tape gate confirms). Ids are never
  reused, so a stale reference resolves to None, never to somebody else
- The camera-movement knot resolved: world.player_move(p) rotates that
  player's axes by THEIR cam_yaw, carried in their input packet. Player 0's
  branch is the original expression character-for-character (the f32 cos
  widened to f64 kept deliberately — tidying it would move the numbers)
- libs/game/session/replication.rs: Shared = pos/vel/size/kind/tag;
  Derived = facing/anim/scale/glow/blob shadows, recomputed client-side and
  costing zero wire bytes; Local = camera/audio/effects. Statics never enter
  the per-tick stream
- Protocol (additive, version unchanged): EntityDesc + Descriptors message
  splits rare reliable construction data from volatile unreliable state —
  without it a joiner sees poses for entities it cannot build. EntityDesc
  carries pos because statics never appear in the state stream (the
  late-joiner test caught ground arriving at the origin)
- Script: game.players/player_name/player_entity/player_input/bot/on_join/
  on_leave; blocks gained owner: PlayerId so a car reads its own driver
- Arcade: ARCADE_HOST=1 / ARCADE_JOIN=<addr>; clients skip world
  construction and don't simulate
- Racing wire volume, 6 players x 60Hz x 200 entities: 2400 pps,
  20.9 Mbit/s up (audit projected 74 Mbit for the XR stack). Asserted in
  racing_scenario_wire_volume_fits_a_living_room

Two more not-a-playable-default bugs, same class as M1b's rng-at-zero:
Entity::default() leaves gravity_scale 0 (weightless wheels) and ground
without friction gives no traction — only the DSL path filled these in.

255 tests green; tape probe BYTE_IDENTICAL; xr/arcade/gamemaker build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 01:21:44 +02:00
Admin
c13c867547 Arcade M1b: libs/game/blocks — car/character/plane, brains, race kit; racing game in 72 lines
The thesis proof: examples/gamemaker/resources/fixtures/racing.splash is a
complete playable racing game in 72 lines (12-corner oval from a waypoint
loop, 4 cars, gates, standings, restart) with no physics, no AI and no lap
bookkeeping in script. Blocks run engine-side at 60Hz: Blocks::pre_step
(intent -> motion) before step_world, post_step after; Blocks is Clone and
snapshots beside GameWorld so a failed eval rolls both back together.

- game.car (4 suspension raycasts on a box3d rigid chassis), game.character
  (drives the existing mover sweep + owns idle/walk/run blending),
  game.plane; game.drive/autodrive/speed
- Brains: game.wander/chase/patrol/caught — the fixture's hand-rolled AI,
  absorbed engine-side
- Race kit: spawnpoint, checkpoint, place, race, standings, lap/rank/
  finished, score/score_of (Shared-tier data, ready for replication)

raycast_vehicle audit (defects documented in car.rs, still live in xr):
libm sin/cos in steering (unreplicable), a wrong side-impulse denominator
(iaj.dot(iaj) where it should be (I^-1 aJ).aJ), and an unguarded division.
Kept the structure, replaced Bullet's friction solver with an arcade force
model: suspension acts at the contact point, grip and drive through the
centre of mass, steering as yaw torque — no lateral force can generate
roll, so it is stable by construction rather than by roll_influence fudge.

Engine bug fixed at the source: GameWorld::new() left rng at 0 and
xorshift64* is a fixed point at zero, so rand() returned 0 forever for any
world built through the sim API. reset_content seeds on every eval, which
hid it from gamemaker entirely; found by a wander brain that never left home.

Tape probe byte-identical; racing fixture evals clean and drives (AI follow
the line, gates bank in order).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 00:54:22 +02:00