Repository navigation
Conversation
…ewer Builds on the subassembly viewer with the parts that make it useful as an assembly reference rather than a turntable. Exploded view. Parts cluster by proximity (union-find over mesh centres) so a motor, its mount and its prop travel as one rigid unit along the line from a shared pivot, instead of every mesh scattering independently. Two escapes from that rule: 1211/1212 sit between the plates and overlapped the upper plate on a radial path, so they are sent straight down; wide flat pucks above the cap (the GPS dome and friends, which are unnamed in the GLB and have to be matched by shape) go straight up. The top cap swings on a real hinge line at its rear seam rather than translating, and the hinge rides on its carrier so the lid stays seated on the enclosure through the animation. Movement is eased rather than linear, since a linear explode reads as a glitch. Component labels. Optional leader-line labels anchored to each subassembly's largest part, tracked per frame through the explode so the anchor follows the geometry. Materials. The GLBs carry little useful material data and, in the motor arm's case, no useful mesh names either, so parts are recoloured per file: carbon for props and arm tubes, matte plastic for motors, aluminium for plates and beams, Arrow blue for small hardware and landing gear feet. Landing gear tips are unnamed and identified by their baked-in orange CAD colour. PCB components are assigned deterministically from a palette by hashing their position, so the board reads as populated rather than uniformly grey. Arrow logomark rendered onto the top cap as a decal plane.
…and a11y The viewer fetched two assets from third parties on every visit, and both fail the same way: blocked or unreachable, and the model renders as nothing or as flat black. On the most technical page in the docs, for a project whose point is that everything is inspectable, that is the wrong dependency to carry. Draco decoder. useGLTF(url, true) pulls the decoder from www.gstatic.com. Vendored from the three package instead. It sits in static/draco/ rather than beside the models on purpose: static/quiver/ is gitignored and repopulated from the upstream Quiver repo on every build, so a decoder placed there would be present locally and absent in CI, and the failure would only appear in production. Environment map. <Environment preset="city" /> downloads a 1k HDR from raw.githack.com, an unofficial proxy pinned to a GitHub commit. Replaced with RoomEnvironment generated on the GPU through PMREMGenerator, which costs no network at all. Verified visually: no change to how the materials read. After both, the page makes zero cross-origin requests. Mobile. The parts tree stacks above the canvas below 768px and defaults open, which pushed the aircraft off the bottom of the screen on load. It now starts collapsed on narrow viewports and opens from the existing button. Loading state. Suspense fallback was null, so the canvas was an empty box for the entire download with nothing to indicate progress. Accessibility. A WebGL canvas is opaque to search engines and assistive tech. The wrapper now carries a description pointing at the parts tree, which is already a complete text listing of the assembly. The label goes on the wrapper because react-three-fiber does not forward arbitrary DOM props to the canvas. Also removes the propeller spin control, which was a playground experiment.
…-viewer-explode # Conflicts: # .cspell.project-words.txt
thomasgarrison
approved these changes
Aug 31, 2026
thomasgarrison
left a comment
Contributor
There was a problem hiding this comment.
This looks great. Any feedback I can give would be more additive for future features rather than anything wrong with the current implementation, and would need to happen on the quiver repo:
- Find a way to add in our harnessing to the build123d design/this viewer.
- Richer per-part information and file download from the viewer
This has me thinking more about the Arrow super-app and what we could build similar to this to coordinate and collaborate at a higher level. I imagine a version of this that isn't just read-only eventually. We could have this all in the same app as discussions, bounty proposals, governance, etc
This branch has not been deployed
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.
Builds on the subassembly viewer merged in #174, adding the parts that make it work as an assembly reference rather than a turntable, and removing the last two third-party requests the page was making.
Exploded view
Parts cluster by proximity (union-find over mesh centres) so a motor, its mount and its prop travel as one rigid unit along the line from a shared pivot, rather than every mesh scattering independently. Two exceptions: 1211/1212 sit between the plates and overlapped the upper plate on a radial path, so they are sent straight down, and the wide flat pucks above the cap (the GPS dome and friends, unnamed in the GLB and matched by shape) go straight up. The top cap swings on a real hinge line at its rear seam rather than translating, with the hinge riding on its carrier so the lid stays seated through the animation. Movement is eased, since a linear explode reads as a glitch.
Component labels and materials
Optional leader-line labels anchored to each subassembly's largest part, tracked per frame so the anchor follows the geometry through the explode.
The GLBs carry little useful material data and, for the motor arm, no useful mesh names either, so parts are recoloured per file: carbon for props and arm tubes, matte plastic for motors, aluminium for plates and beams, Arrow blue for small hardware and landing gear feet. PCB components are assigned deterministically from a palette by hashing position, so the board reads as populated rather than uniformly grey. Arrow logomark rendered onto the top cap as a decal plane.
Removing the runtime CDN dependencies
The viewer fetched two assets from third parties on every visit, and both fail the same way: blocked or unreachable, and the model renders as nothing or as flat black. On the most technical page in the docs, for a project whose point is that everything is inspectable, that is the wrong dependency to carry.
Draco decoder.
useGLTF(url, true)pulls the decoder fromwww.gstatic.com. Now vendored from thethreepackage intostatic/draco/.It is committed rather than fetched at build time on purpose. It cannot live beside the models in
static/quiver/, because that directory is gitignored and repopulated from the upstream Quiver repo on every build, so a decoder placed there would be present locally and absent in CI. The failure would then only show up in production. 192 KB of WASM in the repo is the cost of that guarantee.Environment map.
<Environment preset="city" />downloads a 1k HDR fromraw.githack.com, an unofficial proxy pinned to a GitHub commit. Replaced withRoomEnvironmentgenerated on the GPU throughPMREMGenerator, which costs no network at all. Verified visually, with no change to how the materials read.After both, the page makes zero cross-origin requests.
Mobile, loading and accessibility
The parts tree stacks above the canvas below 768px and defaulted open, which pushed the aircraft off the bottom of the screen on load. It now starts collapsed on narrow viewports and opens from the existing button.
The Suspense fallback was
null, so the canvas was an empty box for the whole download with nothing indicating progress.A WebGL canvas is opaque to search engines and assistive tech, so the wrapper now carries a description pointing at the parts tree, which is already a complete text listing of the assembly. The label sits on the wrapper because react-three-fiber does not forward arbitrary DOM props to the canvas.
Also removes the propeller spin control, which was a playground experiment.
Review notes
Five files, and three of them are the vendored Draco decoder. The reviewable surface is
Viewer.tsxandstyles.module.css.Worth checking on a phone, since the mobile default is the one behaviour change to an existing merged feature rather than an addition.