Problem
Making a lightsaber look like a premium physical object in a browser without shipping heavyweight 3D model, texture, or HDRI assets.
Solution
Built the hilt from modular procedural geometry with physically based materials, and generated the studio environment locally from Lightformer area lights plus contact shadows, so the entire look compiles into the bundle.
Problem
Letting users share an exact build without a backend, accounts, or storage.
Solution
Made the URL the single source of truth: configuration is serialized to versioned query parameters and validated on read against option catalogs, with unknown values falling back to defaults and names control-stripped and length-bounded.
Problem
On touch devices, OrbitControls captured every gesture, so users could not scroll past the 3D preview.
Solution
Disabled orbit controls by default on mobile and set the canvas to pan-y so swipes scroll the page, then added an explicit Explore toggle that hands control to the saber and a Done action that returns to normal scrolling.
Problem
Exporting a build card required reading pixels back from a WebGL canvas, which is normally cleared after each frame.
Solution
Enabled preserveDrawingBuffer on the renderer, then scaled the live canvas into a 1080x1350 2D canvas composition with typeset build details and exported it via toBlob and an object URL.
Problem
The mobile save dialog rendered half off the left edge of the screen despite bottom-sheet styles that reset transform.
Solution
Traced it to Tailwind CSS 4 centering the dialog with the CSS translate property rather than transform, so the reset never applied; reset translate as well and anchored the sheet with explicit left and right edges plus safe-area padding.
Problem
Delivering saber audio without shipping sound files or violating browser autoplay policies.
Solution
Synthesized ignition and extinction as filtered oscillator frequency sweeps and the hum as layered detuned oscillators, creating the AudioContext only on explicit user interaction and suspending it on visibility change.
Problem
Keeping a heavy WebGL scene from blocking first paint or breaking on unsupported hardware.
Solution
Prerendered the routes to static HTML, lazy-loaded the 3D module behind Suspense and an error boundary with an explicit WebGL failure message, preloaded it on idle, hover, and focus, and capped the device pixel ratio lower on mobile.