Skip to content

feat: separate the ambient field and Graph Playground - #1

Merged
parvbansal11 merged 13 commits into
mainfrom
design/field-and-instrument
Aug 4, 2026
Merged

feat: separate the ambient field and Graph Playground#1
parvbansal11 merged 13 commits into
mainfrom
design/field-and-instrument

Conversation

@parvbansal11

@parvbansal11 parvbansal11 commented Aug 2, 2026

Copy link
Copy Markdown
Member

Outcome

Rebuilds the public site around two graph languages that never blur together:

  • the ambient field is a quiet, cursor-reactive topology with no product verdicts;
  • the Graph Playground is the deterministic instrument that shows PASS, BREAKING, witness, impact, and repair location.

The primary explanation remains exact: the schema passes, semantics fail at researcher to verifier, the witness is candidate-003, and verifier, decision_maker, and publisher are affected.

What changed after the exploration

  • Reworked section rhythm with asymmetric proof, terminal, limitations, contribution, and report compositions instead of repeating one panel pattern.
  • Replaced pointer repulsion with velocity-aware local physics. Slow movement gathers a temporary constellation. Fast movement opens a corridor and reroutes nearby edges. The graph settles after pointer exit.
  • Removed red cuts, green arrivals, and failure pulses from the decorative field. Only the foreground instrument asserts conclusions.
  • Expanded the playground to the complete four-node affected path and opens a trace-backed witness after the first break.
  • Corrected every public contract reference to the real provenance invariant: verified_requires_opened_supporting_source.
  • Limited the setup sheet to working uv, pipx, source, and LangGraph paths. Planned OpenTelemetry and GitHub Action options were removed.
  • Added technical proof, explicit limitations, contribution paths, and a focused final action.
  • Added source-linked proof.json plus CI checks for metrics drift, local links, JavaScript syntax, decorative canvas semantics, and the no-em-dash rule.

Final screenshots

Dark desktop Light desktop
Mobile Mobile setup sheet
Field at equilibrium Fast pointer split

Measured

Check Result
Lighthouse desktop Performance 100, Accessibility 100, Best Practices 100, SEO 100
Lighthouse mobile Performance 99, Accessibility 100, Best Practices 100, SEO 100
axe-core WCAG A and AA 0 violations at 320, 390, 768, and 1440 px across light and dark checks
Layout no horizontal overflow at audited widths; CLS 0; TBT 0
Pointer field under 4x CPU throttle p95 9.2 ms, p99 9.3 ms, zero interaction frames over 20 ms
Reduced motion static canvas, final instrument state and witness immediately visible
Initial JavaScript 37,774 bytes raw, 11,929 bytes gzip
Primary static payload 218,830 bytes raw across HTML, CSS, JS, proof JSON, and OpenGraph PNG
CI Static integrity passed

The site remains static, framework-free, font-free, analytics-free, and usable without JavaScript. The PR-media orphan branch is retained only for immutable review evidence so deployment does not ship multi-megabyte full-page screenshots.

Two graph languages, deliberately opposed. The ambient field is a live
force-directed graph: nodes drift under repulsion and edge springs, the
topology rewires itself, and semantic pulses travel it. Most arrive; about
one in four stops mid-edge, cuts, and marks its downstream path. That is the
world before GraphABI. Every product surface is the opposite by design -
precise, causal, and it comes to rest.

Canvas 2D with a hand-written simulation rather than a WebGL library: the
interesting work is the force model, not the rasteriser, and Three.js would
have cost ~600 KB against a documented performance budget for nothing.

Also fixes real defects found while rebuilding:

- light mode was broken. The header kept a hardcoded dark background, the
  wordmark 404'd on a missing logo-light.svg, and code text rendered near
  white on white. The palette is now two designed themes, not an inversion.
- the brand lockup is an inline mark plus HTML text, so it is theme-aware,
  costs no request, and no longer depends on Inter being installed.
- blast-radius edges stacked a green background under red dashes during the
  baseline phase. Edge state is now one `background`, so the replay cannot
  assert two states on one rail.
- architecture and report artwork were hardcoded-dark images that inverted
  wrongly in light mode and scaled their labels below legibility on mobile.
  Both are now components built from the same primitives as the page.
- the pulse now rests at a tokenised distance short of the cut, in both the
  horizontal and vertical topologies, instead of colliding with it.

Spacing is on a strict 8px scale, mobile is a rethought vertical topology
rather than rotated desktop, and reduced motion renders every state the
animation would have revealed.
Auditing the palette turned up contrast failures that the previous single
status colour could not avoid: --subtle failed on every dark surface, and
red text on the breaking tint landed at 4.06:1 against a 4.5:1 requirement.

Status colours are now split by role. --pass / --fail / --unknown drive
strokes, rails, node borders and the break mark, where 3:1 applies because
they are non-text UI. --pass-text / --fail-text / --unknown-text drive
anything set as small text, and clear 4.5:1 on every surface it can land on
including the status tints. The break mark keeps its full-strength red, so
the one high-saturation focal point in a graph scene is unchanged.

Also gives the horizontally scrollable code regions keyboard access, which
only affected narrow viewports where they actually overflow.

axe: 0 violations at 1440 and 390, light and dark.
Lighthouse: performance 99, accessibility 100, best practices 100, SEO 100.
The method rail is an edge, so step 03 now actually interrupts it: the rail
opens a gap and the canonical two-stroke mark sits inside it, instead of a
single slash floating unattached in the middle of a cell.

The closing call to action is centred. It was a 14ch headline pinned left
against roughly sixty percent dead space, and the honest fix is composition
rather than inventing decoration to fill it.

Also re-measures the segmented thumb and the field's obstacle rects once
fonts settle, since a late Inter swap changes both the label widths the
thumb is sized from and the text boxes the field routes around.

Measured: no frame over 20ms at 1440, 1920, or 390 with 4x CPU throttling.
The traversal rail and its section node were hidden until an
IntersectionObserver revealed them, so with scripting off every section
eyebrow lost its node and the rails never drew. The rail is structure, not
motion: it now renders by default, and only the arrival animation is
withheld, gated on a class the document sets for itself.

Lighthouse 100 across performance, accessibility, best practices and SEO.
CLS 0, TBT 0 ms, 29 KB gzipped for the whole page.
The baseline no longer resolves every edge at once. One pulse walks the
graph hop by hop, each rail filling green behind it, so the pass is shown
being earned rather than asserted. The candidate then leaves on the same
path and never arrives.

Adds a drain beat between the two runs. The graph previously cut from fully
resolved to empty in a single frame, which read as a glitch instead of a
second run starting clean.

Fixes the blast propagation, which was firing all at once: .is-playing had
narrowed the node transition list to opacity and transform, so border and
background snapped and the stagger delay had nothing to act on. Affected
nodes were lighting up ahead of the edges meant to be carrying the blast to
them. The blast now travels outward, edges leading nodes by one beat.
Nodes carry a depth value that drives radius, alpha, edge weight and drift
distance, so the field reads as a volume rather than a flat wireframe.

The graph now parts around the cursor, near nodes moving further than far
ones, which is what sells the depth. Coarse pointers are excluded: there is
nothing hovering to react to, and a touch would drag the graph around under
the user's own finger.

Still no frame over 20ms at 1440, 1920, or 390 with 4x CPU throttling.
The dialog's transform origin is computed from the trigger's position, so
the panel unfolds out of that node instead of arriving from nowhere. Falls
back to a centred scale when reduced motion is set or there is no trigger.
An audit across twelve widths from 320 to 1920 found system labels rendering
at 10px and the method-rail numerals at 9px, both below the 12px label spec.
Section-level labels now sit at the full 12px; the densest in-panel labels at
11px, where 12px would bloat the instrument panels.

Two consequences fixed with it: the step circles grew to keep the numerals
centred, so the rail that threads them moved a pixel; and the pipeline's
contract labels now wrap instead of running off a 320px viewport, which the
larger type exposed.

No horizontal overflow and no text under 11px at any of the twelve widths.
The roadmap was the one section still speaking list instead of graph. Each
planned item now sits behind a hollow node on a dashed stub: an edge that
does not reach. Hovering completes it in amber, the unknown colour, because
that is exactly the claim being made. Planned is now visible before the
label says so.
The panel was mostly empty space around a thin graph. Both nodes now carry
their actual content: the producer's recorded output and the consumer's
contract, side by side. Switching to the candidate changes exactly one
number, from 1 to 0, and colours it, so the claim the section makes is
visible in the graph before the check is even run.

The edge now names the contract being evaluated rather than repeating the
consumer node's label, and long contract identifiers wrap instead of running
off a narrow viewport.
@parvbansal11 parvbansal11 changed the title feat(site): semantic field visual redesign feat: separate the ambient field and Graph Playground Aug 4, 2026
@parvbansal11
parvbansal11 marked this pull request as ready for review August 4, 2026 18:50
@parvbansal11
parvbansal11 merged commit 7304d6c into main Aug 4, 2026
1 check passed
@parvbansal11
parvbansal11 deleted the design/field-and-instrument branch August 11, 2026 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant