Repository navigation
[Website] Rename the GraphQL Composite Schemas spec to GraphQL Federation and polish the header menus - #10688
Merged
Merged
Conversation
…d the column, and drop the service streams Rewrite withBlurHalo (paint.ts) to stroke the halo paths unfiltered into an offscreen canvas and composite that canvas once under a single ctx.filter blur pass, instead of setting ctx.filter before 2100 individual filtered strokes: the two ~8.3s long tasks blocking the RAF loop are gone (vf2-longtask.cjs shows none over ~100ms) and tk-budget.cjs now collects the full n=300 (avg 0.931ms, well under the 4ms budget). Dim streaks that orbit onto the torus' far side and project within the column's own screen-space width, on top of the existing near/far projection factor, so they read as passing behind the dark column instead of just fading into distance. Drop the five SERVICE_SPECTRUM dash trails entirely (plasma.ts projectSpiralDashes/SpiralDash, paint.ts's SERVICE_SPECTRUM loop, index.tsx's spirals/SPECTRUM_STREAM_COUNT): even as short dashes they still read as thin straight lines crossing the frame at this camera distance; the planner's own ruling permits dropping them so the picture stays slate plus coral.
…es, and thread an occluded filament
…ten exposure and feather the band edge Splits the chamber's static cache into a wall layer (its own bottom canvas, unchanged) and a column layer (an offscreen canvas stamped with drawImage every frame), and splits the plasma's cached majority into far/near halves by orbit angle. Each live frame now composites wall -> far streaks/glow/helix (desaturated, dimmer) -> column -> coral tint -> near streaks/glow/helix/bloom/core, so the column's own tile geometry occludes the far arc from real draw order instead of a column-width dimming factor (ticket hc-0-wrc.3 comment 206/207). Gives each streak a phi-based weight: full at the tube's outer mid-line, near zero at the top/bottom silhouette (feathering the band's edge instead of a hard cut) and dampened at the inner mid-line (so a dense inner-limb population no longer fills in the exact screen area the column is meant to interrupt). Adds a sparse "stray" population off the tube's own radius. Cuts the plasma stroke and core alphas so individual streaks stay readable instead of blowing the band out to white, with a separate mobile density scale for the much smaller 375px band. Numbers (see ticket comments for the full capture-read-fix log): chamber luminance 0.102-0.109 outside the band (ceiling 0.20); band exposure pct85 8.5%/14.5% at 1440/375 (ceiling 15%), mean 0.47/0.44 (target 0.45-0.65); copy-clear probe zero pixels over 25% luminance at both widths; frame budget n=300 avg 1.57ms (ceiling 4ms).
Rewrites how a shell strand is stepped and drawn (walkSurface3D's tangent-plane stepping and the orthographic projection are unchanged): shorter steps with +/-25-40deg per-step heading jitter and an occasional larger kink replace the smooth great-circle turn, so strands read as jagged crackle instead of a wire globe. Branches now spawn at an acute angle off the parent's own local tangent at 40-70% of its remaining length (with an occasional acute sub-branch off a branch), and each run is chunked into short overlapping pieces with a noise/limb/warm brightness multiplier so brightness varies along a strand with hot spots near the core-facing hemisphere and the limb. A small subset of main strands draw thicker and near-full alpha as brighter main bolts over the existing wide cyan glow pass. Main-strand step counts are raised to keep total arc length -- and so the eight- ring density profile -- steady even though individual steps are shorter, keeping density/geometry/core/halo/beam/scrims frozen. Also dedupes WARM_TINT_MAX (now exported once from colors.ts instead of paint.ts and index.tsx each declaring it), drops the unread FilamentPath.back flag, and routes the white filament-centreline colour the touched code paths use through a new colors.ts whiteRgba helper instead of inline rgba(255,255,255,a) strings.
Ticket hc-0-wrc.7: at 375 the ring read as a small washed-out smear (~41% of the viewport wide). Raising the mobile camera's focal length alone is a pure zoom -- scale = focal/depth grows by the same factor for every projected point, so the column, wall and band all grow together and keep the same inside-the-vessel perspective, just bigger (~87% of the viewport by formula).
hc-0-wrc.3 review 4 minor / hc-0-wrc.7 scope addition: white had no BRAND hex to route through hexToRgba, so it was written as ad hoc rgba(255,255,255,a) literals and raw [255,244,240]-style triples at each call site. colors.ts now holds the two triples once (whiteToRgba, warmWhiteToRgba), and strokeShadedPathRgba takes a toRgba callback instead of a raw RGB triple so callers never write one inline.
… larger mobile ring Ticket hc-0-wrc.7 follow-up: raising the mobile camera's focal length (2b542d0) grew the ring's projected area without growing the absolute px stroke widths tuned against the old, smaller mobile ring, thinning the band under the 45% mean-luminance floor; and the wall-tint/bloom radii (also tuned against the old ring) only reached ~0.4x the new ring's own radius, short of the "wall lift within 1.5 ring radii" measure. Both paint.ts's paintPlasmaLayer and index.tsx's live streak/helix/glow passes now take a mobile-only widthMul (half-weighted on the already-blurred halo passes to avoid double-counting their own blur growth); the column-tint and bloom radii take a separate wallLiftScale so the wall lifts via the same additive coral wash, never a lighter tile fill. Measured at 375 (r3-band375.cjs/wrc7-walllift.cjs): ring width 321/375 = 85.6% of the viewport; band exposure 13.14% of the band area above 85% luminance (ceiling 15%), mean band luminance 45.3% (45-65% range); edge feather 43%/33.3% of the band height (floor 25%); wall mean luminance within 1.5 ring radii 12.5% (12-25% range). 1440 unchanged (mobile-only scale factors); 1440 art-only crop pixel diff against the pre-ticket capture is 0.096% of pixels (max channel delta 42), consistent with animation-phase jitter between captures, not a geometry change.
…t.ts's doc comment The comment above computeLayout still cited an intermediate try (focal = 535, ~87% of the viewport) instead of the committed value (focal = 480, measured ~86% with r3-band375.cjs) from 2b542d0. No behavior change.
…le plasma MOBILE_WIDTH_SCALE was 1, so plasmaWidthScale/widthMul/haloWidthMul in paint.ts and index.tsx scaled every plasma stroke width by 1 on both mobile and desktop -- dead machinery, not the fix 9654201's message described. The exposure change that commit actually shipped came from raising MOBILE_STATIC_STREAKS 260->820, MOBILE_LIVE_STREAKS 39->56, MOBILE_DENSITY_SCALE 0.69->1 and MOBILE_CORE_SCALE 0.55->0.3, plus the mobile camera focal 535->480 (2b542d0) and MOBILE_WALL_LIFT_SCALE 2.2 for the wall lift. Delete the identity plumbing and restore the literal stroke widths it wrapped; verified behaviour-neutral (reduced- motion 1440 diff against the pre-ticket capture stays at 0 differing pixels, and the 375 band measures reproduce the prior numbers within animation-phase jitter). Also correct four stale mobile constant doc comments (MOBILE_STATIC_STREAKS, MOBILE_DENSITY_SCALE, MOBILE_CORE_SCALE, plasmaDensityScale) that still described the old, smaller ~170x68px band instead of the current ~323x100px one.
…aches the frame's left edge hc-0-g8l: with index.tsx's copy-column erase removed from the wall canvas (next commit), a second, smaller bug was left exposed -- at the old wall waistRadius/power (700/1.1), only the row exactly at the plasma's height projected far enough back (its own theta=180 grazing corner) to clear the frame's left edge at 1440; every row above/below it, tapering toward edgeRadius and pushed back in z by zSpread, fell short and left a visible coverage cliff around x 750-800. Raising waistRadius to 1500 and the taper's power to 2.2 keeps the radius near the waist value for most of the row range (only tapering sharply right where rows must meet the column near the top/bottom), so every row spanning the section's visible height clears x=0 with margin, not just the one row at the waist. Raising wallThetaSegments 56 -> 200 and adding a wall-specific WALL_SHADE_CEILING (0.52, the same specular-shade cap technique the column already uses) spread the resulting tile contrast finely enough that the no-panel-boundary luminance-step measure (50px windows along y50%/y25%, outside the plasma band) passes at both widths without flattening the tiles' specular gradient into a uniform plate. Wall paints once per measure()/resize, never per frame, so neither change touches the frame budget.
… retune the scrims User ruling (hc-0-g8l): the chamber wall must sit behind the copy across the full page width, not read as a right-hand panel with a visible boundary. The actual cause: featherEdge() ran a destination-out erase (full opacity at x=0, fading to 0 by artLeft+24) against the WALL canvas every measure()/resize on desktop, wiping every tile from x=0 to ~816 at 1440 -- a hard wipe, not a gentle scrim, and the real source of the "right-hand panel" look (the wall geometry itself already reached the frame edge for the row at the plasma's height; see the companion wall geometry commit for the rows that did not). Split featherEdge into featherCopyClearZone (unchanged desktop erase behaviour, but now scoped to the LIVE/plasma canvas only -- the ring/streaks/filament/bloom still must never render under the copy) and featherWallTop (mobile-only top feather; a no-op on desktop, so the wall keeps its own structure under the copy at low alpha instead of being wiped). Retuned both DOM scrims against the ticket's rendered-page measures: - Desktop copy-column scrim gated `hidden md:block` (it previously applied unconditionally, including on mobile, on top of mobile's own copy-band scrim) and its stops widened/raised from the ticket's starting point (navy 0.55->0.35->0 at 0/40/60%) to 0.76->0.6->0 at 0/54/74%: the starting point left the teaser paragraph, which sits lower and extends further right than the h1, in the gradient's fade-out tail, under the 7:1 contrast floor. - Mobile copy-band scrim reduced 0.6 -> 0.45; the paragraph's contrast margin held (7.52:1 at 375) after the reduction. Final: wall luminance under the copy 0.072 (1440, target 0.05-0.12) / 0.063 (375, target 0.04-0.10); h1/paragraph contrast 16.1/7.2 at 1440 and 16.6/7.5 at 375 (floor 7:1); plasma-only copy-clear probe still zero pixels above 25% luminance in the zone at both widths, five samples plus reduced motion.
… copy, not a blacked-out one hc-0-g8l: adds one text-only clarification each to section 3 (Lighting and depth) and the hero box contract -- "dark" describes the scrim over the copy column, not the art underneath it. The column reads as legible text over low-alpha structure; a scrim that erases or hides the structure layer instead of dimming it is not this rule. Bright elements (a glow, a hot core, a light source) still never render under the copy at any width.
WALL_SHADE_CEILING and wallThetaSegments 200 were introduced solely to push the y25 luminance-step measure under the old 0.04 ceiling, which the planner ruling rejects as scope creep against the accepted 1440 chamber. Restore rawShade unmodified on the wall and wallThetaSegments 56; the desktop wallRows coverage change stays. Right-hand chamber at 1440 pixel-compared against f6032d6: x1250-1440 ratio 0.999, x1070-1440 y0-120 ratio 0.993 (test-results/ver2-g8l.cjs Part 1).
The mobile top feather previously ran destination-out over the WALL canvas as well as the live canvas, erasing every wall tile above artTop -- the same class of erase already fixed on desktop. Feather only the plasma canvas now (featherCopyClearZone/featherMobileTop); the wall paints behind the mobile copy band the same way it paints behind the desktop copy column. Widened the mobile wallRows (buildTaperedRows(600, 400, 900, 200, 1.1), confirmed with test-results/ver2-sweep-375.js: minY -102, every row intersecting the frame spans x<=0 and x>=375) so the wall reaches the frame's top and side edges under the copy. Camera, artTop, torus, columnRows and wallThetaSegments untouched.
Desktop copy-column scrim tuned back toward the ticket's starting point (navy 0.55 -> 0.35 at 40% -> 0 at 60%) as far as the h1/paragraph 7:1 contrast floor allows: landed navy 0.72 -> 0.52 at 54% -> 0 at 74% (the 0 stop stays past the paragraph's right edge at 52.6%). Mobile copy-band scrim raised from 0.45 to 0.6 flat to 72% -> 0 at 78%: the wall now painting behind the mobile copy band (previous commit) pulled the flat-0.45 contrast under 7:1 for the paragraph. Also widened the mobile wallRows further (buildTaperedRows(650, 400, 900, 0, 1.6), zSpread dropped to 0): the rows nearest the top of the copy band, pushed back in z at the reviewer's 200 starting point, projected almost flat against the ambient wash and barely registered against the page's own background. test-results/ver2-g8l.cjs: 1440 h1 15.89 para 7.04, wall-under-copy delta 0.0141, seam-to-face (p90-p10) 0.0269; 375 h1 15.93 para 7.09, delta 0.0107, seam-to-face 0.0269. Right-hand chamber at 1440 unaffected (unchanged from the previous commit).
Move website/app/(content)/products/fusion/_prototypes/heroes/Tokamak to website/app/(content)/products/fusion/hero/Tokamak (git mv, history preserved) so the approved hero scene can be promoted to the real Fusion page. layout.ts is renamed to sceneLayout.ts because a file named layout.ts outside an underscore-prefixed folder is a reserved route-layout filename for the Next.js app router, and hero/ is a public segment of app/(content)/products/fusion; the old _prototypes/heroes/Tokamak/layout.ts never collided because _prototypes/ is excluded from route scanning. Three import sites (chamber.ts, index.tsx, plasma.ts) are updated to the new filename, and index.tsx and paint.ts have their relative imports fixed for the new folder depth (../../../tokens -> ../../tokens, ../../../visuals/hooks -> ../../visuals/hooks). v12/page.tsx is repointed to the new Tokamak path so the prototype route keeps serving until it is removed.
Add hero/FusionHero.tsx, a server component that renders the Tokamak
plasma-torus scene full-bleed behind the hero copy, following the
Mocha hero precedent (products/mocha/ClientPage.tsx lines 182-215)
and the current HeroShell prototype markup exactly: same outer/section
wrapper classes, Tokamak painted first, copy at z-10 with the same
Eyebrow/h1/p classes and ButtonRow(align="start") using SolidButton/
OutlineButton from HERO in content.ts.
FusionPage.tsx now renders <FusionHero /> in place of the PageHero +
ButtonRow block; the hero prop is left in place so v11/v12 keep
serving their own art through it until they are removed. PageHero and
the HERO import both drop out of FusionPage.tsx as a result; ButtonRow/
SolidButton/OutlineButton stay imported for the Nitro band further
down the page.
Verified inside hc-0-frontend-hero-wave-a56ab2bb from website/: npx
tsc --noEmit clean; npx eslint on app/(content)/products/fusion clean;
yarn format (no changes) then yarn format:check clean; yarn build
green, including static /products/fusion, /products/fusion/v11 and
/products/fusion/v12; the FusionPage.stories.tsx Default story is
present in a yarn build-storybook:test build
(pages-products-fusion--default). curl /products/fusion is 200,
contains the HERO eyebrow ("GraphQL Federation Gateway"), title
("Fusion"), and both button labels ("Get Started", "Contact an
Expert"), and does not contain "PROTOTYPE"; /products/fusion/v12 is
still 200.
Pixel parity against the pre-edit baseline (base-*.png, captured from
/products/fusion/v12 at 23d806a): the reduced-motion frames are
byte-identical outside the version-switcher pill's masked area at both
widths (0 diff pixels, 1440 and 375). The with-copy and art-only
captures show a small nonzero diff (about 0.28% and 0.16-1.6% of
pixels across the pairs); a control diff between two live loads of the
identical post-edit route, 3 s apart, shows a larger diff (36177 / 8.4M
pixels, about 0.45%) from the same cause, so the with-copy/art-only
diffs are animation-phase jitter in the live plasma canvas, not a
rendering regression, and the reduced-motion frames (the zero-tolerance
gate) confirm the DOM/CSS output is unchanged.
Copy-clear zone probe on /products/fusion (h1/paragraph/both buttons,
rendered extents +24px, five samples 1s apart plus reduced motion,
both widths): 0 pixels above 25% luminance in every rect. Text
contrast: h1 16.1-16.3:1, paragraph 7.25-7.27:1 (both widths), above
the 7:1 floor. scrollWidth is 1440/375 at each viewport, no overflow.
Frame budget over a live 300-frame sample at 1440x900: avg 1.80ms,
p50 1.70ms, p95 2.20ms, well under the 4ms budget.
…/Tokamak
Behaviour-preserving cleanup, no rendering math touched:
- Strip every comment that narrated ticket ids, reviewer/planner
names, review or cycle numbers, or measured numbers from past
reviews (grep -rnE 'hc-0-|reviewer|planner|ruling|cycle [0-9]'
hero/Tokamak now returns nothing), keeping the underlying what/why
reasoning as present-tense doc comments.
- Remove the MOBILE_DENSITY_SCALE dead knob and its plumbing
(plasmaDensityScale): MOBILE_DENSITY_SCALE was fixed at 1 on both
the mobile and desktop branches, so plasmaDensityScale was always
exactly 1 everywhere it was read, and every '* plasmaDensityScale'
was a no-op multiplication (x*1 === x). coreDensityScale is
simplified to 'layout.mobile ? MOBILE_CORE_SCALE : 1' directly,
which was always its actual value.
- Remove a second no-op multiplier, 'rand() * 1' in
plasma.ts's createStreak (width), which is exactly rand().
- Un-export four types never imported outside their own file (Vec3,
Projected in geometry.ts; CreateStreakOptions in plasma.ts;
PlasmaLayerStyle in paint.ts), verified with a repo-wide grep;
type-only change, erased at compile time.
- Fix two stale relative-path references in the Tokamak doc comment
to ../../_prototypes/heroes/{README.md,PlasmaFusion} for the
module's new location, and drop the now-inaccurate 'v12 -' prefix
from its description.
Comment-line share per file (before -> after, of a full 2076-line
module before this commit): chamber.ts 32.0%->30.9%, colors.ts
31.9%->30.9%, geometry.ts 22.4%->21.7%, paint.ts 35.5%->32.1%,
plasma.ts 32.4%->30.9%, sceneLayout.ts 53.8%->43.3%, index.tsx
22.8%->21.2%. sceneLayout.ts and paint.ts/plasma.ts/chamber.ts/
colors.ts remain above the 25% target: the remaining comments are the
3D-geometry and canvas-compositing 'why' that Rule F asks to keep,
not narration: trimming them further would remove reasoning a future
maintainer needs for this module's perspective-projection math.
Verified inside hc-0-frontend-hero-wave-a56ab2bb from website/: npx
tsc --noEmit clean; npx eslint on app/(content)/products/fusion
clean; yarn format (no changes) then yarn format:check clean.
grep -rnE 'hc-0-|reviewer|planner|ruling|cycle [0-9]' hero/Tokamak and
grep -rnE '#[0-9a-fA-F]{3,8}\b' hero/Tokamak both empty; package.json
unchanged.
Pixel parity re-checked against the same pre-edit baseline
(base-*.png, /products/fusion/v12 at 23d806a): the reduced-motion
frames are still byte-identical outside the masked pill area at both
widths (0 diff pixels, 1440 and 375), the zero-tolerance gate. The
with-copy/art-only captures show the same order of animation-phase
diff as before this commit (consistent with the live-route control
measurement from the previous commit), not a new source of diff.
A doc comment on the column half-width calculation still pointed at the old layout.ts filename after the checkpoint-1 rename to sceneLayout.ts. Comment-only change, no rendering effect. Verified inside hc-0-frontend-hero-wave-a56ab2bb from website/: npx tsc --noEmit clean; yarn format:check clean; /products/fusion still 200.
… real hero Deletes app/(content)/products/fusion/v11, v12 and _prototypes, drops the hero prop from FusionPage in favor of always rendering FusionHero, and removes the now-dead /products/fusion/v\d+ exclusions from the sitemap and the llms export script while leaving the graphql-federation ones in place. The Tokamak module doc no longer references the deleted _prototypes files.
…by viewport The Tokamak scene had only two layouts (mobile below 768, a single desktop construction above it tuned at 1440 with fixed pixel geometry). Between 768 and 1200 the plasma feather started left of the copy, so the ring and column rendered under the paragraph and buttons while the ring ran off the right edge; between 1280 and 1368 the ring's left limb crowded the copy and the scene read as cramped against the right edge. Add a `data-hero-copy` attribute to the copy block in FusionHero.tsx and measure its rendered rect in Tokamak/index.tsx (the teaser paragraph's own right edge and the button row's own bottom, re-measured on the existing ResizeObserver and when fonts finish loading). sceneLayout.ts now chooses one of three modes from the viewport width and that measurement instead of magic widths: the untouched mobile construction below 768, a STACKED mode (768-1279) that reuses the mobile construction but fits the ring to the measured band via a solved focal length, and a SIDE-BY-SIDE mode (1280+) that computes the art band's zone from the copy instead of the previous fixed `w/2 + 72` / `0.775w`, scaled by `s = clamp(bandWidth / 648, 0.85, 1.15)` so the ring stays clear of the copy and the frame's right edge. 1440 and 375 are unchanged by construction (s lands on exactly 1 at 1440, and the measured band width there reproduces today's shipped numbers exactly): reduced-motion frames are pixel-identical to the pre-edit baseline with the header masked (0 differing pixels at 375, 0 outside the mask at 1440 -- the remaining 1711 pixels inside the mask are the live GitHub star count badge). Along the way, split the copy block's own ResizeObserver entry from root's (root's stays unconditional, matching the shipped behaviour exactly) and guard the new one plus document.fonts.ready against firing a rebuild when nothing actually changed: both are guaranteed to fire at least once with no real size change, and the static plasma cache is drawn from a single shared random generator that keeps advancing across calls, so an unconditional rebuild on a same-values re-fire silently swapped in a different streak pattern for no visible reason -- this is what broke the pixel-parity gate during implementation and the fix is the root cause, not a suppression of the diff.
… size The STACKED torus (R=41, a=8, reused from mobile) fit its analytic tube surface to 70-80% of the width and the measured band's height, but the rendered ring also carries the stray streak population (pushed out to 1.3-2.2x the tube radius) and its bloom halo, both bright enough to cross the 25%-luminance probe threshold well beyond that analytic surface. Measured against the real render (wkf-containment.cjs), the ring came out 93-94% of the width at 768-1024 -- comfortably over the 70-80% target and, combined with the corresponding rendered height, touching the section's own bottom edge with only a couple of pixels to spare. Flatten the STACKED torus (R:a about 9:1 instead of 5:1, keeping R + a close to mobile's own 49) so a wide ring fits a short band without relying on inflated analytic targets alone, retune the width/height fractions fed to solveFocalForRing against the real rendered extent instead of the analytic one, and weight the band's vertical centring slightly below the midpoint (the tilted camera's near-side reference point isn't the ring's own visual centre). Re-measured: the ring now lands at 70-75% of the width at every stacked width from 768 to 1279, with its bounding box entirely inside [artTop, section bottom] and real margin on both edges.
paintColumnLayer used to fill each column tile's own inset polygon at navy 0.94 before painting its face, leaving the seam gap between tiles fully transparent and letting a touch of whatever draws behind the column (the far plasma arc) bleed through every tile too. It now fills the column's whole projected silhouette first -- the union of the column's own uninset (row, theta-segment) cells, built by chamber.ts's new buildColumnSilhouette from the same grid the real tiles use -- at alpha 1, with a vertical cylinder shading darkest at the silhouette edge. The real tiles paint on top unchanged, so their own seam gaps now sit over this opaque base's darker paint instead of true transparency: nothing behind the column can show through a tile or a seam. index.tsx wires the new silhouette into the column's build step, and adds a `?tokamakDebugColumn` escape hatch that skips every plasma draw in a frame so the column's own opacity can be sampled and screenshotted in isolation. Verified inside the container from website/: npx tsc --noEmit, npx eslint on hero/Tokamak, yarn format then format:check all clean; /products/fusion 200; grep for hex literals empty. With the plasma canvases hidden via the debug flag, a 60-point grid sampled across the column's own silhouette (60/60 inside its real non-transparent bbox, 10 rows at each of 1440 and 375) found no page-navy and no transparent gap anywhere, and a 40-point seam-luminance check (each point compared to the brightest pixel in its own +-12px neighbourhood) found no seam brighter than its neighbouring tile face at either width.
isFarSide only ever classified a whole streak or helix run by its starting theta0, so a streak whose 20-40deg arc straddled the far/near boundary was drawn wholesale on one side of the column: a near-classified streak's tail showed in front of the pillar where it should have been behind it, and a far-classified streak's head vanished under the column where it should have stayed visible in front. projectStreak (and projectHelix) now carry each sampled point's own theta, so isFarSide can classify per point instead of per streak. plasma.ts's existing splitByPredicate (previously only used for the helix) now also splits every streak's point list into far/near runs at the exact boundary crossings, duplicating the boundary point into both so the runs still meet with no gap. index.tsx uses this for both the static majority (baked once into the far/near caches) and the live subset: each live streak is now projected exactly once per frame (down from twice), split into its far/near runs, and those runs feed the FAR step (before the column blit) and the NEAR step (after it) together with their own glow pass, so a streak crossing the column reads as truly behind it on one side and truly in front on the other -- not popping from one side to the other as a whole arc. Verified inside the container from website/: npx tsc --noEmit, npx eslint on hero/Tokamak, yarn format then format:check all clean; /products/fusion 200; grep for hex literals and package.json diff both empty. An in-browser unit check (window.__tokamakDebugSplit, the real isFarSide/splitByPredicate under ?tokamakDebugColumn) fed synthetic 9-point streak arcs straddling both boundaries (theta=0 and theta=PI) plus two arcs entirely on one side: every case produced the expected far/near run split with the boundary point duplicated into both runs (5 checks, 5/5 passing). A 12-frame step-through (300ms apart, at 1440x900 and 375x900, cropped tight around the column at 1440) showed no strand crossing the pillar between frames. The 60-point silhouette sample and 40-seam luminance check from the opaque-base commit still pass unchanged (60/60, 40/40 at both widths -- this change never touches paint.ts). Reduced-motion parity against the pre-edit baseline (test-results/l92-base-*.png, captured at 0244368 before any edit, header masked): the diff mask is a solid block over exactly the column's own bbox plus two symmetric blobs where the band's bloom extends past it on either side (1440: x795-1439/y72-791 inside the 1440x900 frame; 375: x17-362/y610-791 inside 375x900), zero differing pixels anywhere else in either capture. Plasma-only copy-clear probe (h1/paragraph/both buttons, +24px, 5 samples plus reduced motion, both widths): 0 pixels over 25% luminance in every rect (maxLum 0.117-0.125 against the 0.25 ceiling). Frame budget at 1440 (n=300 real frames): avg 1.755ms, p50 1.700ms, p95 2.100ms, max 5.400ms, well under the 4ms budget.
The ticket's file scope for this fix is exactly paint.ts, plasma.ts
and index.tsx in hero/Tokamak -- buildColumnSilhouette landed in
chamber.ts in the previous commit instead, which the review diff check
("diff exactly paint.ts, plasma.ts and index.tsx") would fail on
sight. Moves buildColumnSilhouette and ColumnBaseCell from chamber.ts
into paint.ts (paint.ts already owns the column painter, and now owns
building the geometry it paints too), with its own small front-face
test duplicating chamber.ts's private facingAway rather than exporting
that helper across files. chamber.ts reverts to its pre-ticket state.
index.tsx imports buildColumnSilhouette from ./paint instead of
./chamber; nothing else about the call site changes.
Verified inside the container from website/: npx tsc --noEmit, npx
eslint on hero/Tokamak, yarn format then format:check all clean;
/products/fusion 200; grep for hex literals empty; git diff --stat
0244368..HEAD now touches exactly paint.ts, plasma.ts and index.tsx
in hero/Tokamak. Re-ran the checkpoint 1 and 2 checks against this
relocation: the 60-point silhouette sample, the 40-seam luminance
check, the synthetic-streak split unit check and the reduced-motion
parity diff against test-results/l92-base-*.png all reproduce byte-
identical numbers to the pre-relocation runs (same bbox, same meanLum,
same diff pixel counts) -- confirming this is a pure move, no
behaviour change.
Replaces the column's flat, near-constant-radius row profile with a proper hourglass: r(y) = r_waist + k*(y - y_band)^2, rims at 1.8x the waist radius, row spacing compressing toward the rims in screen space (spacingPower 0.62, empirically verified against the real projection, not assumed from world-y spacing alone). The waist stays at the band (world y = 0 = torus.y), at row index floor(len/2), so the per-point split and the opaque base keep reading the same row. sideBySide and mobile/stacked each solve their own top/bottom span independently (the camera's tilt does not project symmetrically around its aim), so both rims land inside the target screen band at 1440 (top ~12%, bottom ~88%, all 19 rows visible) and at 375 (both rims between artTop+24 and the canvas bottom). Wall rows, the camera and the torus are untouched. tsc --noEmit clean; yarn format then format:check clean; /products/fusion 200 at 1440 and 375.
Replaces the column's per-cell opaque backing (a lifted navy/slate mix,
one fill per (row, theta-segment) cell -- antialiased hairlines at every
shared edge) with ONE simple outline polygon of the whole hourglass
silhouette, filled once at alpha 1 with a new `blackToRgba` helper (a
user ruling for this element overrides the README's "black only encodes
transparency" convention). The polygon walks the top rim row's own front
arc, down the right limbs, the bottom rim row's front arc reversed, then
up the left limbs -- so the top rim's own front edge is the polygon's
own top edge, always solid, and there is no separate per-cell fill left
to crack or leave a hairline. `paintTile` is unchanged, so tile faces
keep their previous specular formula; seams and every gap between tiles
now show solid black (spot-sampled seam pixels read r=g=b=0, alpha 255)
instead of a lifted mix or a transparent gap.
Verified against the live route (1440/375, reduced motion,
?tokamakDebugColumn=1, plasma hidden):
- rv-l92-alpha.cjs (column canvas's own alpha, its documented
+-3px-neighbour "interior" definition): 1440 interior n=365630, holes
2.787% (worst alpha 1); 375 interior n=47490, holes 4.241% (worst alpha
2), concentrated at y<680, inside the pre-existing mobile top-feather
band. A 4x/10x crop of the flagged 1440 region (x780-900,y90-200) shows
a single smooth antialiased silhouette edge, not a tile-seam gap; a
wider +-6px interior definition gives the same low percentage with an
even higher alpha floor (worst 2-3), confirming this is outer-edge AA
on the curved rim, not a leak into the column's interior.
- rv-lum.cjs (column body x900-1330,y500-780, reduced-motion 1440,
n=121111): mean dropped from the pre-edit 0.0886 to 0.0552 (-37.7%),
satisfying the ruling that the black base must lower the column's mean
luminance, not lift it.
- Spot seam sampling on the column-only canvas at 1440 (12 local-minima
candidates across one band row): 10/12 read r=g=b=0, alpha 255 exactly;
the other 2 are 1-8/255, sub-pixel antialiasing between adjacent tile
fills.
tsc --noEmit clean; eslint on hero/Tokamak clean; yarn format then
format:check clean; grep -rnE '#[0-9a-fA-F]{3,8}\b' hero/Tokamak empty.
notVerified this commit: the full 60-point silhouette/seam script (Rule
F's falsifiable seam assertion, located from real tile geometry) is
checkpoint 3's job per the fixer's own checkpoint plan, not run yet;
the G2 hourglass measures (waist-vs-rim width, sagitta) were verified
during checkpoint 1's geometry work, not re-verified against this
commit's visual output; parity, 12-frame step-through, copy-clear probe
and frame budget are re-run in checkpoint 3.
Removes window.__tokamakDebugSplit and window.__tokamakDebugColumnBox and
the per-frame getImageData bbox scan that fed the latter -- no window
globals or full-canvas scans in the production component (Rule F5).
hidePlasmaForDebug (the ?tokamakDebugColumn escape hatch that hides the
plasma canvases so a test script can sample the column layer in
isolation) now also requires NODE_ENV !== "production", on top of the
query param. Test scripts locate the column's own bbox from their own
alpha scan of the column-only capture instead (same technique
rv-l92-leak.cjs already used), and the split helper is unit-checked via
a direct esbuild bundle import of plasma.ts.
Full re-verification against the three commits on this branch (geometry,
black base, this cleanup), inside the container from website/:
- tsc --noEmit clean; eslint on hero/Tokamak clean; yarn format then
format:check clean; /products/fusion and /products/mocha both 200;
grep -rnE '#[0-9a-fA-F]{3,8}\b' hero/Tokamak empty; package.json
unchanged (no diff).
- rv-l92-alpha.cjs (rewritten to derive its own bbox): 1440 interior
n=365630, holes 2.787% (worst alpha 1); 375 interior n=47490, holes
4.241% (worst alpha 2), concentrated in the pre-existing mobile
top-feather band -- a 4x/10x crop confirmed this is outer-silhouette
antialiasing, not a tile-seam leak (see the previous commit).
- l92-column-opaque.cjs (rewritten: esbuild-bundles sceneLayout/chamber/
geometry/paint/plasma, reconstructs the column's own tile grid with
row/segment indices to locate real seam midpoints -- the exported
Tile[] carries none -- and derives the column bbox from its own alpha
scan, reading the page's real copyRect/root size/dpr instead of
assuming them): 1440 -- 261 seams located (60 inside the band), 236
passing (90.4%; in-band 51/60, 85%), 54/54 silhouette samples passing
(walk-inward refinement onto the real rendered edge); 375 -- 220 seams
located (98 inside the band), 187 passing (85%; in-band 97/98, 99%),
56/56 silhouette samples passing. Residual seam failures are
concentrated in rows 0-7 (far from the band, the smallest/most-
compressed tiles), where this script's own analytic tile-grid
reconstruction is least precise, not necessarily real base leaks.
- l92-g2-measures.cjs (new, from the real computeLayout/project/
ringPoint via the same bundle): band width vs top/bottom rim width --
1440: 42.1%/47.5% narrower (>= 35% target); 375: 45.5%/47.9% narrower.
Sagitta of the row two rows above the band vs the band row -- 1440:
76.95px vs 39.84px (>= 6px, greater than the band, rim rows the
largest at 208.96px); 375: 30.2px vs 24.09px, same pattern. The
planner's ruling states the sagitta measure "at 1440"; 375's number is
reported for transparency, not gated.
- l92-split-check.cjs (rewritten to import isFarSide/splitByPredicate
from an esbuild bundle of plasma.ts): 5/5 synthetic straddling-streak
checks passing, same assertions as before.
- 12-frame step-through (l92-stepthrough.cjs, l92-stepthrough-crop.cjs --
the crop script rewritten to derive its own column bbox) at 1440 and
375: no strand crosses the pillar between frames on visual review.
- Parity (l92-parity.cjs + l92-parity-mask.cjs) vs the pre-edit baseline
l92-base-{1440,375}.png (0244368, header masked y<72): 1440 diff
bbox x792-1439/y72-791; 375 diff bbox x0-374/y610-791. The rendered
diff masks show the new hourglass silhouette plus the plasma band and
nothing else -- solid black (zero diff) everywhere outside it.
- Copy-clear probe (wkf-zone.cjs, now including 375): ANY_FAIL false at
every width (375, 768, 834, 1024, 1180, 1279, 1280, 1368, 1440, 1920),
motion and reduced motion; maxLum <= 0.125 everywhere, under the 0.25
ceiling.
- Frame budget (wkf-budget.cjs, n=300, 1440): avg 1.638ms, p50 1.6ms,
p95 1.9ms, max 5.6ms -- avg/p95 well under the 4ms budget.
notVerified: three self-critique rounds were run (full-page captures,
4x/10x zoomed crops of the top rim, bottom rim and band, the 12-frame
step-through) and read against reference-tokamak-pillar.png and a fresh
wrc3-mocha-1440.png capture -- logged as a separate ticket comment, not
in this commit body. Older reviewer scripts that also referenced the
removed window global (rv-l92-whiteback.cjs, rv-l92-alphamap.cjs,
rv-l92-seamleak.cjs, vf-l92-holeloc.cjs) were not updated -- out of this
checkpoint's explicit scope -- and will error if run as-is; rv-l92-leak.cjs
did not depend on the global and needed no change. The 12-frame
step-through remains 12 direct screenshots (ffmpeg unavailable in the
container), the task brief's own accepted substitute for a decoded
video, not re-litigated here. This checkpoint's own seam-location script
is an analytic reconstruction of chamber.ts's private tile-grid math
(needed because Tile[] carries no row/segment index) verified against
the captured image, not against chamber.ts's real internal state
directly -- a genuine chamber.ts refactor could silently desync it.
… its chevron button
…hero pillar instead of reseeding and forking one
…rison pages Keep the GraphQL Federation spec renames and the shared site improvements (header menus, product icons, frontend container, Nitro and release-safety fixes) while removing the new pages and everything only they used: their routes, comparison content and helpers, nav, footer and platform links, sitemap, llms, nginx and analytics wiring, LayeredDiagram, GraphSphere and the Fusion feature icons, the content collection refactor, and the component options added only for those pages.
…ename # Conflicts: # website/content/docs/fusion/composition.md # website/content/docs/fusion/directives-reference.md # website/content/docs/fusion/migration/migrate-from-15-to-16.md # website/src/components/header/navData.tsx
This was referenced Oct 28, 2026
Open
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Renames the GraphQL Composite Schemas specification to the GraphQL Federation specification across the docs, and brings over the shared website improvements that came out of the federation page work.
fusionreference now link tographql.github.io/graphql-federation-spec/draft/instead of the oldcomposite-schemas-specURL, which now returns 404. This covers every spec link in the composition error table, the directives reference, the FieldSelectionMap notes, and the migration guides, and the old spec issue link now points tographql/graphql-federation-spec. The Fusion overview and directives reference say "formerly the GraphQL Composite Schemas specification" once, and the Fusion product description reads "GraphQL Federation Gateway".aria-expanded, opens and moves with the keyboard, closes with Escape, and stays inside the viewport from 1060 to 1272 px.ProductArtworkIcon,productArtwork.ts). The protocol card icons on the home page are cropped to their glyphs.HeaderShellis removed, so every route,/products/nitroincluded, uses the same sticky, tinted header instead of a transparent overlay. The Nitro hero moves up under the header so it still starts at the top of the viewport.ClassificationCardandClientImpactMatrixmove from the Nitro and release-safety pages into shared components, andsyntaxTokensmoves tosrc/components. At narrow widths (375 px), the impact matrix wraps the operation count under its bar instead of running into the status column.useReducedMotionPreference, which renders the same markup on the server and during hydration.test-results/.The
composite-schemas-speclinks in the C# XML docs and test comments are not part of this PR.Test plan
tsc --noEmit,npm run lint, andnpm run format:checkpass inwebsite.