Skip to content

FE-1552: Make the sweep drawer a live control with rastered, eased distribution views - #9478

Merged
kube merged 44 commits into
claude/fe-1552-sweep-view-fixesfrom
claude/fe-1552-frame-popover-raster
Sep 3, 2026
Merged

FE-1552: Make the sweep drawer a live control with rastered, eased distribution views#9478
kube merged 44 commits into
claude/fe-1552-sweep-view-fixesfrom
claude/fe-1552-frame-popover-raster

Conversation

@kube

@kube kube commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Important

Experimental
Adds the Parameter sweeps and Optimization surface feature flags.
Frame inspector histogram and heatmap bin extents ship for everyone.

Summary

Before this PR, sweep drawer visuals lagged its compute. Frame inspector listed one DOM row per bin behind a scrollbar, the contour surface was click-only, the summary showed one inherited progress bar, and distribution heatmaps striped and flashed where GPU-binned frames met exact frames. Sweep session, provider, GPU backend and timeline code sat in multi-concern files, and no setting gated the sweep or surface features.

This PR draws the inspector's distribution as a canvas raster, makes the surface a drag control, lists every computing batch in the summary, paints heatmap bins by their declared extent with eased updates, and keeps the drawer's layout still while runs stream. It splits that code into single-concern modules documented in the architecture docs and adds the Parameter sweeps and Optimization surface settings.

9478.mp4

Measured on the Bench / SweepDrawer stories after a slider commit:

Case Before After
Mean per-sample change, CPU (already-drawn left 40% of the first chart, sampled every 75 ms) 5.7 4.2
Mean per-sample change, GPU (same sampling) 14.4 11.2
Elements shifting through a fill, a slider commit and the restream (every element's box, every 100 ms, CPU and GPU) none

Links

Changes

Frame inspector and heatmap

  • Popover's histogram is a canvas in a fixed 104 px box

    Adjacent rectangles with no gaps, a value axis and a count axis.
    bin-histogram-raster holds the geometry as pure functions.

  • Bins narrower than a pixel merge into one column

    Column is drawn at samples-per-bin, so uneven merges do not spike. A bin with samples keeps at least one pixel of height.

  • Distribution frames carry binExtent in core

    GPU histogram windows declare a stride's reach around its labelled count, width binning declares [label, label + width), exact bins declare nothing and take one lattice step.

  • Heatmap spreads each bin's count over the rows its extent covers

    It never infers a width from which values a frame happens to occupy, so a two-mode frame stays two modes.

  • Updates within one selection are eased

    Each new grid blends with the one on screen at 0.5 per step, resampled by value when the lattice moved, then settles over three 100 ms redraws to the exact target.
    A GPU tile or a pipelined rung folding in mixes in instead of snapping.

  • New selections start from their own data

    Blend baseline is keyed on the content epoch.

  • Adds the Simulate / FramePopover and Simulate / ExperimentMetricTimeline → Mixed bin lattices stories

Surface drag

  • Surface is a drag control

    Press shows a crosshair with the parameter values under the pointer; release commits both axes there. Crosshair is a CSS overlay, so pointer moves never repaint the raster.

  • Orange ring marks the navigator's position at the nearest sampled cell
  • One pointer id is armed at a time

    touch-action: pan-y keeps vertical swipes scrolling; lostpointercapture cleans up.

  • Optimization surface shares the interaction through use-surface-drag

Summary, batches and layout stillness

  • Sweep session exposes every computing batch as sweepBatches

    Registry covers ladder rungs, surface chunks and cell refinements.
    Summary shows an "N computing" chip that expands into rows with their own progress.

  • Progress bar means the selected combination's runs over the run budget

    Same in the drawer and the top-bar popover.

  • Sweep publishes are throttled to 100 ms
  • Nothing in the drawer moves when a run starts, streams, resumes or finishes

    Stat strip reserves each value's widest text and always shows the errors stat. Batch toggle and sampling spinner keep their slots while idle, the footer's Cancel keeps its footprint when disabled, and surface captions are one fixed-height line.

  • Metric tiles render from the metric specs in a fixed order

    Chart shape is known before the first frame.

  • Time stat shows the end time once a sweep's selection saturates

    It showed 0.

Settings

  • Two settings are added under Simulation

    Parameter sweeps adds the per-parameter Sweep toggle to the experiment form, the only way a sweep can start. Optimization surface shows the study drawer's Surface section and its local compute.

  • With both off, nothing sweep-related is reachable

    Sweep form controls, drawer sections, idle status and batch list are unreachable, and a study drawer runs no compute of its own.

Module split

  • Sweep session and experiments provider become folders of single-concern modules

    sweep-session/ and provider/.
    Provider splits into experiment creation, detached objective, records, batch instantiation and backend lanes.

  • GPU backend splits into shader, handle and runner folders

    compile-net-shader/ has one file per shader concern, gpu-experiment-handle/ holds run parameters, calibration and frame merge, runner/ holds device, tiles, seeds and histogram frames.

  • Metric timeline and drawer split the same way

    Timeline: use-metric-plot/, distribution-heatmap/, view state, controls.
    Drawer, view-experiment-drawer/: summary, metrics, compute activity.

  • Shared pieces move to shared/ folders

    Colour ramps, surface sampling and axis formatting, the surface frame, the progress-percent rule.

  • New architectural units declare their layer

    core.webgpu.shader, react.experiments.sweep, ui.contour-surface.

  • Removes the restream-ghost switch and the superseded per-cell paths

    Dim is the one behaviour.
    sampleSweepCell and compileParameterValues are gone, replaced by the batch paths.
    Behaviour and bench timings are unchanged.

Behaviour changes carried on purpose

  • Surface batching compares initial markings at cell values, not grid indices
  • Fixed-value parse errors for swept parameters drop by identifier, not message prefix
  • Optimization walk restarts only when its slice or axes change

    No longer on every record update.

  • Late calibration writer no longer replaces a cached entry with larger slabs

Review fixes

  • Disposed sweep session unsubscribes from its background batches' progress

    A cancelled or removed experiment no longer patches state until those batches finish.

  • Pinned per-run seeds ride the run plan and the core expander attaches them

    Replaces the provider's own record expansion and its second boolean encoding.

  • GPU frame merger judges re-delivery against the previous chunk's high-water mark

    Two metrics sharing frame numbers in one chunk keep the cheap append.

  • Y-ceiling ratchet resets on every view change
  • Optimization surface keeps every cell a selection refined until the walk changes
  • Single-consumer modules move beside their consumers

    Pages and comments the split left stale are corrected.

  • GPU: config uniform buffer is padded to its 16-byte struct size

    Pair-consumed typed places stay below the f32 unranking limit; tokens produced earlier in a frame compact down with the survivors.

  • GPU: backend cache can be disposed and drops a lost device

    Lease bookkeeping stays on the entry it leased. GPU creation honours the instantiation abort signal.

  • GPU: per-run values that overflow f32 and pinned-seed plans are refused
  • Sweeps: a failed sweep stays in error

    Disposing a session cancels its background batches; the surface gate opens on in-flight frames.

  • Sweeps: integer axes draw uniformly; axis readouts keep adjacent positions distinct
  • Surfaces and drawers: optimization surface resets per study

    It uses prototype-free records; both drawer bodies pin their fixed sections.

  • Provider disposes an experiment's backends with it

    Changesets are one per PR.

Known issues

  • Ad-hoc worksheet edits fixed values only, so sweep ranges are unreachable while the experimental ad-hoc scenarios setting is on

Next steps

  • GPU backend support for string and uuid attributes and for transitions with several input or output places. Shader split keeps each in one file: compile-net-shader/token-layout.ts, transition-firing.ts and output-emission.ts

Test coverage

  • bin-histogram-raster.test.ts:

    Gap-free tiling, sample conservation under merging, level uneven merges, axis ticks and labels.

  • distribution-heatmap.test.ts, density-grid.test.ts and display-easing.test.ts:

    Resolution and normalisation, mixed lattices with stride-2 beside exact and width-binned from the lower edge, a two-mode frame staying two modes, ulp-scale gaps keeping every bin, blending and the ease-then-settle sequence.

  • sweep-session.test.ts:

    Batch registry with selection first, successor joining, batches dropping and dispose clearing.

  • batch-registry.test.ts:

    Publish on register and unregister, throttled progress ticks, no publishes from a cleared registry.

  • create-experiment-drawer.test.tsx:

    Sweep toggle appears only with the parameter sweeps setting on.

  • viewport-settings-dialog.test.tsx:

    Both settings default off.

  • expand-run-plan.test.ts:

    Pinned seeds on a plan, with and without ids.

  • frame-merge.test.ts:

    High-water mark across two metrics.

  • Suites beside the split modules:

    calibration, frame-merge and run-parameters for the GPU handle; device, tiles, seeds and histogram-frames for the runner; expand-run-plan and worker-pool-experiment-backend; reusable-worker-factory; sweep-cell-objective; contour-field; surface-sampling; experiment-progress; metric-frames; view-state.

  • Bench / SweepDrawer stories driven with Playwright:

    Drag interaction, activity list, heatmap easing and layout stillness.

How to test

  • Open Petrinaut preview on Vercel
  • Viewport controls > Settings > Simulation > Parameter sweeps, Optimization surface
  • Load example > Café Queue
  • Simulate > Experiments > Create
  • Expect a Sweep toggle on every numeric scenario parameter
  • Sweep two parameters, Run
  • Summary > "N computing" chip
  • Expect batch list expanded, progress bar reading the selected combination's runs over the run budget
  • Press and drag on the surface
  • Expect crosshair following with values in the caption
  • Release
  • Expect navigator jumping there, charts restreaming and easing in rather than snapping
  • Click a metric chart
  • Expect histogram fitting its box with touching bars and labelled axes, heatmap band continuous with no alternating rows
  • Watch the drawer through the whole run and after a slider commit
  • Expect summary, parameter and surface sections holding still while values change, footer buttons not moving when Cancel goes away
  • Open a study drawer on a deployment with the optimizer service, /optimization route
  • Expect Surface section present and responding to press-and-drag
  • Local fallback for a study: turbo run dev --filter @apps/petrinaut-website -- --with-optimizer-service

Demo

Screenshots pending (will be handed over for drag-drop).

@kube kube self-assigned this Aug 31, 2026
@vercel

vercel Bot commented Aug 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Sep 3, 2026 6:38pm UTC
petrinaut Ready Ready Preview Sep 3, 2026 6:38pm UTC
petrinaut-docs Ready Ready Preview Sep 3, 2026 6:38pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 3, 2026 6:38pm UTC

Request Review

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/apps > hash.design Affects the `hash.design` design site (app) labels Aug 31, 2026
@kube kube changed the title FE-1552: Draw the frame popover's distribution as a canvas raster FE-1552: Make the sweep drawer a live control with rastered, eased distribution views Sep 1, 2026
@kube
kube changed the base branch from claude/fe-1552-parallel-orchestration to claude/fe-1552-sweep-view-fixes September 1, 2026 23:16
@github-actions github-actions Bot added the type/eng > backend Owned by the @backend team label Sep 1, 2026
@kube
kube force-pushed the claude/fe-1552-frame-popover-raster branch from eb92d31 to 9b9cbd8 Compare September 1, 2026 23:17
kube added 28 commits September 3, 2026 18:27
The compute activity list sits under the summary that renders it, the range-draw translator under the batch instantiator, pair selection inside the shader generator, and the bin-value summary under the plot hook that reads it. The session stops re-exporting the cell helpers only its own modules use, and the translator's random-draw oracle test becomes a fixed two-run fixture.
Seeded batches no longer expand their plan into run records in the provider with a second boolean encoding; the plan carries the seeds and the core expander attaches them.
…erimental settings

Both are off by default. Without the sweeps setting the experiment form offers no Sweep toggle, so every experiment takes fixed values and no sweep session, navigator, surface or batch list can appear. Without the surface setting a study drawer shows no Surface section and runs no local compute.
A batch failure now rides on the session update, so the idle publish that follows it no longer overwrites the error status. Disposing a session cancels its background batches through their handles instead of letting them run to completion. A draw-build failure and an error before the first frame both release the surface's waiters, and a stale generation's error no longer marks the replacement selection failed. The surface gate opens on in-flight frames, not only on completed runs.
…bodies

The surface is keyed by study id, so axis choices, slider positions and the sample cache no longer carry over to another study; its parameter records are prototype-free and its refinement effect depends on the study's id and input rather than the whole streamed record. Both result drawers hide overflow on the overlay body so only their lists scroll.
Axis readouts derive their precision from the axis step, so adjacent positions of a narrow interval never display the same value. Integer axes draw one equal-width bucket per value instead of rounding a continuous draw, which gave the endpoints half the share of interior values.
… by the pool

The provider keeps the backends an experiment chose and disposes them when the experiment's handle or sweep session goes, so a finished GPU experiment releases its device. A wide background lane takes at least one worker, never two, so three lanes do not exceed the pool on small machines.
@hash-release hash-release Bot mentioned this pull request Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

6 participants