Skip to content

web: /build's 3D preview shows the case you pick, with arrows to step through them - #487

Merged
engmung merged 4 commits into
mainfrom
dev
Oct 9, 2026
Merged

engmung merged 4 commits into
mainfrom
dev

Conversation

@engmung

@engmung engmung commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Brings dev to main: #486 (from the Patternflow-lab workspace) plus one follow-up.

#486: the build page's 3D preview becomes the case you pick

  • The Build panel's case switch (official v3.9 / Besoiobiy printed / SimonePDA laser-cut, ?case= links) swaps the preview's model, with an acrylic/MDF toggle for SimonePDA.
  • Each model is built by the new tools/case-models from the case's own files and lives at web/public/cases/<id>/model.glb. The first-load model goes from 1.15 MB (3dforweb.glb, removed) to 0.32 MB; the guide takes its LED panel from the official model.
  • The preview reads white rather than beige: neutral PLA, Neutral tone curve, local lights instead of a CDN environment map, an LED dot grid, round knobs, clear acrylic.
  • Docs catch up: laser cut is no longer "being prepared", the v3.9 board is named where v3.0 was, the build guide and assembly map point at Besoiobiy's remix. web-ci.yml also runs on hardware/case/**, since the case cards' tests check those paths.

Follow-up: arrows on the preview

  • On the Build tab, prev/next arrows either side of the device step through the cases (official → Besoiobiy → SimonePDA → round again), styled like the Inside globe's arrows (84 px, 44 px on a phone).
  • They drive the same switch as the panel: the store, the ?case= address, the case card and the build_case_selected event (surface: product_preview) all follow. Hover or focus preloads the case an arrow points at. Hidden on the other tabs.
  • writeCaseToUrl moved from BuildPanel.tsx to build-cases-data.ts next to the new stepCase, so the panel and the preview share it.

Checked locally (dev + #486 + arrows): tsc clean, eslint no errors (5 existing <img> warnings), vitest for components/3d, components/sections and components/guide passes. In the browser at phone width and 1440 px: all three cases switch from the tabs and from the arrows, the address and card follow, the arrows wrap, they are absent on /pattern and /, no console errors. A full next build was not run here; the workspace PR reports it passing.

🤖 Generated with Claude Code

patternflow-bot and others added 4 commits October 9, 2026 20:48
…fficial v3.9, Besoiobiy, SimonePDA (#3)

* hardware: Besoiobiy's printed case as a remix folder

hardware/case/remixes/besoiobiy-printed/ holds the printed case Besoiobiy
shared on the Discord: their Bambu Studio project, the Blender scene (the
same LFS object, moved), the scene STL as exported, one STL per part cut
from it, their eight figures and a photo, and a README that carries the
author, the CC BY-SA 4.0 license and the build notes. The assembly map
gets a row for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqMhYfHm6xUykCapCcDwzt

* hardware: correct the Besoiobiy remix README after review

The photo shows the power cable leaving through the side-wall opening,
so the two openings were paired with the wrong orientations. The frame
covers close the back of the panel, so the assembly now wires the panel
before they go on and leaves the box open until the section 9 checks.
Check your panel first gains the thread size (M3, where the BOM panel
takes M4), the bolt reach and the real slot tolerance. Smaller fixes:
the covers are counterbored, not countersunk; the knob bore is a D; the
scene STL is pulled apart, not assembled; the bridge is about 48 x 5 mm;
the .blend opens from Blender 4.5 on; the power bank bay is sized; the
back render is shown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqMhYfHm6xUykCapCcDwzt

* docs: point build guide section 4 at Besoiobiy's printed case

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqMhYfHm6xUykCapCcDwzt

* hardware: second review pass on the Besoiobiy remix README

The panel the build guide links is not on this case's bolt pattern
(its side rows sit 137.4 mm apart in the official case, 139 mm here),
so opening the cover holes for M4 is not enough: say the case is for
an M3 panel on Besoiobiy's pattern. Flash the DevKit off the board
before it is seated and powered, as section 8 does. Give the power-bank
bay as an empty bay that also has to hold the J4 plug, make the J4
cable's route consistent with where the bank sits, set the inserts
before anything goes in, and say sections 7 to 9 change order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqMhYfHm6xUykCapCcDwzt

* hardware: match the Besoiobiy remix README to upstream main

Upstream took this folder as one maintainer commit, and its README adds
the panel link to the Fits line. Taking that copy keeps the two trees
byte-identical, so a later sync of dev with upstream has nothing to merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: the Build panel switches between the official case and the two community remixes

The case is now a choice on /build: the official printed case, Besoiobiy's
printed remix and Simone Majocchi's laser-cut remix, as three tabs over one
card. Each card shows the author, material, the boards and panel it fits,
what it takes to make, what it needs beyond the BOM, when it was verified,
the license, two photos (all of them in the viewer) and the GitHub folder
and files. A remix says what to check on your own panel first. Step 01 and
the case row under Start here follow the switch, and /build?case=<folder>
opens the panel on that case.

The card data lives in build-cases-data.ts, copied from each README; its
test checks every GitHub link against this tree, every photo against
public/cases/, and each remix card against its README header.

Brought up to date with BUILD_GUIDE.md and the remix READMEs:
- content/build.md lost the build matrix nothing rendered any more
  ("Preparing: Laser cut"), and its body is now the case switch's lead.
- Facts: ESP32-S3 ~$13 and ~10 h of printing, as the guide says.
- Steps: the v3.9 board; power through the screw terminal.
- Start here: panel compatibility before buying; the breadboard and v2
  guides linked directly; laser cut is no longer an "other route".
- /build metadata and llms.txt name the printed or laser-cut case.
- /build/breadboard: ~10 h and section 4 (not v2's ~11 h and 2 & 3), the
  left USB-C port and the Pattern tab for flashing, the 8.2 anchor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* docs: the v2 guide and the assembly map name the v3.9 board, and laser cut is no longer in preparation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: draft screenshots of the Build panel's case switch, for PR #2

Desktop (1440 × 900) and phone (390 × 844 @2x) on each of the three
cases, and the panel as it was on dev. Evidence for the pull request
only; not part of the site. Remove before merging.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: the case cards after review — what to cut, what to measure, and a viewer that survives a switch

- Laser cut: the drawing is three pages to cut (the plate, the border
  strips, the box and feet), not one sheet; the card, step 01 and the lead
  in build.md said one.
- Besoiobiy: 14.35 mm is where the sockets end behind the LED face, not how
  deep they are; the card now says what to measure, and the 8.5 mm of
  thread the bolts need.
- Official: the adjustable for_other_panels/ version is not universal, so
  this card gets its own check. Every check links to the README section
  that says how.
- The printed-parts photo is before gluing; its alt text said glued.
- Switching case with the photo viewer open no longer crashes the page:
  the viewer belongs to the case it was opened on.
- The method line on the unselected tabs reads at full muted ink (it was
  3.7:1); the tab names share a top line on a phone; the kicker and the
  card heading wrap evenly; the README caption baked into the exploded
  renders is painted out of the web copies.
- Tests pin the Start here row's href, replaceState over pushState, the
  keys being consumed, the tabpanel's name, a card photo opening the
  viewer on itself, the crash above, the #anchors, and read build.md by
  path so the suite runs from the repo root too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: Web CI also runs on hardware/case/, which the case cards' test reads

build-cases-data.test.ts checks every link on the /build case cards
against hardware/case/ and each remix card against its README. A change
there alone used to skip Web CI and leave the check for the next web PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* docs: web/public/cases/ is CC BY-SA, and the README no longer calls laser cut in progress

The case photos on /build are copies of the remix authors' and the build
guide's CC BY-SA images; the license summary now says so, as it does for
web/public/builds/. The README's one line on the enclosure names the two
community remixes, and keeps stainless steel as the variant in progress.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: final screenshots of the Build panel's case switch, for PR #2

After review: desktop (1440 × 900) and phone (390 × 844 @2x) on each of
the three cases, the whole panel, and the panel as it was on dev. Evidence
for the pull request only; removed again in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: drop the PR #2 screenshots from the tree again

They stay readable at 7ccb7ba, which the pull request links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: the remix screenshots for PR #2 again, under neutral names

The same eight images as at 7ccb7ba, byte for byte, so the pull request
body can show them: its image addresses with the original names did not
survive being saved. Evidence only; removed again in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: drop the PR #2 screenshots from the tree again

They stay readable at 6ffc70d and 7ccb7ba, which the pull request links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bRDk1Qd2Jgev46CPBkFLw

* web: the preview's case models start with the official v3.9 one, built by tools/case-models

tools/case-models puts each case's model together from files in the repo:
the official case is the guide's case-v39.glb with the LED panel, the v3.9
board and the DevKit in it, simplified and Draco-compressed (313 KB, where
the landing model was 1.15 MB). The store gains the case the Build panel's
switch is on, and caseModels.ts the node contract the preview will read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* tools: build.sh remakes every case model, and the panel can prefetch one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* tools: the LED panel keeps its UVs through the case-model pipeline

prune() drops a UV set no texture uses, and the LED panel's UVs are what the
pattern shaders draw with. Keep them, re-extract the panel, rebuild the
official model (316 KB).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* tools: the official model's LED panel keeps its source transform exactly

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* tools: SimonePDA's laser-cut case as a 3D model, stood up from its drawing

simonepda.py reads the cut paths of lasercut_layout.pdf (the sheet comes out
256.00 x 340.00 mm, the scale check) and extrudes every part as drawn: the
plate with its holes, windows and slots, the four border strips on edge round
the panel, the finger-jointed box over the board, three open-cube feet.
331 KB assembled. The box stays acrylic in the MDF finish: assemble.mjs now
merges materials only when their names match too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: the Build panel's case switch drives the shared store, and a remix card leads with its README

The picked case lives in useAppStore, so the 3D preview can follow it; ?case=
still opens the panel on a case and picking still rewrites the URL on /build.
Hovering or focusing a tab starts loading that case's model. Each remix card
now opens with a link to its README on GitHub; the card text, checked claim by
claim against the README, stays, with four claims brought back in line. The
line saying the 3D model is the official case is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* tools: Besoiobiy's printed case as a 3D model, put together from its own STL

besoiobiy.py finds the nine parts in source/patternbox.stl by matching each
stl/ file on what a move cannot change, assembles them with translations
worked out from the faces that meet, and stops unless the result is what the
remix README measures: 267 x 329 x 30.85 mm, the 161 x 321 mm opening, the
four encoder holes, no two parts overlapping. 345 KB assembled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: the guide takes its LED panel from the official case model, and the docs name tools/case-models

The guide only ever used the old landing model's LED panel node; the
official case model carries the same node (same transform, geometry and UVs,
checked vertex by vertex), so the guide and the landing preview share one
0.32 MB file again instead of the 1.15 MB one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: a test holds each case model to the node contract and its download budget

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: the product preview shows the case picked on the Build panel (first pass)

HeroScene loads the picked case's model (the official one with the page, a
remix when it is picked, keeping the current one on screen until it is in),
finds its parts by the node contract and runs the four build steps on any of
them; a case with more than one finish gets a switch in the viewer. The old
v3.0 landing model, 3dforweb.glb, is no longer used anywhere and goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* tools: the case-models README covers all three scripts; the changelog covers the whole change

SimonePDA's knobs come off the front as far as on the other two cases:
further, they crossed in front of the panel in the three-quarter view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: review fixes for the case-switch preview

- Each knob greys on its own while held: the files' four knobs share one
  material, so the preview gives each its own copy (a test holds it).
- A model that failed to load is let go of in drei's cache and tried again
  when its case is picked; if the official model fails, the preview says so
  instead of leaving a remix up under the Official tab.
- The hand cursor shows over a knob however the pointer gets there.
- Picking a case rewrites ?case= in place, and is no longer counted as a
  page view; Home or End on a tab that is already picked sends nothing.
- The landing panels not on screen are inert, so the keyboard cannot reach
  the case switch from the Pattern tab.
- Besoiobiy's knob caps stand where the shaft bottoms out in their bore
  (3.7 mm off the front), not at the official knobs' 0.8 mm.
- The case-model scripts need Python 3.12; extract_led.mjs resolves its
  default path properly; docs say what is shared and where photos come from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: screenshots of the case-switch preview, for PR #3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: drop the PR #3 screenshots from the tree again

They stay reachable at f903845, where the PR body links them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: detail-review comparison images for PR #3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

* web: drop the detail-review images from the tree again

They stay reachable at c8a42a1, where the PR body links them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P2Ta77EYfNvbYmQ64Z8JFn

---------

Co-authored-by: Claude <noreply@anthropic.com>
…tone curve, local light, LED dots, round knobs, clear acrylic (#4)

* tools: case models in neutral white PLA, the official knob drawn round, clear acrylic

- pla_white is #f4f4f2 at roughness 0.85, a white without a cast: the warm
  #eceae4 read as beige under the preview's light (PR #3's detail review).
- The official knob is hardware/case/knobs/knobs_20mm.stl's own profile,
  read from the STL at build time and turned with 96 sides (lib/knob.mjs);
  case-v39.glb carries the same knob as a 32-sided prism, whose flats showed.
  Same size, same base; 0.4 mm round on the top edge. All four share one
  mesh, so the official model grows by 812 bytes (317,180 B).
- Acrylic faces at 12% opacity, cut edges darker and cool green.

All three models rebuilt; a clean rebuild gives the same bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: the product preview gets a tone curve, local light, LED dots and one scale for every case

- EffectComposer: Neutral tone mapping, on each pixel's own colour
  (canvasAlpha.tsx), then the bloom. The canvas is see-through, and the
  composer used to sRGB-encode premultiplied colour, which is why a clear
  sheet always came out frosted white.
- The environment is local Lightformers, as on the guide's stage, not the
  city HDR fetched from a CDN at run time.
- The LED panel's face is round emitters on a black mask (patterns/common.ts,
  shared by every pattern path), drawn as whole cells once an LED is under
  about three pixels; colours held under the tone curve's knee, whites hot
  enough that the bloom is what it was; the panel's rim and sides are its
  black frame instead of the pattern smeared over them.
- Every case at one scale, centred only: the panel and knobs were drawn 3%
  smaller in the remixes.
- SimonePDA's feet are loose pieces (CaseModel.loose): with the parts and on
  Assemble, not behind the clear sheet on the device as it stands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* docs: the case-models README and the changelog cover the white case, the light and the round knob

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: a test holds every case model's white PLA to a white without a cast

Reads pla_white's base colour from each GLB and checks its CIELAB a* and b*
are within 1 of zero (the old #eceae4 is b* +2.6) and L* is over 94.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: the white-PLA test allows ±1.5 in a* and b*, and says what it holds

#f4f4f2 is b* +0.96 and a* −0.35; the warm #eceae4 it replaced is b*
+3.14 (the last commit said +2.6). The comment in lib/looks.mjs gives the
build photos' range as measured, b* −6 to +11. The comment changes no
material, so the models are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: review fixes — what the Neutral curve does, a testable pose per Build step, and what the docs claim

From an adversarial review of this branch:
- The Neutral tone curve is described as it is: below its knee it takes the
  same small offset (0.04 at most) off every channel, which keeps a neutral
  white neutral and a pure colour pure; it is not the identity. LED colours
  top out at the knee, 0.8, where it greys them by under 0.1%.
- Each Build step's pose moves to buildPose.ts with shows(), and a test holds
  the loose-piece rule: SimonePDA's feet out on steps 1 and 3, off on 2, 4
  and idle. The one-scale test now fails on the old fit-scaling code.
- The LED panel, not the knobs, is the part every case shares (Besoiobiy has
  its own caps); the old fit drew the remixes 3.5 to 4% smaller; up to 4% is
  the front's diagonal (Besoiobiy's case is 8% wider); BOARD_SPAN's 4.09 is
  the official device's.
- knob.mjs: the outline runs clockwise (solid on the right); the top edge's
  round is a choice for the preview, as the knob prints on its top; the size
  check cites hardware/case/README.md. assemble.mjs says where the knob comes
  from. The feet comment says where the feet are.

Comments only in tools/: the rebuilt models are byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: the tone curve is Neutral's shoulder, bright colours keep their glow, the light panels say where they face

From the rendering lens of the review:
- Neutral's toe (x − 6.25x² off every channel under 0.08) crushed the dark
  parts: the knobs to 1/255, the panel's dim LEDs, MDF's burnt edges to a
  saturated orange. neutralToe.tsx gives back exactly what it takes, just
  before the curve, so below the knee the frame is as lit and the curve only
  rolls off what is brighter. The knobs show their shape again and the
  panel's off LEDs read as a dark grid on black.
- What makes an LED a light is now its luminance against the bloom's
  threshold, not its white: the editor path's bright yellows and cyans keep
  their energy and glow as they did, and near-whites under the threshold are
  no longer boosted into a glow on desktop only.
- The Lightformers' rotation-y did nothing (drei aims each at the origin);
  dropped, and said so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* docs: the changelog gives the case front's final numbers, b* +0.4 and L* 89.8

Measured on the production build after the review fixes (9x9 patch on the
front, desktop and phone alike); the dev build of origin/dev gave +1.7, 82.5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: evidence images for PR #4 (photo vs preview, before vs after, close-ups)

Evidence only; removed again in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

* web: drop the PR #4 evidence images from the tree again

They stay reachable at c68c4c0, where the PR body links them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V2YJoXD5nkTv3DWFZhSfke

---------

Co-authored-by: Claude <noreply@anthropic.com>
web: build page 3D preview switches between the official case and two community remixes
…e the Inside globe's

On the Build tab the product preview gets the globe's prev/next arrows,
cycling official -> Besoiobiy -> SimonePDA and round again. They are the
Build panel's switch from the other side: same store, same ?case= address,
same build_case_selected event (surface product_preview), and a hover or
focus preloads the case an arrow points at. Hidden on the other tabs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 9, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated
pattern-flow_origin Ignored Ignored Oct 9, 2026 2:43pm UTC

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.

2 participants