Steam Controller 2026 visualizer (Valve CAD → optimized GLB)#6
Merged
Conversation
Wires Valve's official 2026 Steam Controller CAD into the visualizer.
The pending DEVICES entry already had a steam-controller protocol slot;
this PR makes it visually ready so the moment the real vid:pid is
captured and the entry is promoted to DEVICES, the overlay loads the
correct model without further visualizer changes.
Source pipeline:
Source : gitlab.steamos.cloud/SteamHardware/SteamController
sc_solid_stl_20260429.stl (binary STL, 78.9 MB, 1.58M tris)
Step 1 : node tools/stl-to-glb.js <stl> <raw.glb> 0.001
(new converter — dedup vertices, mm→m scale, 78.9 MB → 37.9 MB)
Step 2 : npx -y @gltf-transform/cli optimize <raw.glb> <out.glb>
--simplify-ratio 0.03
(1.58M → 259K tris, 37.9 MB → 961 KB)
The new tools/stl-to-glb.js is a general-purpose binary-STL → GLB
converter: dedups vertices via micrometer-quantized keys (CAD exports
have tiny float noise), supports unit scaling, no external deps. Useful
for any future vendor CAD release that ships STL (Sony, Nintendo, etc.).
LICENSE NOTE: this single asset (steam-controller.glb) is
CC BY-NC-SA 4.0 (Valve's license), unlike the rest of the visualizer
which is MIT. Full attribution + commercial-use implications spelled
out in packages/visualizer/assets/controllers/STEAM_CONTROLLER_ATTRIBUTION.md.
Known limitation: STL is a single solid body. PROFILES['steam-controller']
is body-only — gyro rotates the whole mesh, but button presses won't
animate. To get full-fidelity button animations would require the
STEP file (preserves component hierarchy) and a Blender pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
petegordon
added a commit
that referenced
this pull request
May 24, 2026
…ender The Super Nova GLB (and any other GLB run through `gltf-transform optimize` with defaults, including the Steam Controller GLB queued in PR #6) ships with EXT_meshopt_compression marked as a *required* glTF extension. Three.js's GLTFLoader supports the extension — but only if you call `loader.setMeshoptDecoder(MeshoptDecoder)` first. Without that, meshopt-compressed buffer views silently fail to decode and the mesh renders as an empty axis-aligned bounding box, which is what showed up as a featureless black rectangular block when the auto-detect correctly swapped the overlay to load gamesir-super-nova.glb. Three changes wire it up: packages/visualizer/src/controller-overlay.js + import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js' + loader.setMeshoptDecoder(MeshoptDecoder) at the top of the GLB load Promise (called per-load; Three's loader is idempotent here) apps/overlay/scripts/copy-three.js + add 'libs/meshopt_decoder.module.js' to the addons list so the vendored Three.js bundle that the no-bundler importmap serves includes it (matches the existing fflate vendor pattern) The fix benefits *every* future GLB the lab ingests via the documented `gltf-transform optimize` pipeline — Steam Controller, future Cyclone 2 model, etc. The alternative (skipping meshopt during optimize) would ship 30-50% larger GLBs for everything; better to support the standard extension once and reap the size benefit going forward. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
petegordon
added a commit
that referenced
this pull request
May 24, 2026
…ender The Super Nova GLB (and any other GLB run through `gltf-transform optimize` with defaults, including the Steam Controller GLB queued in PR #6) ships with EXT_meshopt_compression marked as a *required* glTF extension. Three.js's GLTFLoader supports the extension — but only if you call `loader.setMeshoptDecoder(MeshoptDecoder)` first. Without that, meshopt-compressed buffer views silently fail to decode and the mesh renders as an empty axis-aligned bounding box, which is what showed up as a featureless black rectangular block when the auto-detect correctly swapped the overlay to load gamesir-super-nova.glb. Three changes wire it up: packages/visualizer/src/controller-overlay.js + import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js' + loader.setMeshoptDecoder(MeshoptDecoder) at the top of the GLB load Promise (called per-load; Three's loader is idempotent here) apps/overlay/scripts/copy-three.js + add 'libs/meshopt_decoder.module.js' to the addons list so the vendored Three.js bundle that the no-bundler importmap serves includes it (matches the existing fflate vendor pattern) The fix benefits *every* future GLB the lab ingests via the documented `gltf-transform optimize` pipeline — Steam Controller, future Cyclone 2 model, etc. The alternative (skipping meshopt during optimize) would ship 30-50% larger GLBs for everything; better to support the standard extension once and reap the size benefit going forward. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
6 tasks
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
Wires Valve's official 2026 Steam Controller CAD release into the visualizer. The pending DEVICES entry for the Steam Controller already had a
steam-controllerprotocol slot; this PR makes it visually ready so the moment the real vid:pid is captured (when hardware ships in the wild) and the entry is promoted to DEVICES, the overlay loads the correct model with no further visualizer changes.Asset pipeline
sc_solid_stl_20260429.stl(78.9 MB, 1.58M tris)node tools/stl-to-glb.js <stl> <raw.glb> 0.001npx @gltf-transform/cli optimize --simplify-ratio 0.03The new
tools/stl-to-glb.jsis a general-purpose binary-STL → GLB converter (dedups vertices via micrometer-quantized keys, supports unit scaling, no external deps) — useful for future vendor CAD releases.License note⚠️
The single asset
steam-controller.glbis CC BY-NC-SA 4.0 (Valve's license), unlike the rest of the visualizer which is MIT. Full attribution and commercial-use implications are spelled out inpackages/visualizer/assets/controllers/STEAM_CONTROLLER_ATTRIBUTION.md.TL;DR: fine for personal / non-commercial / open-source use; remove or replace the GLB if shipping the lab in a commercial product.
Known limitation
STL is a single solid body — no separated parts for buttons, sticks, triggers, trackpads, or paddles.
PROFILES['steam-controller']is therefore body-only: gyro rotates the whole mesh, but button presses won't animate. Achieving full-fidelity animations would require converting the upstream STEP file (preserves component hierarchy) via FreeCAD/OpenCascade + a Blender pass — separate future work.Test plan
npm installat root — no new deps.node tools/stl-to-glb.jsruns without errors on the upstream STL.npx @gltf-transform/cli inspect packages/visualizer/assets/controllers/steam-controller.glbshows ~259K tris, ~961KB.🤖 Generated with Claude Code