three-fiber-component-shape-planner
Purpose
Translate a planned GLB delivery into the exact public surface a React Three Fiber component should expose, so the web engineer's contract is locked before code is written.
Quick start
- enumerate the props the consumer needs (color, animation name, scale, onLoaded)
- decide ref shape (forwardRef, imperative methods)
- decide Suspense boundary location
- decide useGLTF caching + cleanup strategy
- decide animation hook contract (auto-play, manual control)
When to use
- the GLB will ship to a web app using React Three Fiber
- before the web team writes the component
- when "I'll just import the GLB" needs more rigor (multiple clips, prop overrides, lazy loading)
When not to use
- consumers using vanilla Three.js (different API)
- consumers using Babylon / model-viewer (different stack)
- the GLB is rendered server-side (e.g. AR pre-render); no React component needed
Trigger phrases
- "how should the React component look"
- "what props should I expose"
- "ref shape for the model"
- "we use react-three-fiber"
Prerequisites / readiness
- GLB delivery contract known (clips, materials, variants)
- target React/Three.js/R3F versions known (or assume current stable)
- consumer team's preferred state-management style noted (Zustand / context / props)
Input schema
Required inputs
| Input |
Why it is required |
| GLB delivery contract |
Determines what props can vary |
| R3F version |
Hook signatures change between R3F 8 / 9 |
| Use case (hero / configurator / AR) |
Determines lazy-loading + Suspense placement |
| Customization scope |
Color overrides? Animation triggers? Variants? |
Optional inputs
| Input |
Use |
| Existing component patterns in the consumer codebase |
Maintain consistency |
| Performance budget |
Decides whether to use useGLTF cache or per-instance load |
| LOD requirements |
Triggers meshoptimizer / Draco decision points |
Assumptions to confirm
- The consumer team can install peer deps (
three, @react-three/fiber, @react-three/drei).
- GLB fetched over HTTP is acceptable; no special CDN auth needed.
- Memory pressure from cached GLB scenes is acceptable for the use case.
Output schema
Primary output
A React Three Fiber component shape spec including:
- Props table (name, type, default, purpose)
- Ref interface (imperative methods exposed)
- Suspense placement (inside vs outside)
- useGLTF caching policy (shared vs per-instance)
- Animation hook contract
- Cleanup contract (unmount behavior)
Secondary output
- minimal usage example for the web engineer
- caveats about R3F version compatibility
- error / fallback contract (what shows if GLB fails to load)
Evidence / caveat output
Runtime status: Not Run | Attempted | Produced | Verified | Failed | Blocked / Not Run
Artifact status: Not Run | Not Produced | Produced | Verified | Failed
Evidence used: <links, paths, logs, or "none">
Limitations: <known gaps>
Required laws
../../laws/evidence-before-done.md
../../laws/non-blender-user-language.md
../../laws/no-arbitrary-python-interface.md
../../laws/official-runtime-only.md
Official runtime boundary
This skill produces planning specs only. It does not generate component code, run a web app, or claim that the resulting component will perform correctly without measured load tests. Web-side implementation is owned by the consumer team.
If runtime is involved, refer to ../../docs/runtime-stack-strategy.md for the 2-path + CLI appendix model. R3F lives entirely on the web side and does not interact with Blender at runtime.
Operating procedure
- Read the GLB delivery contract + animation contract.
- Enumerate consumer customization points → props table.
- Decide ref shape based on imperative needs (play / pause / setColor).
- Decide Suspense placement based on use case (hero needs sub-tree fallback; configurator needs page-level fallback).
- Decide useGLTF caching policy based on instance count + memory.
- Decide animation hook contract based on trigger model.
- Produce spec + minimal usage example.
- Hand off to web engineer + flag verification checklist.
Decision tree
Multiple instances of the same model?
→ useGLTF cache (shared) + reuse scene clones
Single instance?
→ useGLTF works as-is
Animation triggered by hover/click?
→ expose `animationName` prop + ref method `playAction(name, opts)`
Material variants (configurator)?
→ expose `variant` prop + use KHR_materials_variants
Lazy load on scroll?
→ wrap in Suspense at section level + dynamic import
GLB fetch can fail?
→ wrap in error boundary + provide fallback prop
Playbooks
Playbook A: Hero card single instance
- Suspense at component boundary, fallback
<mesh> placeholder.
useGLTF('/hero.glb') directly.
- No props beyond
scale, position, rotation.
- One animation auto-plays on mount.
Playbook B: Configurator
- Suspense at page section level.
useGLTF shared cache.
- Props:
variant, colorOverride, animationName, onVariantChange.
- Ref:
playAction(name), setVariant(name), triggerExplodedView().
Playbook C: AR viewer with <model-viewer> fallback
- Detect AR support; render R3F path or
<model-viewer> fallback.
- Component exposes both code paths through one prop interface.
Mode handling
Text-only mode
Produce the spec; do not write component code. Leave implementation to the consumer team.
Runtime-ready mode
Component implementation is the consumer's responsibility. This skill never upgrades to "runtime-ready" because runtime is the web app, not BlendOps.
Blocked runtime mode
If consumer stack version is unknown, list per-version caveats.
Validation checklist
Pass / Warn / Fail rubric
| Verdict |
Criteria |
| Pass |
All decision points resolved, props/ref/Suspense/cache/animation/cleanup spec complete, usage example present. |
| Warn |
Spec mostly complete but Suspense placement or caching ambiguous. |
| Fail |
Generates component code (out of scope), claims runtime perf, or omits ref / fallback contract. |
Failure handling
- If user wants component code → redirect: this skill specifies; the consumer implements.
- If R3F version unknown → write per-version caveats.
- If consumer's state management is unknown → make state external via props + onChange callbacks (most portable).
Troubleshooting
| Problem |
Response |
| GLB renders but materials look wrong |
Verify color management (sRGB encoding for color textures, linear for data textures); add caveat. |
| Animation does not play |
Verify clip name matches; ensure useAnimations(clips, scene) is called with correct scene reference. |
| Multiple instances cause lag |
Clone scene via SkeletonUtils.clone() per instance; share geometry, not animation state. |
| Hot-reload breaks model |
useGLTF cache survives HMR; preload + cache-bust on path change. |
Best practices
- Prefer external state via props + callbacks over internal mutable state.
- Always forward ref so the consumer can grab the model root.
- Always wrap in Suspense; never assume sync GLB load.
- Document peer-dep version range in the spec.
Good examples
- "Component spec: props { src, scale=1, animationName='idle', variant?, onLoaded? }, ref methods { playAction(name, opts), setVariant(name) }, Suspense at component boundary, useGLTF shared cache, R3F 8.x."
Bad examples
- "Just useGLTF and render." — no props, no ref, no Suspense, no error path.
- "Will be smooth." — no measurement, no ceiling.
User-facing response template
Component name: <PascalCase>
R3F version: <8.x / 9.x>
Props:
<name>: <type> = <default> // <purpose>
Ref interface:
<method>(args): <returnType>
Suspense placement: <component boundary / page section / app root>
useGLTF caching: <shared cache / per-instance>
Animation hook: <auto-play idle / manual play via ref / scrub>
Cleanup on unmount: <stop animations / dispose materials / no-op>
Error / fallback: <fallback prop / error boundary / placeholder mesh>
Minimal usage:
<code-style snippet>
Limitations: <gaps>
Next: glb-web-handoff with this spec attached
Anti-patterns
- Returning generated component code instead of a spec.
- Promising runtime performance.
- Mixing internal state + external state without a clear default.
- Skipping Suspense.
Cross-skill handoff
- GLB performance budget →
../glb-mobile-performance-budget/SKILL.md
- Animation contract →
../glb-animation-handoff/SKILL.md
- Web handoff summary →
../glb-web-handoff/SKILL.md
- Final response →
../non-blender-user-response-writer/SKILL.md
Non-goals
- Generate component code.
- Run R3F at runtime.
- Verify performance.
- Replace the consumer team's engineering decisions.
References
references/component-shape-patterns.md
references/suspense-placement-rules.md
references/usegltf-caching-rules.md
../../docs/skill-system.md
1---2name: three-fiber-component-shape-planner3description: Plan the React Three Fiber component shape (props, refs, Suspense, useGLTF cache, animation hooks) before delivering a GLB to a web team.4---56# three-fiber-component-shape-planner78## Purpose9Translate a planned GLB delivery into the exact public surface a React Three Fiber component should expose, so the web engineer's contract is locked before code is written.1011## Quick start12- enumerate the props the consumer needs (color, animation name, scale, onLoaded)13- decide ref shape (forwardRef, imperative methods)14- decide Suspense boundary location15- decide useGLTF caching + cleanup strategy16- decide animation hook contract (auto-play, manual control)1718## When to use19- the GLB will ship to a web app using React Three Fiber20- before the web team writes the component21- when "I'll just import the GLB" needs more rigor (multiple clips, prop overrides, lazy loading)2223## When not to use24- consumers using vanilla Three.js (different API)25- consumers using Babylon / model-viewer (different stack)26- the GLB is rendered server-side (e.g. AR pre-render); no React component needed2728## Trigger phrases29- "how should the React component look"30- "what props should I expose"31- "ref shape for the model"32- "we use react-three-fiber"3334## Prerequisites / readiness35- GLB delivery contract known (clips, materials, variants)36- target React/Three.js/R3F versions known (or assume current stable)37- consumer team's preferred state-management style noted (Zustand / context / props)3839## Input schema4041### Required inputs4243| Input | Why it is required |44|---|---|45| GLB delivery contract | Determines what props can vary |46| R3F version | Hook signatures change between R3F 8 / 9 |47| Use case (hero / configurator / AR) | Determines lazy-loading + Suspense placement |48| Customization scope | Color overrides? Animation triggers? Variants? |4950### Optional inputs5152| Input | Use |53|---|---|54| Existing component patterns in the consumer codebase | Maintain consistency |55| Performance budget | Decides whether to use `useGLTF` cache or per-instance load |56| LOD requirements | Triggers `meshoptimizer` / Draco decision points |5758### Assumptions to confirm59- The consumer team can install peer deps (`three`, `@react-three/fiber`, `@react-three/drei`).60- GLB fetched over HTTP is acceptable; no special CDN auth needed.61- Memory pressure from cached GLB scenes is acceptable for the use case.6263## Output schema6465### Primary output66A React Three Fiber component shape spec including:67- Props table (name, type, default, purpose)68- Ref interface (imperative methods exposed)69- Suspense placement (inside vs outside)70- useGLTF caching policy (shared vs per-instance)71- Animation hook contract72- Cleanup contract (unmount behavior)7374### Secondary output75- minimal usage example for the web engineer76- caveats about R3F version compatibility77- error / fallback contract (what shows if GLB fails to load)7879### Evidence / caveat output8081```txt82Runtime status: Not Run | Attempted | Produced | Verified | Failed | Blocked / Not Run83Artifact status: Not Run | Not Produced | Produced | Verified | Failed84Evidence used: <links, paths, logs, or "none">85Limitations: <known gaps>86```8788## Required laws89- `../../laws/evidence-before-done.md`90- `../../laws/non-blender-user-language.md`91- `../../laws/no-arbitrary-python-interface.md`92- `../../laws/official-runtime-only.md`9394## Official runtime boundary9596This skill produces **planning specs only**. It does not generate component code, run a web app, or claim that the resulting component will perform correctly without measured load tests. Web-side implementation is owned by the consumer team.9798If runtime is involved, refer to `../../docs/runtime-stack-strategy.md` for the 2-path + CLI appendix model. R3F lives entirely on the web side and does not interact with Blender at runtime.99100## Operating procedure1011. Read the GLB delivery contract + animation contract.1022. Enumerate consumer customization points → props table.1033. Decide ref shape based on imperative needs (play / pause / setColor).1044. Decide Suspense placement based on use case (hero needs sub-tree fallback; configurator needs page-level fallback).1055. Decide useGLTF caching policy based on instance count + memory.1066. Decide animation hook contract based on trigger model.1077. Produce spec + minimal usage example.1088. Hand off to web engineer + flag verification checklist.109110## Decision tree111112```txt113Multiple instances of the same model?114 → useGLTF cache (shared) + reuse scene clones115Single instance?116 → useGLTF works as-is117Animation triggered by hover/click?118 → expose `animationName` prop + ref method `playAction(name, opts)`119Material variants (configurator)?120 → expose `variant` prop + use KHR_materials_variants121Lazy load on scroll?122 → wrap in Suspense at section level + dynamic import123GLB fetch can fail?124 → wrap in error boundary + provide fallback prop125```126127## Playbooks128129### Playbook A: Hero card single instance130- Suspense at component boundary, fallback `<mesh>` placeholder.131- `useGLTF('/hero.glb')` directly.132- No props beyond `scale`, `position`, `rotation`.133- One animation auto-plays on mount.134135### Playbook B: Configurator136- Suspense at page section level.137- `useGLTF` shared cache.138- Props: `variant`, `colorOverride`, `animationName`, `onVariantChange`.139- Ref: `playAction(name)`, `setVariant(name)`, `triggerExplodedView()`.140141### Playbook C: AR viewer with `<model-viewer>` fallback142- Detect AR support; render R3F path or `<model-viewer>` fallback.143- Component exposes both code paths through one prop interface.144145## Mode handling146147### Text-only mode148Produce the spec; do not write component code. Leave implementation to the consumer team.149150### Runtime-ready mode151Component implementation is the consumer's responsibility. This skill never upgrades to "runtime-ready" because runtime is the web app, not BlendOps.152153### Blocked runtime mode154If consumer stack version is unknown, list per-version caveats.155156## Validation checklist157- [ ] Props table complete with name + type + default + purpose158- [ ] Ref interface specified (or marked "no imperative methods needed")159- [ ] Suspense placement explicit160- [ ] useGLTF caching policy explicit161- [ ] Animation contract explicit (auto / manual / scrub)162- [ ] Cleanup contract explicit163- [ ] Error / fallback contract explicit164- [ ] Minimal usage example included165- [ ] No claim of runtime performance without measurement166- [ ] R3F version targeted167168## Pass / Warn / Fail rubric169170| Verdict | Criteria |171|---|---|172| Pass | All decision points resolved, props/ref/Suspense/cache/animation/cleanup spec complete, usage example present. |173| Warn | Spec mostly complete but Suspense placement or caching ambiguous. |174| Fail | Generates component code (out of scope), claims runtime perf, or omits ref / fallback contract. |175176## Failure handling177- If user wants component code → redirect: this skill specifies; the consumer implements.178- If R3F version unknown → write per-version caveats.179- If consumer's state management is unknown → make state external via props + onChange callbacks (most portable).180181## Troubleshooting182183| Problem | Response |184|---|---|185| GLB renders but materials look wrong | Verify color management (sRGB encoding for color textures, linear for data textures); add caveat. |186| Animation does not play | Verify clip name matches; ensure `useAnimations(clips, scene)` is called with correct scene reference. |187| Multiple instances cause lag | Clone scene via `SkeletonUtils.clone()` per instance; share geometry, not animation state. |188| Hot-reload breaks model | useGLTF cache survives HMR; preload + cache-bust on path change. |189190## Best practices191- Prefer external state via props + callbacks over internal mutable state.192- Always forward ref so the consumer can grab the model root.193- Always wrap in Suspense; never assume sync GLB load.194- Document peer-dep version range in the spec.195196## Good examples197- "Component spec: props { src, scale=1, animationName='idle', variant?, onLoaded? }, ref methods { playAction(name, opts), setVariant(name) }, Suspense at component boundary, useGLTF shared cache, R3F 8.x."198199## Bad examples200- "Just useGLTF and render." — no props, no ref, no Suspense, no error path.201- "Will be smooth." — no measurement, no ceiling.202203## User-facing response template204205```txt206Component name: <PascalCase>207R3F version: <8.x / 9.x>208209Props:210 <name>: <type> = <default> // <purpose>211212Ref interface:213 <method>(args): <returnType>214215Suspense placement: <component boundary / page section / app root>216useGLTF caching: <shared cache / per-instance>217Animation hook: <auto-play idle / manual play via ref / scrub>218Cleanup on unmount: <stop animations / dispose materials / no-op>219Error / fallback: <fallback prop / error boundary / placeholder mesh>220221Minimal usage:222 <code-style snippet>223224Limitations: <gaps>225Next: glb-web-handoff with this spec attached226```227228## Anti-patterns229- Returning generated component code instead of a spec.230- Promising runtime performance.231- Mixing internal state + external state without a clear default.232- Skipping Suspense.233234## Cross-skill handoff235- GLB performance budget → `../glb-mobile-performance-budget/SKILL.md`236- Animation contract → `../glb-animation-handoff/SKILL.md`237- Web handoff summary → `../glb-web-handoff/SKILL.md`238- Final response → `../non-blender-user-response-writer/SKILL.md`239240## Non-goals241- Generate component code.242- Run R3F at runtime.243- Verify performance.244- Replace the consumer team's engineering decisions.245246## References247- `references/component-shape-patterns.md`248- `references/suspense-placement-rules.md`249- `references/usegltf-caching-rules.md`250- `../../docs/skill-system.md`