Commit graph

299 commits

Author SHA1 Message Date
82c6ef3ab0 fix(fork): refresh draw from upstream work - font API skew 2026-09-26 03:11:40 +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
f82a3c2126 draw: glass of a view that stopped drawing leaves the screen -- a glass surface records into the window overlay and stays there while its parent list does not redraw (a cached view); a texture-cached view that went invisible never redraws, so its glass stayed where it last was. The calendar switching from its phone layout to the wide one kept the phone toolbar's glass capsule over the sidebar's mini month. The overlay now also drops a glass whose parent list renders into a pass that is no longer attached (Cx::pass_attachment_is_stale, walked up the texture-pass chain)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 11:14:14 +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
deb66b4fef draw text: the CoreText outline fallback is only ever resolved for a face whose outlines live solely in hvgl, and font-family diagnostics are the font trace topic -- a space has no outline in any font, so every face on macOS reached the fallback and would have resolved a CTFont for it (PostScript-name lookup, a cascade-list scan, then the face written to a temp file and loaded through the font manager) on the UI thread to outline nothing; the gate checks for an hvgl table with no glyf, CFF or CFF2, so bitmap faces stay out too; MAKEPAD_FONT_DEBUG read the environment on every update_font_definitions and is now MAKEPAD_TRACE=font
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 22:34:43 +02:00
ychen
09ff817679 feat(text): CoreText outline fallback for hvgl-only fonts (macOS)
Apple ships system fonts whose only outline table is the proprietary hvgl
format (PingFangUI.ttc on macOS 26+ has no glyf/CFF at all). They parse
fine — cmap, metrics and shaping all work — but ttf_parser can outline
nothing, so text silently renders blank.

When ttf_parser yields no outline, Font::glyph_outline now asks CoreText
(whose in-OS decoder reads hvgl) for the glyph path and converts the CGPath
into the same GlyphOutline commands the SDF rasterizer already consumes.
Shaping, metrics and the atlas are untouched; the fallback only fires for
glyphs that render nothing today.

CTFont resolution is layered because CoreGraphics and CTFontManager both
refuse hvgl-only fonts loaded from data or URL, and CTFontCreateWithName
silently substitutes a fallback for dot-prefixed hidden names: try the
PostScript name, then scan the system UI font's cascade lists for CJK
languages (where hidden fonts like .PingFangUITextSC-Default are
reachable), then a temp-file font-manager load. Every candidate is
validated against the ttf_parser view of the face (glyph count + cmap
probes) so a substituted font can never smuggle mismatched glyph IDs into
the atlas. Variation coordinates (e.g. wght for bold) are carried onto the
CTFont via kCTFontVariationAttribute, consistent with the HVAR-adjusted
metrics rustybuzz produces.

Also: env-gated MAKEPAD_FONT_DEBUG=1 logs font family member resolution
(resource path + byte count) while families load.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 4c59a370834189b87ee6d151b9971defb860e812)
2026-09-23 22:34:43 +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
68e1892585 platform: the Android desk swipes at 120 Hz — offscreen render passes and framebuffers cached, SVG meshes kept, font families that complete
Measured on the Pixel 11 Pro XL (PowerVR): a pane swipe presented at
~84 fps on the 120 Hz panel, a vsync dropped every three to six frames.
simpleperf showed 22% of the CPU in the driver's shader compiler and 24%
in its render-target teardown: the Vulkan backend created a VkRenderPass
and a VkFramebuffer for every offscreen pass on every frame and destroyed
them after the fence, and on this driver each render pass compiles a
load-op shader. Offscreen draw render passes now live for the device
(keyed by formats and load/store ops) and framebuffers are cached per
render pass, attachment views and storage extent, invalidated through
texture retirement so they die after the frame that used them.

The app icons were re-tessellated from SVG every frame: one DrawSvg kept
one scale and the desk draws each icon at two or three sizes. A DrawSvg
keeps up to four meshes per device scale; the geometry pool defers frees
and releases them once per frame against the geometry ids the live draw
lists still name, so a retained draw call never sees its slot reused.

A font member whose resource can never load (the WM referenced Inter and
its other faces through `self:../../widgets/...`, unmapped in a package)
kept its family incomplete, and an incomplete family is redefined every
frame: the layout cache cleared, every label laid out again, the asset
reopened. Such a member drops out of its family once, logged, keyed on
the resource registry's generation so a resource that appears later is
asked for again. The WM names its fonts through `makepad_widgets:` and
reads the clock in-process on the UI thread instead of forking `date`
twice a second.

Android gains a `frame.cpu` trace (events, next-frame, draw and repaint
milliseconds per drawn frame) and a profileable manifest so simpleperf
can sample a release build. The dyn-pack tile proof tolerates the app's
own Dirty line after an engine rebuild.

After: SurfaceFlinger presents every swipe frame at 8.3 ms, the render
thread runs at ~45% instead of 85–97%, and the frame is paced by the GPU.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 00:03:14 +02:00
vjroger
6f345003c9 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 took it
Squashed from vjroger/makepad `storybook-pr` at 086d25452 (1,332 commits on top of
6f1e44649; his last commit restored every path outside the contribution to upstream).

- apps/storybook: every component organised, documented and previewed live.
- widgets: about eighty new widgets (accordion, alert, avatar, badge, breadcrumb, calendar,
  card, carousel, chat, chip, colour, command palette, date and time pickers, dialog,
  dropzone, floating action and panel, form, hamburger, line and radial menus, kanban,
  masonry, menu, nav list, pagination, pill nav, popover, progress, property inspector,
  range slider, rich text, select, spinner, table, tabs, tag field, timeline, toast,
  toolbar, tour, transfer, tree, waveform, wheel picker and more); theme tokens and a
  theme store, themes mixed by weight with a legibility check, a twelfth style sheet in
  black and orange; the data grid gains row selection, drag and reorder, heading tips and
  alignment; the glass button is a water lens; the portal list keeps the wheel it uses,
  stands down from a press another control holds, can keep a row on screen and rule the
  gap under a short list.
- platform: sweep locks and scroll blocks nest, `is_mouse_held_outside`, per-axis
  scroll-handled flags, `next_frame_is_pending`, owner-scoped scroll unblocking, a
  hands-off marker for the remote bridge, exploded-view projection and focus.
- draw: the interior distance of square-cornered boxes, a pointer shape, and
  `turtle_ancestor_clip`.
- wm: the style tween carries an eighth weight for the new sheet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 22:56:31 +02:00
Kevin Boos
b5bd9bc6b9
Ten fixes from moving an app onto current dev: macOS drawable/resize, the UI signal broadcast, internal drag on Linux, and log noise (#1239)
* Button: add `label_align` to center a wrapped label

`Button::draw_walk` passed `Align::default()` to `draw_text.draw_walk`, so
a label that wrapped onto more rows left-aligned them under each other even
when the button itself centered its content, and no script property could
reach that argument.

* New `#[live] label_align: Align`, mirroring the one `TextInput` already has.
* Defaults to left, so every existing button draws exactly as before.
* Pair it with a `Fill`-width `label_walk` to give the rows room to move.

* macOS: don't paint into a drawable the layer has since outgrown

The prefetching `DrawableWorker` hands back a drawable that `nextDrawable`
acquired on the previous beat. A frame that straddles a resize therefore
attaches a texture of the old size to a viewport derived from the new one.

* moving a window between displays of different DPI drew the whole UI at
  the old scale, and it stuck: a dpi change dirties the pass exactly once
* dragging a border fast left the strip the old texture didn't cover
  unpainted, which macOS shows as magenta

Check the invariant where the drawable is consumed: a texture whose size
isn't the layer's `cal_size` is dropped and one is acquired on this beat,
the way the pre-worker path did every beat. The pool was just rebuilt for
the new size, so that acquire doesn't block. Traced on the `present` topic.

* Window: don't put an app icon in the caption bar by default

`AppIcon` falls back to a generic placeholder tile for any app id makepad
ships no artwork for, so every third-party app got a meaningless icon next
to its title, and an off-centre title with it.

* `AppIcon` gains `visible`, which it had no way to express before
* the caption icon defaults to hidden; apps opt in with
  `caption_icon +: {visible: true}`

* Quiet the startup and per-decode log spam

A plain run printed ~1500 lines before anything happened.

* `zune-qoi` was the only zune crate with `log` in its default features,
  and cargo unifies that onto `zune-core`, so every zune decoder logged
  per image. zune-core's macros became real logging in this tree, so what
  used to be inert now floods the log
* memory budget, task-pool priority/summary and the Metal retained-upload
  budgets move onto the `MAKEPAD_TRACE` topics this tree added
  (`memory`, `pool`, `gpu.upload`)
* drop the studio-websocket line, which only says a disabled thing is off

* Make the UI-hang sampler opt-in

It started with every `Cx`, so a shipped app carried a thread waking ~16
times a second forever, and any stall over 250ms got the UI thread
suspended once per sample while its stack was walked.

`MAKEPAD_UI_HANG_MS` is now the switch as well as the threshold. Unset, no
thread starts and the phase guards see a null registration, which is a TLS
read and a null check.

* Wake the event loop from render workers without raising the UI signal

`Event::Signal` means "a worker has something for you" and is dispatched to
the whole widget tree. The submitter, the instance allocator and the
drawable worker raised it after every commit, so an app painting at 120fps
walked its tree 120 extra times a second. Measured in robrix: 119 signals
against 111 repaints, down to ~0.3 per frame.

They only ever wanted the loop awake, so give them `wake_ui_loop()`, which
is what `set_ui_signal` already called underneath. A dirty pass is what
keeps the paint clock armed, so nothing depends on the flag to get painted.

* Compare the resident instance bytes instead of hashing them

`immediate_payload_hash` FNV'd every byte of every dirty draw call to skip
the upload when nothing changed. That suits a few big payloads, not a 2D
frame: robrix scrolls ~1090 draw calls of ~110 bytes, and the hash cost
2.3ms a frame in a debug build to skip ~12% of 110KB of uploads.

Instance buffers are StorageModeShared, so the resident copy can just be
compared. `memcmp` stays fast in an unoptimized build, and an exact
comparison can't collide into a stale frame the way a hash can.

* Install a platform stylesheet only when an app asks for one

`current()` picked "ios"/"android" straight off `OsType`, so any app built
for a phone was silently restyled: ~270 theme tokens including the fonts,
over whatever the app had already set.

Worse, it only half-landed. `apply_theme` runs from `widgets_mod` but
`apply_widgets` runs from `script_mod`, so an app that calls the
`theme_mod` + `widgets_mod` pair got the mobile palette with desktop
metrics. Every in-tree user already calls `install` or sets
`MAKEPAD_WIDGET_STYLE`, so that variable is now the only implicit route.

* Let an internal drag deliver its pointer events on Linux and wasm

Moving internal drag handling into shared code changed it in two ways that
the macOS and old X11 paths never had, and a dock tab shows both.

The pointer event was replaced by the drag event rather than followed by
it, so no widget saw the `MouseUp`. `Tab` sets `is_dragging` on FingerMove
and clears it only on FingerUp, so a tab could be reordered once and then
never dragged again. Dispatch the pointer event first and append the drag
one, with a flag so that dispatch doesn't produce the drag event again.

A release that never moved after `start_dragging` also produced no Drop and
no DragEnd at all, so `Dock` never cleared `dragging_tab` and kept painting
the ghost. `Tab::min_drag_dist` has no default, so a press, one motion and a
release reaches it. Every other backend ends the drag unconditionally.

* Split the UI signal so makepad's own queues don't broadcast Event::Signal

`set_ui_signal` was the one wake for everything, and every platform loop
answered it by running makepad's handlers AND broadcasting `Event::Signal`
to the whole tree. So termination, the network runtime, live reload and
every pool completion (label shaping, per frame) woke every widget.

* `set_internal_signal`: the loops run their handlers and don't broadcast
* `TaskPool::submit_internal`: a job whose result makepad polls at draw
* `Event::Signal` is documented, and the loops treat the app flag as a
  superset of the internal one, so nothing left on it can regress

The scheduler keeps the app signal on purpose: `service_scheduler` re-arms
the platform timer from `call_event_handler`, which only the app half runs.
Media device changes still go through `SignalToUI::set`, whose instance API
is app-facing; they are hotplug-rare, so splitting that is left alone.

* Harden the drawable re-acquire, the internal drag and the opt-in sampler

Follow-ups from reviewing the five commits above.

* the resize re-acquire only runs while the drawable pool has a free slot.
  Exhausted, `nextDrawable` blocks the UI thread on the compositor, which is
  what the worker exists to avoid; skip the beat and stay dirty instead
* the byte compare no longer skips an item the GPU has evicted, which would
  leave it invisible in a pass that then repaints forever
* the internal drag suspends its items across the pointer dispatch instead
  of holding a flag. An unwound dispatch now ends the drag rather than
  wedging it for the life of the process, and a widget that starts a new
  drag from that dispatch keeps it instead of tripping "start drag twice"
* `tests/ui_hang.rs` opts the sampler in, since it is the thing under test
2026-09-18 09:06:31 +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
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
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
e32b74b988 platform: Web/wasm runtime, WebGL, web audio, browser storage
Squash of 38 work commits (Sep 2–6):
  ed5b2fa  web: wasm32 portability in libs and web startup geometry deferral
  0ccd384  platform web: focus dispatch, window-zero geometry and generation-correct ids after the startup deferral
  a7af3ea  platform + mpfiles: platform clock instead of std::time on the web, unwind-safe event dispatch
  52251b7  platform: a namespaced async key/value storage API on Cx — files natively, IndexedDB on the web
  84b46c1  mbtile reader: file-backed readers are native-only so the map stack builds for wasm
  6b661bf  web: crashes report themselves — panic text, breadcrumbs, memory, workers; a dead instance stops pumping
  372bfd7  asset-store: browser durability — generation extents over cx.storage, chunked CAS, quota and GC
  0f967ce  web path: the stream trace and the sqlite pager never wait on a clock the browser does not have
  4e58ab9  vj: the output window exists only once opened — never on the web
  93232a2  platform: two pool workers on wasm until the allocator is per-thread
  c7fe851  vj: effect thumbnails render, encode and persist in browser storage on the web
  5b33781  platform: thread-caching allocator for the threaded wasm build
  463de64  web: shaders compile per draw list, link in parallel
  e7be0e3  vj + platform: the browser UI thread never waits on a lock, and the web hot paths log only errors and summaries
  7b33f7b  vj + platform: a loaded deck actually plays on the web vj + platform: a loaded deck actually plays on the web
  dc85eb0  web + vj: render-to-texture passes keep their 3D camera on WebGL, thumbnails wait for shader compile, bundled tiles re-ask — effect thumbnails match native
  b39d301  web audio: the worklet links the whole module — every platform import the audio thread does not serve is stubbed, clocks and the UI wake are real
  1e2dcd0  web: a pass without a draw list is skipped instead of taking the app down (F12 layers overlay)
  0ef0311  web audio: a throw inside the worklet's process() is reported with its real text instead of a bare ErrorEvent
  97e0701  vj + platform: the web audio thread never waits on a lock — a loaded deck plays
  58d3fd5  web audio: the output is created inside the first gesture, and a stalled worklet module load is retried on a fresh context
  410acd0  web + vj + route: the console carries failures and one-line summaries, nothing per request, per tile or per hiccup
  a3248d1  web audio: the worklet gets the audio access pointer as its context — the thread-stack call gained a request id and the audio start was still passing the pointer in its place
  9e2d65b  pdf + photos + task + wm + video + automate + widgets: no per-job threads — pool jobs and start-up workers
  639887d  webgl: texture passes get their depth target — the tilted map (and every 3D scene drawn into a texture) was draw-order only: hollow buildings, no roofs, landmarks buried
  2aa0780  webgl: BGRA uploads become RGBA at upload and sample_as_bgra is a plain sample on the web, as on every native backend — the tilt-shift's sharp band showed red/blue-swapped water
  de9aba3  vj + web: the Layer button works on the web — a second Window is a queried capability (OsType::is_single_window; the web creates none and reports it once), so the output becomes an in-page full-canvas layer with browser fullscreen (Esc, the browser's own fullscreen exit, or a double-click leave it); a pass without a draw list settles its dirty flag instead of erroring every frame; exitFullscreen fixed; fullscreenchange feeds the window geometry
  f615054  tweaker + webgl: click-to-climb continues only from the widget the climb started on, so a press on a sibling picks that sibling (the empty draw_bg was a bare View being pinned); the Shader tab says when a layer has no live draw call; the WebGL paint walk no longer resets every draw list's view_transform — the magnified material well drew at the window origin on the web
  0d7ddee  webgl: a uniform block is uploaded only when its generation moved — per draw call (uniforms_gen), per draw list (uniforms_gen, recording_gen), per pass (pass_uniforms_gen) and per shader scope block; the JS side caches (ptr, len, gen) per uniform buffer and re-records/recompiles reset it; direct camera writers (vj effects, render scene, the web flipped copy) bump the pass generation
  e48b056  Revert "webgl: a uniform block is uploaded only when its generation moved — per draw call (uniforms_gen), per draw list (uniforms_gen, recording_gen), per pass (pass_uniforms_gen) and per shader scope block; the JS side caches (ptr, len, gen) per uniform buffer and re-records/recompiles reset it; direct camera writers (vj effects, render scene, the web flipped copy) bump the pass generation"
  b043332  webgl: uniform blocks upload only when their generation moved — one global monotonic counter on Cx hands out every generation (draw call create/dirty/zbias, draw list allocate/transform/re-record, pass allocate/time/dpi/ortho/camera and the web flipped copy, shader scope writes), so a reused pool slot can never match a cached generation; clear_draw_items, pool reuse and VAO recreation reset the caches; the JS caches key on the generation alone. Proven on a local build: the pan screenshot keeps every tile, the settle tail drops 20.5 → 12.8 MiB/s
  3c2530d  web memory diet: the 805 MiB at load was the ocean-high archive's 13 M-entry leaf directory decoded to 407 MiB per lookup round and evicted at once — leaves now parse streaming into a window around the waiting tile ids (LeafParseLimits); a phone policy on the web (deviceMemory, UA, touch + short side) caps wasm at 512 MiB with a 320 MiB budget; archive leaf/range caches, reads and bakes in flight follow the budget; packed tile bytes stay packed until the bake decodes them; terrain scratch sized to the viewport and dropped with the layer; Cx::memory_report by owner. Phone viewport 1334 → 308 MiB after a minute of pans, desktop 1208 → 588
  303458d  webgl: a 2D texture pass builds its camera through set_ortho_matrix like every other backend, so the exploded z-layer view's camera reaches the GPU — the hand-built ortho branch uploaded an identity view and clipped every exploded draw, leaving the tweaker's layers view a bare window on the web; the Y flip for render-to-texture is one helper shared with the keep-camera branch
  1801e38  Harden web renderer and make Route location opt-in
  09fa1f0  Restore WebGL text with complete fallback samplers
  9e61553  Keep Route 3D buildings under bounded web memory pressure
  b005c6e  Preserve complete Route geometry within measured web memory budgets
  0832b35  platform: support float GI targets and retained mesh snapshots

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 13:39:18 +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
a2fdeb325d
Turtle: compute max_height from the height axis, not the width (#1231)
max_height() forwards its walk to next_walk_width(), so a height is
resolved against the horizontal axis: for Size::Fill it takes the space
the width flow rules pick, then subtracts the walk's left and right
margins instead of its top and bottom.

Only Size::Fill diverges, which is why this has gone unseen. Both
routines return v.max(0.0) for Size::Fixed, and Size::Fit never reaches
the call thanks to the early return. DrawText::draw_walk_laidout is
where it would surface: it builds its box from max_width() and
max_height() and passes both to walk_turtle() as Size::Fixed, so text
drawn with a Fill height would take its height from the available width.
2026-09-12 08:38:55 +02:00
Admin
a75fe914ff layout: extend turtle sizing and add Grid 2026-09-05 17:21:48 +02:00
Admin
1801e38453 Harden web renderer and make Route location opt-in
Bound drawable, geometry, texture, image, map and radar work; validate WebGL submissions and retire GPU resources safely. Treat context loss as terminal without re-entering Wasm after worker termination.

Add explicit Route location consent and regression coverage, including software-WebGL release probes for six deployed demos.
2026-09-05 12:13:36 +02:00
Admin
3c2530d000 web memory diet: the 805 MiB at load was the ocean-high archive's 13 M-entry leaf directory decoded to 407 MiB per lookup round and evicted at once — leaves now parse streaming into a window around the waiting tile ids (LeafParseLimits); a phone policy on the web (deviceMemory, UA, touch + short side) caps wasm at 512 MiB with a 320 MiB budget; archive leaf/range caches, reads and bakes in flight follow the budget; packed tile bytes stay packed until the bake decodes them; terrain scratch sized to the viewport and dropped with the layer; Cx::memory_report by owner. Phone viewport 1334 → 308 MiB after a minute of pans, desktop 1208 → 588
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 23:45:22 +02:00
Admin
018ce7370d 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
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 22:10:03 +02:00
Admin
b04333265e webgl: uniform blocks upload only when their generation moved — one global monotonic counter on Cx hands out every generation (draw call create/dirty/zbias, draw list allocate/transform/re-record, pass allocate/time/dpi/ortho/camera and the web flipped copy, shader scope writes), so a reused pool slot can never match a cached generation; clear_draw_items, pool reuse and VAO recreation reset the caches; the JS caches key on the generation alone. Proven on a local build: the pan screenshot keeps every tile, the settle tail drops 20.5 → 12.8 MiB/s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:59:55 +02:00
Admin
e48b056df1 Revert "webgl: a uniform block is uploaded only when its generation moved — per draw call (uniforms_gen), per draw list (uniforms_gen, recording_gen), per pass (pass_uniforms_gen) and per shader scope block; the JS side caches (ptr, len, gen) per uniform buffer and re-records/recompiles reset it; direct camera writers (vj effects, render scene, the web flipped copy) bump the pass generation"
This reverts commit 0d7ddee3f7.
2026-09-03 20:37:35 +02:00
Admin
0d7ddee3f7 webgl: a uniform block is uploaded only when its generation moved — per draw call (uniforms_gen), per draw list (uniforms_gen, recording_gen), per pass (pass_uniforms_gen) and per shader scope block; the JS side caches (ptr, len, gen) per uniform buffer and re-records/recompiles reset it; direct camera writers (vj effects, render scene, the web flipped copy) bump the pass generation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:22:56 +02:00
Admin
bb49fe6989 map + platform: retained per-tile draw lists — each resident tile owns one DrawList2d per carto pass (fill, casing, stroke, icon, icon-high, shadow) and the label glyph batches are retained the same way, recorded when the bake, LOD ring, fringe/icon gates, flat/tilted or clip change and re-attached otherwise; a pan/zoom/tilt frame pushes this frame's uniforms onto the retained calls (DrawVars::update_uniforms_on_area, resolved slot table) and uploads zero instance bytes; the tilted per-pass depth is a pass_depth uniform; a held list's zbias resolves at entry (zbias_hold in every backend); the shimmer heartbeat patches shiny_time in place without a redraw; a freed/reused sub-list id is skipped by every draw-tree walker and the mask list re-records empty on the flat transition (contract test). Web pan tail 1,098 → 20 MiB/s, flat pan 2.4 → 0.43 MiB/frame; Metal grabs within the run-to-run noise floor
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 20:04:18 +02:00
Admin
8d542feea7 platform: a child pass orphaned by its attaching draw list is no longer painted — the window's gauss_scene pass stayed a live_with_parent child after the map went flat and re-encoded a frozen 400-item list every pan frame with stale geometry ids (new tile meshes × old instance counts, tens of millions of triangles into a texture nobody read); make_child_pass records the recording list + redraw id, stale passes are skipped, a cached View re-attaches on a cache hit; tests for the orphan gate and the pool generation contract
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 18:22:02 +02:00
Admin
5184340565 platform + vj + map + files + widgets + image_tiles: the runtime owns one warm two-lane task pool — jobs never spawn threads
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 16:06:44 +02:00
Admin
83a8d4f69d fonts: the web demos start with the Latin set — CJK and emoji faces load on the first glyph that needs them
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-03 10:40:48 +02:00
Admin
d6d324144e map: round road caps are a fragment SDF, dead cap rows gone
A round cap was a hard disc fan of up to 32 vertices per road end with no
anti-aliasing; a Butt/Square start pushed a feather pair it never
indexed. The cap is now carried by the last body pair extended by half a
width, with uv.y = 1 + cap_axis, and the fragment computes the circle's
coverage with the same derivative-based AA as the band edge. Amsterdam
start view: casing 42.5 -> 40.4 MiB (shape 100 17.1 -> 16.5, shape 110
15.2 -> 14.5), tilted total 116.4 -> 114.3 MiB, flat 313.9 -> 311.7.
Cap edges gain AA; Metal hidden grab vs the head without it 1.23 % /
0.27 % start (label placement in the crops), web GPU gate clean
(CAP1 lane).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 01:04:31 +02:00
Admin
7a2c09a873 map: road-union faces on a 16-byte vertex
Shape-0 Boolean union faces (plazas, road bodies, tunnel and bridge
faces) leave the 28-byte road vertex for FaceVertexTyped: i16 anchor,
UNorm8x4 colour, F16x2 class/material + depth tick, F16x2 deck lift +
coverage. The road shader draws them through a second vertex format on
the same pass; face streams use u16 indices. Amsterdam start view:
casing 73.6 -> 58.7 MiB (42.5 casing + 16.2 face), tilted total
158.6 -> 143.7 MiB, flat 328.8 -> 313.9, 433 ms/tile. Metal hidden grab
within the noise floor of the head without it (1.26 % / 0.23 %, label
placement); web GPU gate clean. Faces now draw as one batch per tile
before the stroke bands, so a translucent shadowed face over a crossing
casing blends ground instead of stroke at that pixel — not visible in
the crops (FACE1 lane).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:48:11 +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
99d2180aad map: roofs on a 20-byte vertex, contact shadows as instances
Lifted shape-0 roofs leave the 48-byte universal vertex for a five-slot
RoofVertexPacked (anchor, unorm8 colour, exact metre height, f16
material | zbias ticks); DrawMapRoof reconstructs the fixed vector
channels and shares the colour pass, the fade, the LOD band and the
shadow-mask projection / footprint cut-out. Roof records that need more
(parapet AO depth variants, marker stalks) stay on the generic layout in
a fill_3d_misc stream. The tree and signal contact shadows are no longer
tessellated ten-segment discs in a vertex stream but four floats per disc
drawn as an instanced unit quad into the shadow mask, with the same
radial ramp.

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

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00
Admin
9d664ca967 map: roads on a 32-byte vertex
Casing, stroke and fringe records leave the 48-byte universal vertex for
an 8-slot road layout: full-precision anchor and deck height, f16 offset /
depth / tessellator uv pairs, unorm8 colour, and one f16 integer that
packs class, material, dash id, kind (stroke / union face / fringe) and an
explicit expanded flag. DrawMapRoad reproduces DrawMapVector's expansion,
terrain, tilt, space-warp and shadow-mask behaviour for those streams;
casing/stroke draw through it in the colour passes, the fade cross-fade
and the shadow-mask projection, and the space-warp subdivision has a
road-stride midpoint.

Harness: 339.0 -> 281.5 MiB for the 25 start-view tiles, 437 ms/tile.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:02:33 +02:00
Admin
02b58fc931 map: ground fills on a 20-byte vertex — position, colour, variant + AA coverage, depth ticks; DrawMapFill is the fill path of the map shader
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 22:02:33 +02:00
Admin
72b60b6d0c 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
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 22:02:33 +02:00
Admin
2d4ff16b93 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
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 22:02:33 +02:00
Admin
22faab2c8b Merge branch 'work' into webdemos 2026-09-02 15:30:29 +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
77d91385fc wm: the module contract and the first in-process app — sheets in a tile, in an isolate of its own
libs/app_module (makepad-app-module) is the contract (aicontrol §3):
AppModule (id, label, register into an isolate, an OpenSchema, create
into InstanceParts, capabilities), InstanceHandles (an InstanceScope
owner token, the storage jail as a cx.storage namespace, the viewport,
a ReplySink for calls that finish later), a ServiceExecutor addressed
apart from the root, and an OpenSchema that refuses raw paths — a file
is a handle the host issued or nothing. Only types live there.

The WM hosts one (module_host.rs): allocate the isolate, retint its
theme from the palette, register, create — one trusted entry into the
isolate, never a second &mut Cx beside the VM; teardown drops the root
first, runs shutdown in the isolate, frees it. MpModuleView is the tile
for an instance's root, drawing and dispatching with the isolate
INSTALLED on Cx (enter_isolate/leave_isolate, new in widgets) and
gating keys on the WM's focus; a TileHost trait covers both tile kinds
so the desk and the focus logic never ask which. The registry overlay
(apps.rs) links modules per app-* feature; the desktop default stays
Process, switched per app in ~/.makepad/wm/apps.splash or by a dev
--module flag. The bus gains its in-process leg: an instance is an
m<id> endpoint the pane addresses like any other — the leg the web
superbuild runs everything on.

sheets is lib + bin: SheetsModule mints MpSheets{} in the isolate and
answers sheets.summary on its executor; the standalone binary keeps its
Window and F10 overlay behind the standalone feature.

The drive found a platform bug: a shader compiled on a widget minted in
an isolate hit the draw-shader object cache by object index alone, so
an isolate's Button reused the main heap's entry and drew with zero
instance slots. The cache is keyed by (heap, object) in every backend,
and add_instance refuses a zero-slot draw call instead of dividing by
it. Isolate cost, measured (the P2 entry gate): 12 ms and ~8 MB per
isolate, flat to 32 — no pre-warming needed.

Verified by hidden grabs under the WM: /os.launch sheets → an
in-process Sheets tile (no child process), the apps row Desktop ·
Sheets, /sheets.summary answered through the in-process leg, a warm
terminal beside it, F10, close → the instance torn down and its isolate
freed. wm 145, sheets 84, app-module 3, services 33; platform and draw
check for windows-msvc, linux-gnu and wasm32.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 15:16:42 +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
d931f9d764 map: tile archive third pass — per-pass pruning, validated watcher metadata, shared blob bytes, timer watchdog, atomic cancellation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 13:14:57 +02:00
Admin
09b41a8dc9 fonts: FontSet and FontPolicy — one application choice, selected-only loading, a font-assets manifest
Latin (IBM Plex) is the web default, International (adds the CJK and emoji faces) the
desktop default; app_main! records the choice before widgets register, the theme only
registers the selected chains, a glyph miss never starts a load, and the resolved font
resources are emitted as the makepad.font-assets.v1 section for the packager.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WV6BzHQiJEvvK9EPc1d4ks
2026-09-02 12:40:50 +02:00
Admin
120b7e23ae score view: the engraver as a shared library, with drum and pitched score builders
libs/score_view carries the engraving, spacing, font and document code out of the score app so any app can show notation: a ScoreView widget with width/page/content fits, pan and zoom, a playhead, a dark palette, drum-key labels, lyrics under melody notes, and builders for drum, pitched and bass-tab scores. The score app uses it. Vector glyphs no longer write depth for transparent fragments, and the Metal screenshot staging sizes itself from the source texture.

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