Commit graph

148 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
fb84574715 platform: faster builds and sturdier runs -- #[derive(Script)] emits one helper call per field, studio-protocol no longer waits for script, an app's package dir, icons and bundle name rebuild only that app, MAKEPAD=gpusim builds again, and a contained panic on macOS no longer frees the windows under AppKit
The platform part of work 5f9953350..163af41b7, as one step that builds (makepad-platform checks for macOS and wasm32):

- script: #[derive(Script)] emits one helper call per field, and ScriptNew's default methods keep their bodies out of every type
- platform: studio-protocol no longer waits for script, so platform starts ~0.5 s earlier
- platform: an app's package dir, icons and bundle name rebuild only that app
- script + wasm_bridge: no build script that reruns on every file
- 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 pick
- feedback: Send feedback, a caption icon and a small panel that shows exactly what is sent
- platform: MAKEPAD=gpusim builds again
- thiserror: RUSTC_BOOTSTRAP no longer turns on the unstable generic member access API
- platform (macos): a contained panic no longer frees the windows under AppKit or leaves an app that ignores quit

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 20:10:03 +02:00
Admin
588a19aae9 platform: Windows and macOS -- every window keeps animating with several open, half-float RGBA textures have four channels, a first-opened popup draws its rows, a texture pass before its window has a size is skipped, desktop apps open no console window, the macOS display link is kept until invalidated, and a hosted child redraws at its tile's new size
The platform part of work 90b6a0581..5f9953350, as one step that builds (makepad-platform checks for macOS and wasm32):

- sheets, score, git, home: saves cannot cut a file short or overwrite another one, and checkouts cannot write outside the repository
- git: worktree status matches git on real repositories and can be cancelled
- platform (windows): every window keeps animating with several windows open
- audio_route: one API on macOS, Windows and Linux, monitoring by default and processing only when asked, plus shaders that discard a value compile to WGSL
- platform, widgets, ai: a restyle recompiles nothing it already has, shows only complete frames, and a window can own its caption
- platform (windows): half-float RGBA textures have four channels
- platform (macos): the display link is kept until it is invalidated
- windows: desktop apps open no console window, and still speak through pipes
- ai: Claude Desktop drives any app with the F10 panel
- wm: starts on Windows
- platform (windows): a popup opened for the first time draws its rows
- platform + wm: a hosted child redraws at its tile's new size
- platform (windows): a texture pass drawn before its window has a size is skipped, not a crash

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 20:09:39 +02:00
Admin
d7ae76ae92 platform: hosted apps on Android -- every app its own process under the WM, frames handed over with GPU fences, a touch that is taken away is cancelled, hosted children ask the WM for what they cannot do, window crossfades and whole-frame presents, relief-lit textures
The platform part of work 6941c0e86..90b6a0581, as one step that builds (makepad-platform checks for macOS and wasm32):

- platform, widgets, wm: a touch that is taken away is cancelled, never released
- wm on Android: every app is its own process
- platform, wm: hosted apps ask the WM for what they cannot do themselves
- 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
- vulkan (android): a window released on suspend is not released again
- android: hosted children hand frames over with GPU fences and draw only when they have work
- wm on Android: the shell follows the Pixel launcher's motion
- 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 Dock app bu
- git: timings read a portable clock
- 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, and the AI
- platform: Android builds without Vulkan compile again, and the font-selection test counts the hosted entry point
- platform: the pipeline-skip repaint mark exists only on Apple, where Metal reads it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 20:09:17 +02:00
Admin
01a1c70b76 script: the Octoscript VM hardening -- execution caps, fuel and deadlines, heap/string/array/object limits, parser diagnostics and re-entrant dispatch, keeping a Makepad host's semantics and speed
The platform part of work 76627b6f1..6941c0e86, as one step that builds (makepad-platform checks for macOS and wasm32):

- script: re-entrant dispatch, thread index validation, Any-based handle downcasts, UTF-8 previews; regex: never_loop fix
- script: port Octoscript WS1 — worklist equality with fuel/deadline/work bail, uncaught-error bail, allow_debug_output
- script: port Octoscript parser/tokenizer/control-flow VM patches (ws2)
- script: port Octoscript heap/string/array/object hardening onto upstream's allocation budget
- script: port orphaned Octoscript VM hardening (execution caps, clear_type_methods, parser diagnostics)
- script: keep silenced streaming evals running past uncaught errors
- script: the Octoscript hardening keeps a Makepad host's semantics and its speed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 20:08:33 +02:00
Admin
a185b868d1 platform: GPU passes store top-left rows on every backend, hosted apps get software frames as textures, the Android desk renders at 120 Hz, and the platform builds warning-free on every CI target
The platform part of work 6f1e44649..76627b6f1, as one step that builds (makepad-platform checks for macOS and wasm32):

- 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 whatever
- platform: the Android desk swipes at 120 Hz — offscreen render passes and framebuffers cached, SVG meshes kept, font families that complete
- ai stems: LaneDemixer, VocalsModel and the platform Stage origin/main needs
- platform, widgets, wm: every Vulkan pass renders through a negative-height viewport again, so a Wayland or X11 window stands upright, and no capture consumer
- platform: every OpenGL texture pass stores top-left rows, custom cameras included, and culls with the winding its inverted projection gives
- 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 all
- The regex engine accepts \b and \B, reports the earliest match so a scan can resume after it, and can decide word boundaries on ASCII so a code search never f
- 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
- stitch: the crate says what the rest of the repository says about its license
- platform: no warnings on tvOS and linux_direct, and a missing pty helper says so
- tests: the workspace suite, run as a whole for the first time, passes outside the example UI tests
- platform: a hidden window wears no hands-off frame
- libs: no warnings in the workspace check on any row
- tools: makepad-screen is makepad-agents, and its binary is `agents`
- platform: the storage module says how much a volume has free
- git: the memory ledger can take what it is asked for
- ci: a driven app takes every key once, and the storage module builds for the browser

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 20:08:13 +02:00
b211a372d9 fix(fork): base platform+test on upstream work 5f99533 + re-apply nigig BeforeStartup, NIGIG_TEST_MODE, touch protocol 2026-09-25 23:19:08 +03:00
8eaa075f1f fix(fork): refresh platform from upstream dev fda40f5 + re-apply nigig BeforeStartup, NIGIG_TEST_MODE, touch/long-press/paste/IME protocol 2026-09-25 22:55:32 +03: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
b6a99cb381 wm: starts on Windows -- the desk no longer overflows the 1 MB main stack
wm.exe died at startup with "thread 'main' has overflowed its stack"
(0xc00000fd) on Windows, where the main thread gets 1 MB against 8 MB on
macOS and Linux. The startup chain is shallow (~85 frames) but five of its
frames were huge: ShellIcons (41 DrawSvg, ~110 KB) sat by value in every
ShellDraw, PhoneSurface carries one ShellDraw and WmDesk carries a
PhoneSurface plus its own ShellDraw (286 KB). Each constructor layer
(WmDesk factory, WmDesk::script_new, PhoneSurface::script_new and
script_new_with_default, ShellDraw) held its whole value in its frame:
about 970 KB in five frames. Reproduced on macOS by linking wm with a
1 MB main stack (same overflow).

script gets a transparent Box<T> (ScriptNew/ScriptApply/ScriptHook forward
to T: same type id, proto, default and apply), and ShellDraw boxes its
icons. The same chain now takes ~305 KB (WmDesk 286 -> 69 KB, PhoneSurface
140 -> 30 KB, ShellDraw 117 -> 7 KB); the 1 MB-stack build starts and runs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 01:13:29 +02:00
Kevin Boos
03705413e7
Constrain Splash external I/O to the host service bridge (#1243)
* Constrain Splash external I/O to the host service bridge

* Validate untrusted Splash source with the host I/O restriction

* Give strict Splash validation a disposable storage jail

* Close the remaining ways out of the Splash host I/O restriction

- Keep CachedWidget singletons per heap, and don't register CachedWidget
  or WindowMenu in restricted isolates.
- Don't emit Html/Markdown link URLs as actions from a restricted isolate,
  and ignore its menu bar updates.
- Suppress clipboard copy/cut hits for any restricted isolate, not only
  within Splash.
- Give script calls made while an isolate is installed the same budget.
- On web, let package resource fetches skip the guest I/O guard.
- Name the validation jail without the wall clock, and skip it on wasm.
- Make the host I/O tests fail when their guards are removed.
2026-09-25 00:56:09 +02:00
Admin
6b6fbf003b platform, widgets, ai: a restyle recompiles nothing it already has, shows only complete frames, and a window can own its caption -- generated shader helpers were named after their module's heap position, which moves on every restyle, so the Metal source text changed and every style switch recompiled ~20 pipelines, even back to a loaded style; helpers are now numbered by first call order within the shader, so a warm switch compiles 0 and misses 0 draws (was 47 missing per frame for 0.5 s). A style switch holds the old frame until three frames in a row are complete (no draw skipped, no pipeline pending), then crossfades; cx.pipelines_pending() and per-reason skipped-draw counts back it. A window can hide its stock caption and name its own drag region (set_drag_region), enforced on every event and draw so no re-apply brings the stock bar back; app keys in that region answer the drag query as client. The audio analyzer keeps a stereo history (latest_stereo). The AI engine runs a CLI model's tool calls as they stream in and shows the text between them
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 18:47:36 +02:00
Admin
5986d4f8ee audio_route: one API on macOS, Windows and Linux, monitoring by default and processing only when asked, plus shaders that discard a value compile to WGSL
audio_route: the Core Audio process tap gains Windows (WASAPI process loopback; the source is ducked through its ISimpleAudioVolume) and Linux (the PulseAudio/PipeWire monitor of the source's sink; ducked through its stream volume) backends behind the same Route API. A route only monitors by default (copy for meters and visualisers; the app's own output is untouched). Route::set_processing turns processing on: the source is ducked to 2^-13 and boosted back by exactly 2^13 in float, so the processed signal is bit-exact. RouteConfig.state_dir keeps the duck state, so restore_after_crash puts a ducked volume back after a crash.

script/wgsl: an if/else whose branches end in a value nothing uses wrote that value as a bare statement (_phi_353;). Metal, GLSL and HLSL accept that, WGSL does not, so DrawMenuRow failed on Vulkan and menu rows lost their drawing (the theme chips on Linux). ShaderBackend::write_discarded_expr writes such values as `_ = expr;` for WGSL and keeps void calls as statements, in both places that emit leftovers. MAKEPAD_TRACE=shader.wgsl lifts the two-error log suppression.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 18:45:23 +02:00
Admin
d15996efd9 task, cargo-makepad, widgets, audio: the task manager chooses its columns, graphs every process' network and disk traffic and installs itself as a Dock app built by cargo makepad -- cargo makepad desktop bundle -p <crate> [--install[=DIR]] builds a self-contained, signed macOS .app (MAKEPAD_PACKAGE_DIR=resources in its own target dir, every dependency's resources plus only the fonts the binary's manifest names, icon from [package.metadata.makepad.desktop], per-app usage strings, signed with the Apple Development identity so privacy grants survive rebuilds) and installs it outside target/ (default ~/.makepad/apps), replacing the per-app package-macos.sh scripts
- task: a right-click column chooser (sections as flyouts, Default Columns), every figure and graph its own sortable column, dragged order and widths saved; per-process network bytes/packets from the kernel's ntstat control socket (matches nettop, no root), disk bytes, footprint and idle wake-ups every tick; history journal v4
- widgets: data_grid_columns, one column helper (chooser, reorder, resize, fit, sort cycle, layout text) that task uses and other tables can reuse; the menu engine refreshes marks inside an open flyout; the segmented control centres its labels on the line height and no longer glides after a moved row
- svg: a stroke join never connects to the previous subpath (the diagonal through outline icons)
- platform: home::app_data_dir; script: ScriptIp body ids widened to 14 bits (16384 bodies, was 4096) with an index of 26 bits, and a clear stop instead of aliasing past the limit
- audio_route (new): tap an app's audio output through the Core Audio process tap into a host processor (equalizer, gain, limiter, analyzer) and play it; audio_picture owns the one FFT; audio_decode probes tags and length from a file's head and tail; search::fold_words; zip_file reads archives with a trailing comment

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 22:34:45 +02:00
Admin
6941c0e86b script: the Octoscript hardening keeps a Makepad host's semantics and its speed -- an uncaught error ends an evaluation only when the host sets bail_on_uncaught_error, so by default a module keeps evaluating past one bad statement and scripts can inspect returned error values; an error raised while no script ran is reported at the Rust->script boundary instead of ending, or being caught by, the next run; cross-call try unwinding stops at the nearest root frame, so an error inside a native's callback (array.retain) never pops frames an outer run_core still executes; the equality work ceiling applies to bounded evaluations only and a scalar == allocates nothing; run_core keeps its cached opcode pointer, invalidated by an epoch every bodies.borrow_mut() advances; take_allocation_error and charge_allocation are one flag read when nothing is limited, cast_to_f64 keeps its number path inlinable and checked_index is one round-trip compare
splash_bench geomean against work, best of alternating runs: +12.9% with the series as submitted (the per-instruction Option<String>::take in take_allocation_error alone was +9.8%), -1.1% with this commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:34:43 +02:00
ymote
a4c31be0b5 script: keep silenced streaming evals running past uncaught errors
The ws1 equality/fuel port made an uncaught script error Bail the whole
evaluation (vendor semantics). Splash's incremental eval_with_append_source
sets silence_errors because incomplete source inevitably raises errors that
are meaningless until the rest arrives, and its live widget tree relies on
evaluation continuing past them; with the Bail, `field := TextInput{...}`
never produced its child and
splash::style_tests::embedded_splash_restyles_its_isolate_without_replacing_edits
regressed (bisected to vm-port/ws1-equality-fuel alone).

Gate the Bail on !silence_errors: streaming evals keep drain-and-continue,
every other eval (including Octoscript's captured-sink evals) terminates on
the first uncaught error. Regression test added in vm.rs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit a4347332b38d0d511287006dc19f0c079604f78a)
(cherry picked from commit 6ee2aecfcb7d9296b501be5ea481caef1a4d024a)
2026-09-23 22:34:43 +02:00
ymote
ba33084d9c script: port orphaned Octoscript VM hardening (execution caps, clear_type_methods, parser diagnostics)
Items no workstream branch owned, ported from the Octoscript vendor tree:

- Operand-stack and call-frame caps: ScriptVm::with_stack_value_limit,
  with_call_frame_limit, clear_execution_limit_failures; ScriptThread
  call_frame_limit / *_limit_exceeded flags, push_call_frame,
  has_execution_limit_exceeded; run_core, CALL_EXEC/RETURN/RETURN_IF_ERR
  and handle_return skip pop_to_me and raise an uncatchable
  "script operand stack limit exceeded" / "script call frame limit
  exceeded" bail. The root evaluation frame counts toward the cap.
- ScriptNative::clear_type_methods for restricted embeddings.
- ScriptParser structured diagnostics: ScriptParserDiagnostic,
  MAX_PARSER_DIAGNOSTICS, diagnostics()/diagnostics_truncated(),
  set_emit_errors(); the existing parse_errors sink is kept in lockstep.

Tests: tests/execution_limits.rs, vm.rs
return_does_not_pop_to_me_after_an_operand_stack_limit, parser.rs
diagnostics_* tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit bfa4087b59abf64d30c385bea53120e0adf2f64b)
(cherry picked from commit 6a349506dd58b4f150dfa12f447385def3f1f469)
2026-09-23 22:34:43 +02:00
ymote
1f481016f4 script: port Octoscript heap/string/array/object hardening onto upstream's allocation budget
Workstream 3 of the Octoscript VM patch port (heap, strings, arrays, objects).

- Array opcode reads and writes validate the index (finite, non-negative,
  integral, representable) before touching storage: ScriptValue::checked_index
  and ScriptVm::checked_array_index, applied at every array/pod index site in
  opcodes_vars.rs and opcodes_assign.rs.
- Updating an existing untracked object field keeps its insertion order
  (ScriptObjectData::map_insert), matching the tracked path.
- Numeric string conversion handles inline and heap strings alike and yields
  a traced NaN for text that is not a number (ScriptHeap::cast_to_f64).
- Heap accounting: Octoscript's retained-heap cap is expressed over upstream's
  ScriptAllocationBudget instead of a second parallel accounting system. A
  persistent budget (heap_cap) is charged by the same charge_allocation calls
  as the scoped with_heap_allocation_limit budget, its headroom re-derived
  from a retained-capacity estimate by reconcile_heap_bytes (setup, GC sweep,
  shrink_to_fit, host boundaries). Public API preserved for octoscript-core:
  set_max_heap_bytes / max_heap_bytes / accounted_heap_bytes /
  reconcile_heap_bytes / take_heap_limit_exceeded. Refusals surface through
  take_allocation_error, so run_core bails uncatchably as before.
- Per-string ceiling: set_max_string_bytes / max_string_bytes /
  take_string_limit_exceeded, enforced on exact lengths at the store choke
  points (new_string_from_str, new_string_concat, intern_or_store_string and
  its preflighted variant, check_intern_string), plus ScriptStringSink,
  ScriptStringBuffer, new_bounded_string_with and temp_bounded_string_with
  (bounded by the string ceiling and the remaining allocation budget) for
  hosts that build strings incrementally. cast_to_string is generic over the
  sink. Byte-array parse_json builds its lossy text through the bounded buffer.
- Pod creation is charged; ValueMap/ScriptArrayStorage/ScriptObjectData expose
  retained_bytes for the estimate.

Retired in favor of upstream: per-path capacity preflights in array_heap.rs /
object_heap.rs (charge_allocation already meters sparse growth), the sink
generalization of to_json/percent/regex builders (upstream preflights exact
lengths), array_mut_with in vec_prims.rs (host conversions are covered by
reconcile_heap_bytes at the host boundary).

Tests: invalid index reads/writes leave storage untouched, numeric conversion
variants, insertion order, capped sparse growth (array, object vec, object
map) refused before mutation, string ceiling at the store paths and in the
bounded buffer, byte-array to_string/parse_json limits, lossy UTF-8 parity,
scoped budget nesting inside the cap.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit ce4bbe5980f38fd0206f06fe27568528bd49a394)
(cherry picked from commit b21de9ff271d523f52b6154df3c7ef84048772d7)
2026-09-23 22:34:43 +02:00
ymote
2f9565e08a script: port Octoscript parser/tokenizer/control-flow VM patches (ws2)
Ports the parser, tokenizer and control-flow part of the Octoscript
makepad-script patch set (PATCHES.md, grammar v0.2) onto the September
`work` revision, by hand, area by area.

Decisions per PATCHES.md item:

1. Logical/comparison precedence, streaming, `!`: ADAPT. Upstream already
   patches a pending ShortCircuitEnd during auto-close but forgot the
   operator: ShortCircuitEnd now retains `what_op` so a tighter logical
   operator keeps a looser left jump open (`a || b && c`), the checkpoint
   restores the original TEST opcodes on continuation, comparisons (14)
   bind tighter than equality (15), and NOT always negates truth
   conversion instead of doing a bitwise NOT on f64-stored numbers.
   Upstream's `last_jump_target` bookkeeping is kept at every patch site.
2. Canonical `try protected catch fallback`: PORT. `catch` is a one-shot
   contextual separator carried in TryErrBlockOrExpr checkpoint state
   (allow_catch/canonical_catch/protected_was_block); block branches keep
   their tail value by removing the inherited pop-to-me marker before
   recomputing the jump; TRY_ERR now uses its encoded relative distance
   and the parser adds the extra TRY_OK skip only when legacy `ok`
   follows. Legacy catch-less `try a b [ok c]` still parses (the checker
   in Octoscript's own crates restricts it to the compatibility entry).
3. Cross-call unwinding: PORT. handle_errors searches all call frames
   (call_stack_has_try), pops younger script calls restoring slot_base
   and the return ip's body, then applies the try-frame cleanup/jump.
   Hard bails stay on ScriptTrapOn::Bail.
4. Loop back-edges: ADAPT onto upstream's reset_iteration_scope fast
   path: truncate_loop_iteration_bases discards iteration-local tries,
   operand values and mes before the scope reset; plain loop/while keep
   their iteration scope and free nested ones. Hard time-budget bails
   drain their diagnostic; OK_END with no try frame bails.
5. Field-assignment reverse-pair walk: PORT (stop at a 1-opcode chunk).
6. Prototype-field `:` rewrite: PORT (chain must begin with an id,
   paired insert through insert_code_with_source keeps opcode/source-map
   lockstep); unavailable rust-value index is a parse error.
7. Numeric-boundary tokenizer: PORT (`_` stays in the pending number
   instead of moving to Whitespace with stale text) plus the char-count
   token length so a multibyte identifier cannot underflow `pos`.

Tests: inline parser/tokenizer/vm regressions and tests/try_catch.rs
(legacy syntax, block/expression branches, nested and cross-function
recovery, contextual `catch`, checkpoint restoration, loop cleanup,
streaming appends, precedence and effects, tokenizer boundaries).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit 8231a13906cfb339b496ff78b687e43a48e4e11b)
(cherry picked from commit a1f7afb543c8a737f9c56936bfcba605097f88df)
2026-09-23 22:34:43 +02:00
ymote
4a00885f26 script: port Octoscript WS1 — worklist equality with fuel/deadline/work bail, uncaught-error bail, allow_debug_output
Port of the equality / fuel / error-bail slice of Octoscript's makepad-script
patch set onto the September `work` base.

equality (PORT, string compare ADAPTED): `deep_eq` moves from heap.rs into
the new equality.rs as an iterative worklist that visits each container pair
once (cycles and shared DAGs terminate), keeps NaN unequal to itself, and
charges one work unit per processed pair, queued edge and typed-array
element, capped by MAX_EQUALITY_WORK = 65,536 per comparison. Upstream's
69d78873e string early-out is kept instead of the patch's chunked byte
compare: every heap string is interned (string_heap.rs) and short strings
are inline, so string equality is exactly bit equality and a string pair
costs one unit. The raw host `ScriptHeap::deep_eq` is iterative and
unbounded and consumes no VM fuel. The `==`/`!=` opcodes go through
`deep_eq_bounded`: each unit charges one instruction of
`instruction_limit_remaining`, the hard deadline (now an f64 on the
platform clock) is sampled every 256 units so trivial comparisons never
touch the clock, and exhaustion drains diagnostics and raises an
uncatchable Bail, like the instruction limit.

uncaught errors (PORT): `handle_errors` without an active try frame drains
the diagnostic once and sets `ScriptTrapOn::Bail(error)`, so no later
instruction or host effect runs and `eval` returns the error value; active
`try` handlers recover exactly as before. The hard time-budget bail drains
its diagnostic before unwinding, as the instruction-limit bail already did.

allow_debug_output (PORT): new host-controlled `ScriptVmBase` flag,
default true so raw makepad debugging is unchanged. When false the `~` LOG
opcode raises a catchable not-allowed error and `ScriptVm::log` is a no-op.
Incidental VM prints are removed: run_core's `log!` traces, the undefined
opcode `eprintln!` (now a bail) and the loop "unknown state" `println!`
(now a bail). mod_std.rs needs no change: std.log already routes through
the gated `ScriptVm::log`.

Tests: platform/script/tests/equality_fuel_bail.rs covers cycles, shared
DAGs, NaN, string/number semantics, the host deep_eq on typed arrays and
beyond the ceiling, instruction fuel charging, the work ceiling being
uncatchable, the in-comparison hard-deadline check, the hard-budget drain,
uncaught-error bail with try recovery, and the debug-output flag.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit a44f8678ed68b20a0c413d607c07a37d55186fbe)
(cherry picked from commit 353fa369faa5672e075dd874a431dc928420bafb)
2026-09-23 22:34:43 +02:00
ymote
6c3414f087 script: re-entrant dispatch, thread index validation, Any-based handle downcasts, UTF-8 previews; regex: never_loop fix
Port of Octoscript's re-entrancy and hardening items onto the new VM host contract.

- vm.rs: run_core no longer caches a raw pointer into the active body's opcode
  vector across native calls. Each opcode is copied through a scoped
  `bodies.borrow()` that ends before dispatch, so a native handler that
  re-enters `eval` and replaces the body's parser cannot leave a dangling
  pointer. Regression: reentrant_reload_of_the_active_body_does_not_keep_an_opcode_pointer.
- thread.rs: ScriptThreads::set_current validates the index before updating
  the cached pointer (set_current_thread_id routes through it); update_ptr is
  bounds-checked via get_mut; cur/cur_ref/trap use release-mode assert!.
  Regressions: selecting_an_unknown_current_thread_panics_before_pointer_update,
  empty_threads_reject_current_access_in_release_builds.
- handle.rs: ScriptHandleGc: Any; is/downcast_ref/downcast_mut compare
  Any::type_id, removing the overridable ref_cast_type_id hook.
  Regression: handle_downcasts_use_the_concrete_any_type.
- suggest.rs: value previews truncate at character boundaries.
  Regression: preview_truncation_preserves_utf8_boundaries.
- libs/regex utf8.rs: iterator entry uses `self.range_stack.pop()?` instead of
  a never-advancing `while let`, replacing upstream's #[allow(clippy::never_loop)].

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgSir4cQyaakzPju4h6smw
(cherry picked from commit ee7729e71c1408f61ec8f9083a79bdf9117d31a7)
(cherry picked from commit cdbc33e8ac1683fcdeb6e9dcb076e26ce5d23360)
2026-09-23 22:34:43 +02:00
Admin
86cd0604ef libs: no warnings in the workspace check on any row -- the CI box checks every package on every target, and the library crates, which have no tile of their own, warned on the rows nobody builds by hand. On wasm and mobile, things are gated with their users: the workspace document worker (its commands, payloads, retry constants and Drop are native; the wasm API stays, behind an uninhabited worker whose constructors answer that the browser has no document worker), the hub's unused non-Unix available_bytes and its ram facts parser, the loader's ArenaPtr, system_speech's bcp47. On the tvOS rows, the only ones built on nightly, the legacy numeric constants and functions become the associated constants they have been since Rust 1.43 (micro_serde, bytemuck, rustybuzz, unicode-script, smallvec, weezl); fetch_update keeps its name under allow(deprecated) in stitch, git and the map archive, since try_update does not exist on older stable toolchains; objc-sys declares free with the signature the standard library uses; rustybuzz calls its own method through a path that a future std method of the same name cannot shadow; and the Script derive's unused helper attribute splat, which nightly now reserves as a built-in, is spelled script_splat (nothing in makepad, Scope or Stage uses it)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 00:02:28 +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
Admin
ab08812892 The regex engine accepts \b and \B, reports the earliest match so a scan can resume after it, and can decide word boundaries on ASCII so a code search never falls back to the slow NFA on non-ASCII text
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 01:39:51 +02:00
Admin
a4ea2536a4 platform: topic hunks the per-commit assembly could not place, the Sep 2–15 dev PRs (#1208–#1236) as adapted to this tree, and the zero-warning chore
code_editor/Cargo.toml                          |     1 -
 code_editor/src/lib.rs                          |     3 -
 draw/src/cx_2d.rs                               |    83 +
 draw/src/cx_draw.rs                             |    43 +
 draw/src/draw_list_2d.rs                        |    22 +
 draw/src/geometry/geometry_gen.rs               |     7 +-
 draw/src/image_cache.rs                         |    51 +-
 draw/src/lib.rs                                 |     1 -
 draw/src/shader/draw_text.rs                    |    40 +-
 draw/src/shader/mod.rs                          |     1 -
 draw/src/text/fonts.rs                          |     2 +-
 draw/src/text/mod.rs                            |     1 -
 draw/src/text/slug_atlas.rs                     |     2 +-
 draw/src/turtle.rs                              |  3469 ++++-
 draw/src/vector/triangulate.rs                  |   378 +-
 libs/error_log/src/lib.rs                       |    17 +-
 platform/network/src/backend.rs                 |     6 +
 platform/network/src/backend/apple/http.rs      |     2 +-
 platform/network/src/http_server.rs             |    15 +-
 platform/script/derive/src/derive_scriptable.rs |    19 +-
 platform/script/src/lib.rs                      |     4 +
 platform/script/src/shader_calls.rs             |    92 +-
 platform/script/src/shader_hlsl.rs              |     9 +-
 platform/script/src/shader_metal.rs             |    18 +-
 platform/script/src/shader_wgsl.rs              |    12 +-
 platform/script/tests/hook_scope.rs             |     8 +-
 platform/src/action.rs                          |    12 +-
 platform/src/app_main.rs                        |   110 +-
 platform/src/cx.rs                              |   466 +-
 platform/src/cx_api.rs                          |   368 +-
 platform/src/draw_list.rs                       |  2598 +++-
 platform/src/draw_pass.rs                       |    35 +-
 platform/src/draw_vars.rs                       |   103 +-
 platform/src/geometry.rs                        |   588 +-
 platform/src/gpu_texture.rs                     |     2 +-
 platform/src/id_pool.rs                         |    71 +-
 platform/src/lib.rs                             |    26 +-
 platform/src/log.rs                             |   111 +-
 platform/src/os/apple/apple_game_input.rs       |     6 +
 platform/src/os/apple/apple_sys.rs              |     1 +
 platform/src/os/apple/macos/macos_app.rs        |   384 +-
 platform/src/os/apple/metal.rs                  |  3347 +++-
 platform/src/os/cx_native.rs                    |     5 +-
 platform/src/os/cx_shared.rs                    |   202 +-
 platform/src/os/gpusim/event_loop.rs            |    24 +-
 platform/src/os/gpusim/mod.rs                   |     8 +
 platform/src/os/gpusim/raster.rs                |    11 +
 platform/src/os/linux/opengl.rs                 |   856 +-
 platform/src/os/linux/vulkan.rs                 |   752 +-
 platform/src/os/linux/vulkan_linux.rs           |     4 -
 platform/src/os/linux/wayland/linux_wayland.rs  |    15 +-
 platform/src/os/linux/wayland/opengl_wayland.rs |    67 +-
 platform/src/os/linux/wayland/wayland_state.rs  |    37 +-
 platform/src/os/web/web.js                      |  1409 +-
 platform/src/os/web/web.rs                      |   212 +-
 platform/src/os/web/web_gl.rs                   |   284 +-
 platform/src/os/web/web_worker.js               |    76 +-
 platform/src/os/windows/d3d11.rs                |  1323 +-
 platform/src/remote.rs                          |  1297 +-
 platform/src/retained_instances.rs              |     3 -
 platform/src/script/res.rs                      |   245 +-
 platform/src/sploded.rs                         |    59 +-
 platform/src/texture.rs                         |   416 +-
 platform/src/thread.rs                          |  2816 +++-
 platform/src/thread/ui_hang/linux.rs            |     2 +-
 platform/src/thread/ui_hang/macos.rs            |    22 +-
 platform/src/thread/ui_hang/native.rs           |     3 +
 platform/src/thread/ui_hang/windows.rs          |     2 +-
 platform/src/web_socket.rs                      |    45 +-
 platform/src/window.rs                          |   129 +-
 platform/tests/texture_lifetime.rs              |   143 +-
 platform/video/src/stream_debug.rs              |     2 +-
 platform/video/tests/stream_codec.rs            |    85 +-
 widgets/derive_widget/src/derive_widget.rs      |     4 +-
 widgets/src/animator.rs                         |   138 +-
 widgets/src/combo_box.rs                        |    10 +
 widgets/src/desktop_style.rs                    |     4 +-
 widgets/src/drop_down.rs                        |    96 +
 widgets/src/font_policy.rs                      |    25 +
 widgets/src/grid.rs                             |     1 +
 widgets/src/image.rs                            |     3 +
 widgets/src/lib.rs                              |    18 +-
 widgets/src/map/archive.rs                      |   544 +-
 widgets/src/map/geometry.rs                     |    34 +-
 widgets/src/map/label.rs                        |    48 +-
 widgets/src/map/tile.rs                         |  6890 ++++++---
 widgets/src/map/tile_draw.rs                    |     2 -
 widgets/src/map/view.rs                         | 17896 ++++++++++++++--------
 widgets/src/menu_bar.rs                         |    18 +-
 widgets/src/screen_cap.rs                       |   513 +-
 widgets/src/slider.rs                           |     6 +
 widgets/src/splash.rs                           |   280 +-
 widgets/src/tweaker.rs                          |   221 +-
 widgets/src/view.rs                             |   105 +-
 widgets/src/widget.rs                           |     5 +-
 widgets/src/widget_async.rs                     |   269 +-
 widgets/src/window.rs                           |   601 +-
 widgets/src/window_voice_input.rs               |    17 +-
 98 files changed, 38159 insertions(+), 12677 deletions(-)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:40:33 +02:00
Admin
4945f1873b platform: rename the CPU simulated-GPU backend from headless to gpusim
Squash of 1 work commits (Sep 12–12):
  e74b919  platform: the CPU simulated-GPU backend is `gpusim` — the word "headless" now means only window-less

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:40:28 +02:00
Admin
b53ea0b30a platform: macOS display-link, App Nap, waker, IME-adjacent event loop
Squash of 2 work commits (Sep 9–12):
  8d851ef  platform: per-draw alpha blend, macOS waker, texture lifetime, file drop
  cc2fa8f  platform: the Metal display link is gone; the hang line prints its tick deficit; hidden instances refuse App Nap

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:40:24 +02:00
Admin
2e27ce2ff1 platform: retained draw lists, shared publications and GPU residency (DL-0..DL-5)
Squash of 27 work commits (Sep 3–12):
  aa907ca  platform: a frame trace on both desktop backends, and a window that cannot present stops ticking at 600 Hz
  e3abf4d  map: the hosted-tile cache keeps the same ~2x-visible margin as the local one — a budget pinned at the visible set evicted the trailing edge of every pan on the next frame and refetched it a moment later
  8d542fe  platform: a child pass orphaned by its attaching draw list is no longer painted — the window's gauss_scene pass stayed a live_with_parent child after the map went flat and re-encoded a frozen 400-item list every pan frame with stale geometry ids (new tile meshes × old instance counts, tens of millions of triangles into a texture nobody read); make_child_pass records the recording list + redraw id, stale passes are skipped, a cached View re-attaches on a cache hit; tests for the orphan gate and the pool generation contract
  bb49fe6  map + platform: retained per-tile draw lists — each resident tile owns one DrawList2d per carto pass (fill, casing, stroke, icon, icon-high, shadow) and the label glyph batches are retained the same way, recorded when the bake, LOD ring, fringe/icon gates, flat/tilted or clip change and re-attached otherwise; a pan/zoom/tilt frame pushes this frame's uniforms onto the retained calls (DrawVars::update_uniforms_on_area, resolved slot table) and uploads zero instance bytes; the tilted per-pass depth is a pass_depth uniform; a held list's zbias resolves at entry (zbias_hold in every backend); the shimmer heartbeat patches shiny_time in place without a redraw; a freed/reused sub-list id is skipped by every draw-tree walker and the mask list re-records empty on the flat transition (contract test). Web pan tail 1,098 → 20 MiB/s, flat pan 2.4 → 0.43 MiB/frame; Metal grabs within the run-to-run noise floor
  313265d  Studio code atlas: geometry code views, live filter, 3D size lens, lanes as terminals
  9c4e0cc  Studio code atlas: performance round — retained uploads, worker labels, exact search, no forks
  7235d7e  Studio code atlas: stall fix, GPU working set, lens hard switch, filter masks, parallel index
  56a6da5  platform: per-pass GPU counter timing on Metal; retained publications replace in place
  72e2443  platform: present-path trace (1 Hz cause histograms), bounded drawable wait and retirement on macOS
  1c5d583  platform: bounded retained maintenance on empty paint beats; republish actual backend debt
  edfed73  platform: retained residency high/low water and hysteresis; no distance eviction without pressure
  acab6a0  platform: critical upload class serves present-blocking items first; identical immediate re-records upload nothing
  906c774  platform: uniform_range on DrawVars and patch_retained_uniforms on retained draw lists
  c29031c  platform/draw/widgets: heap-keyed script resources and RecordingBuffer draw items — the files today's commits depend on
  cd0964f  platform headless: homogeneous near-plane clipping before the perspective divide
  61d424d  platform: release retained bindings of released textures so pool evictions complete
  a00287a  platform: texture-tile cache support — per-item instance ranges, painted pass receipts, display-dpi pass uniform, retained render targets, present gate on the drawable pool
  74b63be  platform: retained upload floor reverted, unconfirmed presents counted
  c03fcc5  platform: tile-cache round 3 support — O(1) demand on re-recorded lists, evictions counter, allocated_size, lost-button release, Vec2d::round
  e515d75  platform: shared instance publications — the DL-0/DL-1 contract, additive beside the retained path
  142a337  platform: shared instance publications — close the seven review items (DL-1b)
  6811a19  platform: Debug for SharedInstances, WeakSharedInstances and PublishReceipt
  c061e47  platform: Metal draws are resident by construction — the hole path and its gates are gone (DL-2)
  0bdbb29  platform: drop the unreachable InstancesNotResident present cause
  de3c868  platform: `drawlist` trace names the holder of a stale draw-list id; the per-frame upload line moves to `gpu.upload`
  721c3d8  platform: publication backends — Metal per-publication backings, lease-keyed uniform ring, receipts on every backend, Vulkan draws attached items (DL-3)
  393de54  platform: integrated deletion — the draw-list system is generic again (DL-5)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:40:23 +02:00
Admin
9580527fdd platform: Linux hosted GPU, Vulkan, OpenGL, Wayland/X11/direct
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>
2026-09-15 13:39:56 +02:00
Admin
bb5de43918 script: Splash VM host contract and script_mod apply
Squash of 2 work commits (Sep 2–2):
  a6d0338  widgets: popup menu items run in the popup owner's script VM; app_main! releases its borrow after a trap
  232909d  script: the VM reaches std and its slot through one host — no aliased references

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:39:47 +02:00
Admin
61b0e5e791 platform: network crate, web-server HTTP, native body cap
Squash of 10 work commits (Sep 2–12):
  9633ded  web server: site static serving plus the first nav backends
  ba1010d  asset-client: review fixes — additive web feature, shared transport contract, guarded cache and base URL
  81ef71c  network: native backends honour the response body cap
  4d75e65  web server: hardening after security review — worker-only parsing, FD-relative static opens, strict framing, bounded work, panic recovery, Cloudflare-aware limits
  dfe2087  web-server: O(1) report admission, one connection deadline, shared route sampler, static fallbacks, cache policy
  9c9c72b  web-server: bodies land before workers, client keys normalized, verbs fail closed
  6c32c88  web-server: ETags from size and mtime, deadlines from size, Allow per resource
  7613f3e  web-server: one deadline per response from its size, 404 before 405 for unknown API paths, one Earth radius
  7deb052  web-server: ETags from size and mtime, never from content; upgrades only where a socket route exists
  f407342  libs, network: in-tree shims replace crates.io libc/log in the Wayland and zune crates; deterministic math; the websocket flushes control messages at once

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:39:44 +02:00
Admin
906f94a949 platform: thread pool, clocks, storage, trace, game input
Squash of 10 work commits (Sep 2–12):
  3389475  trace: one switch — MAKEPAD_TRACE=<topics>, trace!(topic, …), and /trace on the bridge
  c55a315  platform: monotonic clock beside the wall clock, trap-safe dispatch, studio worker only with a studio
  89fe453  platform: wheels and flight sticks are game inputs, with an output-report handle
  e5d37e0  platform: a web file picker and file drop that hand apps bytes
  19cf377  platform: the thread runtime contract — spawner, tasks, pools, scheduler, UI waker
  cf2b8ca  platform: no std::time on web — clippy guard and the platform clock everywhere a web build runs
  c527cd8  vj: the web thumbnail pipeline never blocks the main thread
  2a064d3  workspace: add loader, haptics, voice, and runtime fixes
  541c886  platform: name heavy pool jobs over 250 ms; headless Startup sent once per Cx
  d476e52  Fix Linux worker sizing and screen recording defaults

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:39:43 +02:00
Admin
573164e40c widgets/map: retained map renderer, typed streams, gestures
Squash of 39 work commits (Sep 2–3):
  ad24534  map: persistent asynchronous tile archive over a completion-based byte source
  5d28ed5  map: tile archive review fixes — legacy MBTiles path restored, decode off the UI thread, retry, cancellation, blob dedup, validation
  a7eae82  map: the tile build keeps time with the platform clock
  d931f9d  map: tile archive third pass — per-pass pruning, validated watcher metadata, shared blob bytes, timer watchdog, atomic cancellation
  4b529a1  map: tile ranges fetch once, centre-out, and never time out while queued
  04a36de  map-build: the bake produces only what the renderer reads; a bad tile is skipped and logged
  383b83e  map: the Amsterdam bake report — the real archive through the real bake path, bytes per stream and milliseconds per tile
  2d4ff16  map: POI symbols and building walls are instances — one shared mesh per symbol slot, one record per footprint edge, extruded and placed in the vertex shader
  72b60b6  map: the memory diet folded in — CPU staging freed after upload, budgets from one platform number, bakes capped by bytes in flight, per-zoom bake profiles, a memory report; instance records count as retained CPU
  a6f495d  map: street trees are instances of one template per tile; the CPU staging of every uploaded stream is dropped; the memory diet keeps its platform half only
  9047600  map: the bake report can dump the raw and decoded tiles it measured
  57995b6  map: uploaded staging is freed on a pool worker — a large free on the UI thread of the threaded web build contends the allocator lock, and a contended lock there is an Atomics.wait the main thread may not make
  02b58fc  map: ground fills on a 20-byte vertex — position, colour, variant + AA coverage, depth ticks; DrawMapFill is the fill path of the map shader
  ef25495  map: building shadows derived at draw time in a screen-space mask pass
  9d664ca  map: roads on a 32-byte vertex
  5b49fee  platform, map: the UI thread never futex-waits on wasm
  99d2180  map: roofs on a 20-byte vertex, contact shadows as instances
  5a5eda2  map: road, fill and roof streams on the typed vertex formats, u16 indices
  f987651  map: the analytic road fringe is baked only when the view is flat
  7e66991  map: finished bakes reach the screen on the next frame
  d8539d8  map: the detail parse and merge stop allocating
  7a2c09a  map: road-union faces on a 16-byte vertex
  a2cbe38  map, platform: the tile budgets follow the platform's one memory number
  fef8058  map: marker stalks and stoplights are instances
  662d141  map: building wall instances on a 20-byte record
  d6d3241  map: round road caps are a fragment SDF, dead cap rows gone
  8ae7c3c  map: every typed stream index stays u16 — streams chunk under 65,536 vertices
  4e61e44  route + map: the desktop app streams the makepad.nl archive through a persistent on-disk range cache, chosen in settings
  a8b0382  map: the water/foliage shimmer read draw_pass.time, which flags every DrawMap* shader as animated and repaints the whole map at display rate forever — a Rust-stamped shiny_time uniform instead; the 20 Hz heartbeat drives it
  0d3a9b8  map: nothing animates at rest — the water/foliage shimmer heartbeat runs only during interaction or a camera animation, plus a 1 s settle tail, then freezes at its last phase; flat and tilted views alike
  1f24428  map bake: a face-band triangle is a face only when all three records pack (a mixed triangle stays on the road path); a panicking pool job no longer takes the worker down — caught, reported once, the tile fails; the bake panic that blacked the native map and killed the web workers
  199be9e  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
  01e77d9  map: the shimmer clock is one pass-level uniform (draw_pass.shiny_time, a map-owned slot, never draw_pass.time) written once per heartbeat tick instead of patched into every retained draw call's block — the settle tail stops re-uploading 600 uniform blocks per tick
  d641cbf  map: labels no longer vanish — the gesture label budget is charged from the placement loop, not from candidate collection (4-7 ms on the web at z15-16, up to 6000 candidates in space warp), so a place can no longer commit an empty cache; a truncated pass is never a strict cache hit, arms its own settle wake, and the at-rest follow-up chain is capped at 4
  635c3a3  map: ready tiles are inserted at most two per frame (byte budget kept), queued visible ring first then margin ring, the stale tile drawn until its replacement lands — a restyle burst of 4-9 refined tiles no longer stalls a frame for 70-120 ms
  ddc4709  map: touch gestures — one-finger pan and double-tap zoom, two-finger pinch zoom around the midpoint, rotate with a 5° dead zone, and a parallel vertical slide for tilt, one state machine native and web; the web page keeps browser pinch-zoom out (non-passive touch listeners, touch-action none, maximum-scale 1)
  8eaa6ec  map: two-finger tilt follows the phone convention — fingers up tilt into 3D, down flattens
  018ce73  map: labels hold still through a gesture and never pop — the settled placement rides the camera delta while anything moves (pan now part of the motion signature; re-place only beyond the pan/zoom law), every draw uses the rect-centre fold pivot so CPU placement and the GPU warp agree (a fresh place drew about the screen corner: the giant space-warp labels), and a re-place cross-fades: survivors keep their birth, newcomers fade in, dropped labels retire from their own camera over 250 ms
  c79e84e  map: a tilt is two fingers moving together up or down — same vertical direction for both, the pair's stroke within a fifth of vertical; spread and angle no longer matter, so real fingers trigger it

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:39:37 +02:00
Admin
48e7a01ec9 draw: geometry, shaders, WGSL, fonts, turtle/layout
Squash of 10 work commits (Sep 2–11):
  120b7e2  score view: the engraver as a shared library, with drum and pitched score builders
  09b41a8  fonts: FontSet and FontPolicy — one application choice, selected-only loading, a font-assets manifest
  6981e90  fonts: manifest generated from the chains, app-level font assets, a symbol fallback, deprecated i18n aliases
  77d9138  wm: the module contract and the first in-process app — sheets in a tile, in an isolate of its own
  55a3810  platform: typed compact vertex formats and u16 indices
  83a8d4f  fonts: the web demos start with the Latin set — CJK and emoji faces load on the first glyph that needs them
  1980c24  platform: a draw call whose geometry id went stale is skipped, not drawn with whatever mesh now sits in the reused slot — the runaway triangle count that took a web map pan to 1 fps; reported with a power-of-ten backoff, never per frame
  a75fe91  layout: extend turtle sizing and add Grid
  4429551  draw, widgets: text clips by the list clip; GaussChain; map colour roles
  6e02468  draw: restore Cx2d::set_current_pass_dpi_factor (raster density) beside the display-dpi setter

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:39:02 +02:00
Admin
874374635f widgets: glass, dock, tweaker, themes, code_editor, phone shell
Squash of 36 work commits (Sep 1–12):
  176433a  tweaker: click-again climbs the pick — the container under the children is reachable
  97e9572  speech: one STT/TTS API on every platform, through the ai-hub
  8ea3684  widgets: EventOrder reachable from the DSL; DataGrid hit-tests where it was drawn
  0fd1ea2  route: demo profile — native/demo features, side-panel and provisioning seams, hosted tiles, HTTP nav client
  cf4c84c  keys: F10 is the assistant — the exploded-view debugger moves to Shift+F10, the screen recorder to Ctrl+F10
  126d8c9  route: the demo profile runs in the browser — merged panel draw, platform clock, unavailable backends tolerated
  e21db96  route: demo review fixes — route origin, rain lifecycle, hosted route validation, request context, provisioning
  c24c206  aichat: the Window overlay — F10 in every standalone app, the in-process port, the /ai bridge routes, sheets as the pilot
  dbe43bd  wm + widgets: the AI panel on the left, pushing the body in
  5184340  platform + vj + map + files + widgets + image_tiles: the runtime owns one warm two-lane task pool — jobs never spawn threads
  697215e  route + converse + example-map: every worker comes from the runtime pool or a start-up worker
  862f3bd  asset widgets + chat ui + render: fan-outs and jobs on the runtime pool, the transcript read without a lock on draw
  976ea0e  tweaker: Shift+F10 toggles it on every platform (KeyEvent::is_tweaker_toggle, one call site; the web page swallows exactly Shift+F10 so the browser never sees it); the exploded z-layer view has no keyboard shortcut any more — it is a button in the tweaker
  4e8e4cd  flow-ui: the design pass — menu bar and toolbar with the total run bar, continuous zoom through the draw-list view transform with pointer remapping, dark checker canvas with grid steps, shadowed cards with icon labels and port icons, glowing wires, per-node progress bars, full-bleed image cards, palette cards you drag out, the fab edit controls in the inspector, a template picker behind New, model pickers from the hub; MenuBar widget in the shared crate
  075e1a7  flow-ui: pickers filled from the hub for image and text nodes, popups anchored through the canvas transform, labelled face controls, add_style explains itself, cards resize from a grip with size: vec2 kept in the file, full-bleed pictures, a click anywhere on a card selects it and still reaches the face, no remount on layout-only edits, panels float over the canvas
  a50750f  flow-ui: Flows, Running and Palette as their own rounded panels with splitters, the inspector and source pane likewise, columns resizable; gaussian frame shadows; keys and IME reach the focused face field through the canvas transform
  43302a6  flow-ui: every card owns a draw list and draws in z order, selection brings it to the front; and the design review's findings — every event kind remapped through the camera, run events keyed by run id, no remount mid-run, an input journal that survives a failed PUT, terminal states reconciled, the total bar from the planned node set, isolate ownership on instance change, popups retired before an isolate is freed, the Ask face answers on a button, the menu bar navigates by keyboard, no per-frame allocation in the canvas draw
  4ee4f4c  flow-ui: the resize path sets walks and fits through typed setters, never a script apply from the main VM on an isolate's widget — a failed apply had left a freed script object behind and wedged every frame; a resized card fills its picture box, clips its face and lets the last flexible element take the height
  cff15ac  widgets: a fab number field drops a label that cannot fit instead of crushing it to a dot
  24c927a  flow-ui + widgets: every dropdown is the searchable ComboBox
  a6c5f15  widgets: FabValueInput honours visible, so the seed picker's random mode hides the number field
  1181a3b  flow + flow-ui + widgets: every creator pipeline is a template — 55 templates in six groups (Image, Video, Audio, 3D, Vision & text, Utilities), all evaluated and engine-exercised in tests; the New picker, the flows.templates tool and the palette group the same way; the Templates menu shows them under group headings, and a menu taller than the window scrolls
  f8b9a67  widgets: preserve numeric edit completion and menu focus
  ed5f2e2  Add hotloadable OS themes and preserve widget state across style changes
  f1d3b39  Center resized app recordings on a fixed black canvas
  915fcae  Remove icon rim highlights and align compact home tile contents
  bfa7805  Keep terminal palettes theme-aware and resize above mobile keyboards
  7535ce8  Fix workspace build regressions (#1220)
  2233cbc  Replace legacy Studio with docked and canvas agent workspace
  708aa9f  code_editor: range views, anchors, prepared documents, read-only, tab stops
  0eae276  widgets: capture Studio evaluation feedback and recordings
  487c602  widgets: let Studio pump dock bodies across presentations
  c5adb93  Studio code atlas: settle-line diagnostics, index progress, chrome fades, exact search budget
  ee9ab46  widgets: every screen capture lands in the repo's local/screencap, named by app
  dcc9673  draw, widgets: the phone shell's glass, hosted-view and overlay support, app icons for the new apps
  2fbc679  wm: preserve app caption controls and add Scope to the launcher

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:38:48 +02:00
Kevin Boos
a843d772b5
Html: fix collapsed details with void tags corrupting table layout (#1222)
* Html: keep collapsed details with void tags from swallowing table closures

* Html: harden the parser, the walker and the widget against malformed input

Follows the void-tag fix in the `<details>` skip loop by auditing the rest of
the HTML code for the same class of defect. Robrix renders `formatted_body`
straight from Matrix events, so every parser crash here is reachable from a
message any stranger can send.

Crashes, all reachable from a chat message:

- Numeric character references were parsed as `i64` and cast to `u32`, then
  handed to `char::from_u32(..).unwrap()`. `&#xD800;`, `&#x110000;`, `&#-1;`
  and `&#99999999999999;` aborted the process. They are validated now, and a
  reference that names no scalar value stays literal text.
- An unterminated `&` stayed pending across a tag boundary or a closing
  attribute quote, so a later `;` could fire `decoded.truncate()` and
  retroactively invalidate byte ranges of nodes already emitted —
  `<p>&am<b>p;</b></p>` produced out-of-bounds and mid-character ranges.
  The pending entity is dropped at each of those boundaries.
- An unquoted attribute value beginning with a multi-byte character recorded
  `decoded.len() - 1` as its start, splitting the character.
- `</summary>` with no `<summary>` popped an empty tracker stack, and stray
  `</td>`, `</tr>`, `</li>` and friends reached `cx.end_turtle()` with nothing
  to end. The widget now tracks what it opened and ignores unmatched closes.
- `('A' as u8 + count as u8 - 1)` overflowed on an attacker-controlled `start`
  or `value`; alphabetic list markers now number a..z, aa, ab, ...

Content silently lost or mangled:

- `jump_to_close` counted every open tag toward depth, but a void element
  written without a slash emits no close tag, so it overshot and swallowed the
  rest of the document. `<a href=u>x<br>y</a>` hid everything after the link.
  Only tags with the same id affect depth now, and an element with no close tag
  leaves the walker where it is. `mod_html::find_close_tag` had it too.
- A `<` that cannot start a tag is literal text, the way a browser reads it.
  `5<10 and 6<12` used to parse `<10` as an element and drop the rest.
- `?` mid-tag-name and `<!-->` / `<!--->` ran to end of input.
- `/` in an unquoted value ended it, truncating `href=http://host/path` at the
  first slash; only a slash immediately before `>` closes the tag now.
- `<a href=>text</a>` took `>` as the value's first character, so the tag never
  closed and its content leaked out as text.
- Unquoted values never decoded entities at all, unlike quoted ones.
- `<pre>`/`<code>` whitespace preservation was a single flag that any nested
  tag cancelled, so a syntax-highlighted code block lost its indentation. It is
  a depth counter now.
- HTML's whitespace set is five ASCII characters, not Unicode's;
  `char::is_whitespace` collapsed `&nbsp;` runs and ate the full-width spaces
  in CJK text.
- `find_text` returned the zero-length node the parser emits before every tag,
  so `<a href=x><b>label</b></a>` rendered an empty link. `find_tag_text`
  matched the case-sensitive id and missed any tag carrying an attribute.
- Duplicate `id` attributes bound two elements to one cached sub-widget, so a
  second link could render its own text over the first link's href.
- `<li>a<li>b` and `<td>a<td>b` now implicitly close the previous item, and
  anything a document leaves open is unwound before `TextFlow::end`.

Entity table, which had been generated by folding names case-insensitively:

- 146 names took their case-twin's code point. `&eacute;` rendered `É`,
  `&alpha;` rendered `Α`, `&rarr;` rendered `⇒`, `&copf;` rendered `ℂ`.
- `Igrave`/`Icirc`/`Iuml` had been transcribed as `Lgrave`/`Lcirc`/`Luml`, and
  `Iacute` was missing outright; the invented l-spellings are removed.
- `permil` mapped to the Windows-1252 byte 0x89 rather than U+2030, and an
  empty-string key sat where it belonged, so `&;` decoded to `‰`.
- `tilde`, `lang` and `rang` were wrong.
The ALL-CAPS aliases the table also carries are left as they were.

Also: dropped the `unwrap` in `ElementSelfClose`, memoised table column counts
(quadratic in the number of `<table>` tags), and replaced the backward node
scan on every tag close with the depth counter.

Adds 18 tests covering each of the above. Verified by exhaustive enumeration of
all 12.2M inputs up to length 6 over a markup-heavy alphabet, and 6M randomized
structured cases, both checking that no input panics and that every node's byte
range is ordered, in bounds, on a character boundary, non-overlapping, and
agrees with its `all_ws` flag.

* Html: recover from malformed tags without leaking them into the text

A second pass over the same code, after the first round of fixes changed what
the edge cases look like.

- `</` followed by something that cannot name an element is literal text, the
  rule `<` already follows. `i </3 u` used to emit a close tag named `3` and
  drop the rest of the line.
- Junk inside a tag is discarded up to its `>` rather than resuming text in the
  middle of it, which leaked the tag's own `>` into the output: `a</p x>b` and
  `a<br/x>b` rendered `>b`.
- A custom widget with no close tag of its own is void, so it has no text.
  Reading ahead picked up the *following* sibling's text, and now that
  `jump_to_close` correctly stays put, the main loop drew that text a second
  time: `<img src=x>caption` showed `caption` twice.
- `table_columns_cache` is keyed by node index, so it has to be cleared per
  draw or a recycled widget lays a table out with a previous document's column
  count.
- `<ol start="2147483647">` overflowed the item counter.

* Html: bound jump_to_close's scan and cut the measured hot spots

Benchmarked against the branch point (best-of-7, black_box'd, release).

- `jump_to_close` stops at the first close tag belonging to an enclosing
  element instead of reading to the end of the node vector. It tracks the
  elements opened inside this one so a descendant's close tag is still
  matched correctly, and allocates nothing for the common case of an element
  whose content is plain text.
- Numeric character references were compared against all ~1500 named-entity
  arms before reaching the catch-all. Dispatching on the leading `#` first
  makes them 2.9x faster (991us -> 342us for 3000 references).
- `process_entity` is `#[inline]`; it is called once per character.
- `decoded` is reserved up front, worth ~4% on text-heavy input. `nodes`
  deliberately is not: its length tracks tag count rather than byte count, and
  sizing it from `body.len()` cost a tag-sparse document a large pointless
  allocation — that made the numeric-entity case 3x *slower* before it was
  measured and removed.
- The widget rejects an unmatched close tag from a tally instead of scanning
  the whole open-element stack, which was quadratic on a message combining
  deep nesting with stray close tags.
- `align_keyword_to_x` compares in place rather than lowercasing into a fresh
  String for every aligned cell on every draw.

Tag-heavy parsing is ~2-3% slower than the branch point, which is the standing
cost of the `<pre>` depth tracking, the literal-`<` guard and the entity state
carried across characters. Plain text is ~4% faster.

* Html: follow the tokenizer's recovery rules and resolve element ends at parse time

The parser's states now mirror the WHATWG tokenizer's, so malformed input
produces the tokens a browser would build from it rather than a guess:

- `</` followed by anything but a letter opens a bogus comment that runs to
  the next `>`, `</>` is dropped, and `<?...>` is a bogus comment too. `<`
  or `</` at the very end of input is text.
- `<a/b>` reads as `<a b>`: the slash was not a self-closing marker, so no
  close tag is synthesized. `<x/>` still emits one — the SVG parser is built
  on this walker and XML needs it — which is the one deliberate departure.
- In an unquoted attribute value a `/` is just another character, so
  `href=http://host/path` keeps its path and `<img src=x/>` is `src="x/"`.
- `<!--x--!>` closes a comment, `<!-x>` is a bogus comment, and a tag cut
  off by the end of input is dropped whole.
- Numeric character references follow the tokenizer's end state: zero, a
  surrogate, or anything past U+10FFFF becomes U+FFFD, and the C1 range is
  read as Windows-1252, so `&#151;` is an em dash as legacy content intends.
  Digits are accumulated with saturation so a forty-digit reference lands on
  U+FFFD rather than an error. A decoded space collapses like a literal one.
- `<pre>`/`<code>` are tracked as a stack: a stray `</code>` cannot cancel an
  enclosing `<pre>`, and `</pre>` closes a `<code>` left open inside it.

Every element's end is now resolved once at parse time (`HtmlDoc::closes`),
with the recovery a browser applies: a close tag ends the innermost open
element of its name and everything still open inside it, and a close tag
that matches nothing is ignored. `jump_to_close` and the new
`HtmlWalker::close_index` are lookups, which removes the last quadratic
case — a paragraph of thousands of `<img>` tags cost 3.4ms a frame — and a
stray `</span>` no longer stops a link's `</a>` from being found. The tally
that rejects stray close tags hashes `LiveId` through an identity hasher,
since it is already a 64-bit hash; with SipHash the pass cost 20%.

Widget:
- A `<summary>` left open is closed by `</details>` or the end of the
  document, so its bold run and glyph tracker no longer leak into everything
  drawn after it.
- Implicit closes follow the tree builder's scope rules — `<li>` closes an
  open item up to its list, a cell up to its row, a row with its cells, a
  heading directly following a heading, and any block element an open `<p>`
  — rather than only the innermost element.
- A custom widget's label is all the text inside it, so
  `<a href=x><b>Click</b> me</a>` reads "Click me", and a void one has none.
- Sub-widgets are keyed only by node index. Keying by the `id` attribute let
  a document choose cache keys, and a repeated id bound two links to one
  widget.
- `TrimWhitespaceInText`, `combine_spaces` and `ignore_newlines` are gone:
  all three were written at every site and read at none.
- List markers are borrowed rather than allocated per item per draw, table
  cell alignment compares in place, and link hit-testing no longer clones
  its area list on every event.

Script module: `.html` printed raw hex for every tag and attribute name,
because the document was parsed without interning; it is interned now and
text and attribute values are escaped on the way out, so the output parses
back to the same document. `find_elements` counted every open tag toward
depth, the void-element bug again; it steps by resolved close index.

23 parser tests, exhaustive enumeration of all inputs up to length 6 over a
markup-heavy alphabet, and 6M randomized structured cases, checking that no
input panics and that every node range and close index is consistent.

* Html: resolve every element's end in the tokenizer, and close the review's findings

An adversarial review of the previous commit against the WHATWG tokenizer,
the branch point and a reference parser found the gaps below. All fixed.

The parser now keeps the open-element stack as tags stream past, so each
element's end is resolved in the same pass that tokenizes it — the recovery a
browser's tree builder applies: a close tag ends the innermost open element
of its name and everything still open inside it; a close tag that matches
nothing is ignored; the spec's void elements are whole at their open tag;
what is still open at end of input ends there. `HtmlDoc` records both the
element's own close tag (`close_index`) and where it ends (`end_index`).
That distinction was missing: an element ended by an ancestor looked the
same as a void one, so the script module gave `<li>a<li>b` items empty
ranges — no `.text`, no `.html`, children promoted to siblings — and the
widget dropped the label of a link ended by `</td>`. Both read correctly now.
Because the whitespace-preserving stack is the same stack, a `<pre>` ended
by an enclosing element's close tag stops preserving at that tag, which it
did not before.

Tokenizer fixes, each per the spec's state machine:
- `<!>` and `<!->` are complete bogus comments; they used to swallow text up
  to the next `>`.
- A numeric character reference ends at the first non-digit whether or not
  `;` follows (`&#38 b` reads `& b`), and has no length limit: forty digits
  saturate to U+FFFD as the previous commit claimed but did not do.
- An end tag followed by junk and then end of input is dropped like any
  other tag cut off there; it used to emit its close tag anyway.
- `\r\n` and lone `\r` become `\n`, as the input stream preprocessing says.
- A repeated attribute name on one tag is dropped, so a consumer iterating
  attributes sees the first `data-mx-color` rather than the last.
- A comment is not content, so `a <!-- c --> b` collapses to one space.
- `find_tag_text` answers for the first matching element and does not fall
  through to a later one.

The maps that reject stray close tags and duplicate attributes are keyed
with a per-parse random seed and a multiply-fold hash: the previous identity
hasher let crafted tag names collide and made the pass quadratic, and the
standard SipHash cost a quarter of the parse time.

Widget:
- A `<summary>` is tied to the `<details>` that owns it. A `<details>` opened
  inside a summary was taken for the owner, and `</details>` then popped an
  empty tracker stack — a panic reachable from a chat message.
- `</summary>` and `</details>` end whatever was opened inside them, so an
  `<li>` or a table cell opened in a summary no longer swallows the content
  that follows.
- A collapsed body is skipped to the element's resolved end, so a
  `<details>` ended by an ancestor no longer hides everything after it.
- `count_table_columns` ends the first row at the next `<tr>` as well as
  `</tr>`; a table written without `</tr>` had every column halved.
- The `<p>` rule runs before the heading rule, as the tree builder orders
  them, so `<h1><p>a<h2>` no longer nests the second heading in the first.

Script module: ranges are `(open, end)` with an exclusive end; `parse_query`
no longer panics on `a]b[`.

30 parser tests, exhaustive enumeration of all inputs up to length 6 over a
markup-heavy alphabet, and 6M randomized structured cases, checking every
node range, every `close_index`/`end_index`, nesting consistency, and
determinism.

* Html: build the tree builder's implicit closes into the parser, and end every element where it says

Two verification rounds against the previous commit — a spec-conformance
review, a stack-based reference for element ends, a simulation of the widget's
draw loop over exhaustive and random tag soups, and a round-trip check of the
script module — found the gaps below. All fixed.

The parser now applies the tree builder's implicit closes as it builds the
element stack: a block start tag closes an open `<p>`; a heading closes a
heading that is the current node; `<li>` closes an open item up to its list,
`<dd>`/`<dt>` likewise; a cell closes an open cell up to its row; `<tr>` closes
a row and its cells; a table section closes section, row and cells; a second
`<a>` closes the first. Every consumer therefore sees the tree a browser
builds: `<li>a<li>b` is two items, `<a href=1>x<a href=2>y</a>` two links,
and `<li><a href=u>one<li>two` gives the first link the label "one" rather
than "onetwo". The widget's own copy of these rules is gone; it closes each
element at the index the parser resolved, before that node is handled, and
`<details>`/`<summary>` without a close tag of their own are ended the same
way. Two bugs that fell out of them being special:
- a `<details>` ended by an enclosing close tag stayed on the stack, a later
  `<summary>` bound to it, and the collapse-skip resumed *behind* the walker.
  One stale level drew the text twice; N of them re-walked the document 2^N
  times — a 380-byte message hung the UI. A resume is now never behind the
  walker, and no level is left behind to be claimed.
- a `<summary>` ended by an enclosing close tag never popped its bold run and
  glyph tracker, which leaked into everything drawn after it.

Per-name depth stacks replace the per-name counts, so finding the innermost
open element of a name, or the outermost one above a scope boundary, is a
lookup; scanning the stack made a document of nested `<div>`s quadratic.
A tag with thousands of attributes no longer makes every later tag pay to
clear the attribute-name set. Every nesting shape measured is linear.

Tokenizer and tree builder, per the spec: `</br>` is read as `<br>`, so
`x</br>y` breaks the line; the newline immediately after `<pre>` is not
content; NUL is dropped from text and replaced in attribute values.

Widget: a table whose first row is empty is sized by the first row that has
cells rather than falling back to 100px columns.

Script module: `.html` always writes `=""` and doubles a newline that starts
a `<pre>`, so its output parses back to the same document; `.text` is the
decoded text verbatim, no longer inventing a space inside a word split by a
comment or an inline tag; a query on a selection searches inside it, as
`querySelectorAll` does; descendant steps skip ranges already scanned, which
made `b b` on deeply nested `<b>` quadratic; `parse_query`'s grammar is
documented as implemented.

Deliberately unchanged: the entity table's omissions (`&euro;`, ...), named
references without `;`, and an unquoted attribute value ending in `/` before
`>` (per the tokenizer the slash is part of the value; XML requires quotes).

33 parser tests; exhaustive enumeration of all inputs up to length 6 over a
markup-heavy alphabet and 6M randomized structured cases, checking every node
range, every `close_index`/`end_index`, nesting consistency, attribute
dedupe and determinism.
2026-09-11 10:54:28 +02:00
Jason Yau
14fe611e66
Add Apply::Rebake so script_mod re-runs stop clobbering imperative state (#1219)
Co-authored-by: jasonqiu <jasonqiuchen@outlook.com>
2026-09-05 23:26:03 +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
Kevin Boos
6d71eda34f
Splash: host->script hook calls find fns defined after a shadowing let (#1210)
`call_script_fn` looked names up in the module body scope, but a
`let`/`fn` that shadows a name already in scope opens a child scope,
and everything the script defines after it lands there, invisible from
the module scope. The Splash prefix's own `let fs` / `let host` can be
that shadow, so app hooks never resolved.

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

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

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00
Admin
55a38104aa platform: typed compact vertex formats and u16 indices
Draw shaders can declare geometry POD fields as F16x2/F16x4, U16x2/I16x2
(plain or normalised) and UNorm8x4/SNorm8x4; the fetch converts them to
vec2f/vec4f on Metal and WebGL2 (per-attribute vertexAttribPointer with
type, normalised flag, byte stride and offset), the headless JIT decodes
the same formats, and Vulkan/OpenGL/D3D11 refuse compact layouts with a
logged skip rather than drawing garbage. Attribute packing computes
physical offsets with natural alignment for the whole record; the all-F32
path stays byte-identical (stride = slots * 4, packed_geometry_N on GL).

Geometry::update_typed / update_typed_with_recycled_buffers take
IndexData::{U16,U32} plus a byte vector and the shader's input layout;
updates are validated (stride, whole vertices, index range) and every
geometry carries its index width and a layout signature that survive
releasing the CPU staging, so a draw checks layout and index type against
the resident buffers, never the staging enum. Compact fields are rejected
in instance PODs and in nested aggregates at shader validation; SNORM
minima clamp to -1 like WebGL2.

On Metal the decoded (logical) vertex is reached through the shader
context like the instance is, so every shader function that reads
geometry compiles.

No map stream is converted yet; that is the next cut.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00
Admin
6be1118b2d vj: the whole app on the web — site store for content, embedded store for local imports, native-only seams Unavailable
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 16:12:34 +02:00
Admin
6c32c88d1a web-server: ETags from size and mtime, deadlines from size, Allow per resource
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 15:42:27 +02:00
Admin
9c9c72ba8d web-server: bodies land before workers, client keys normalized, verbs fail closed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 15:36:09 +02:00
Admin
cf2b8ca4bd platform: no std::time on web — clippy guard and the platform clock everywhere a web build runs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 15:30:29 +02:00
Admin
dfe2087399 web-server: O(1) report admission, one connection deadline, shared route sampler, static fallbacks, cache policy
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 14:37:36 +02: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