dreative 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +49 -27
  2. package/dist/cli/audit.js +206 -0
  3. package/dist/cli/audit.test.js +79 -0
  4. package/dist/cli/docsCheck.js +163 -0
  5. package/dist/cli/docsCheck.test.js +8 -0
  6. package/dist/cli/index.js +45 -9
  7. package/dist/server/preview.js +73 -73
  8. package/dist/server/store.js +11 -0
  9. package/dist/shared/artifacts.js +162 -0
  10. package/dist/shared/design.js +42 -22
  11. package/dist/shared/ruleSystem.js +130 -0
  12. package/dist/shared/ruleSystem.test.js +187 -0
  13. package/dist/shared/skillSystem.js +173 -0
  14. package/dist/shared/skillSystem.test.js +110 -0
  15. package/dist/ui/assets/{index--vztc_MR.js → index-CKwmbx2j.js} +13 -13
  16. package/dist/ui/index.html +12 -12
  17. package/package.json +5 -3
  18. package/skill/dreative/DESIGN.md +121 -93
  19. package/skill/dreative/PLAN.md +229 -92
  20. package/skill/dreative/SKILL.md +218 -137
  21. package/skill/dreative/frameworks/nextjs.md +13 -0
  22. package/skill/dreative/frameworks/react-vite.md +12 -0
  23. package/skill/dreative/frameworks/styling.md +14 -0
  24. package/skill/dreative/frameworks/sveltekit.md +10 -0
  25. package/skill/dreative/frameworks/vue-nuxt.md +12 -0
  26. package/skill/dreative/recipes/3d-recipes.md +44 -0
  27. package/skill/dreative/recipes/cinematic-recipes.md +19 -0
  28. package/skill/dreative/recipes/immersive-recipes.md +18 -0
  29. package/skill/dreative/recipes/media-recipes.md +60 -0
  30. package/skill/dreative/recipes/motion-recipes.md +44 -0
  31. package/skill/dreative/references/ARTIFACTS.md +180 -0
  32. package/skill/dreative/references/REFLEX_FONTS.json +44 -0
  33. package/skill/dreative/references/RULES.json +186 -0
  34. package/skill/dreative/references/SKILL_CONTRACT.md +30 -0
  35. package/skill/dreative/references/TIERS.md +42 -0
  36. package/skill/dreative/schemas/plan.schema.json +241 -0
  37. package/skill/dreative/schemas/verify.schema.json +61 -0
  38. package/skill/dreative/skills/3d.md +94 -267
  39. package/skill/dreative/skills/cinematic.md +56 -232
  40. package/skill/dreative/skills/experimental.md +108 -95
  41. package/skill/dreative/skills/immersive.md +61 -223
  42. package/skill/dreative/skills/interaction.md +9 -1
  43. package/skill/dreative/skills/media.md +135 -564
  44. package/skill/dreative/skills/mobile.md +128 -117
  45. package/skill/dreative/skills/motion.md +89 -256
  46. package/skill/dreative/skills/refined.md +116 -102
  47. package/skill/dreative/skills/ux.md +155 -144
  48. package/dist/server/ai.js +0 -177
@@ -1,267 +1,94 @@
1
- # Dreative Specialist Skill — 3D, WebGL & Shaders
2
-
3
- Load this file when `plan.skills` includes `3d`, or the brief/prompt mentions 3D,
4
- WebGL, three.js, shaders, particles, globes, or point clouds. DESIGN.md still
5
- governs everything around the canvas (layout, color, type, motion budgets).
6
- Integrating 3D usually changes component structure (canvas placement, lazy
7
- boundaries, scroll wrappers) when it does, follow DESIGN.md §11's
8
- transformation-depth ladder: offer the restructure, then do it for real.
9
-
10
- ## 0. Does 3D earn its place?
11
-
12
- 3D is the most expensive pixel on the web in bytes, battery, and attention.
13
- It earns its place when the SUBJECT is spatial (a physical product, a device, a
14
- map/globe, an environment, data with real dimensionality) or when the brand brief
15
- explicitly buys a signature 3D moment. It does not earn its place as ambient
16
- decoration: a random floating torus/blob behind hero text is the 3D equivalent of
17
- the gradient blob — banned as a default reach. One 3D moment per page; make it the
18
- signature element (DESIGN.md §2) or don't ship it.
19
-
20
- **At award-site ambition, one 3D prop is REQUIRED, not optional:** the page
21
- ships at least ONE dimensional prop that looks real — a rung-1 GLB or a
22
- rung-2 transparent-background cutout billboard (§3) of a recognizable
23
- subject, photoreal because it IS a photo/render, carrying the full
24
- dimensional kit (parallax against layers, damped ±5-10° rotation, contact
25
- shadow, rim light, multi-angle pseudo-orbit where it earns it) and sitting
26
- in a §1.5 berth. An award plan with zero 3D props is incomplete; a page
27
- whose only "3D" is a background shader plane does not satisfy this — the
28
- prop must be an OBJECT. (Abstract coded forms remain supporting-only and
29
- never count.)
30
-
31
- Cheaper substitutes to consider first: CSS 3D transforms (`perspective` +
32
- `rotateX/Y` on real DOM — free, accessible, great for cards/mockups/tilt), a
33
- pre-rendered video/image sequence scrubbed on scroll, or a Lottie/Rive vector
34
- animation. If the object never needs live lighting or user-driven rotation,
35
- pre-render it — and if a video-generation tool exists in the environment
36
- (PLAN.md §1's probe), a generated loop or frame sequence (media.md §1) is
37
- usually the strongest pre-render source.
38
-
39
- ## 1. Stack
40
-
41
- - **React app → React Three Fiber (`@react-three/fiber`) + `@react-three/drei`.**
42
- Never hand-roll a three.js imperative setup inside React. Drei gives you 80%:
43
- `Environment`, `ContactShadows`, `Float`, `ScrollControls`, `Html`, `Text`,
44
- `useGLTF`, `MeshTransmissionMaterial`, `Center`, `Bounds`.
45
- - **Non-React → three.js** with a small render-loop module; or **OGL** when the
46
- scene is one shader plane and three.js is overkill.
47
- - Post-processing via `@react-three/postprocessing` (Bloom, DoF, Noise) — 1-2
48
- effects max; the stacked-postFX look reads as demo-scene, not product.
49
- - Physics only if interaction demands it (`@react-three/rapier`).
50
-
51
- Lazy-load the entire 3D bundle (`next/dynamic` / `React.lazy`) with an SSR-off
52
- canvas and a styled poster fallback. Three.js must never be in the critical path.
53
-
54
- ## 1.5 Staging: a prop gets a designed berth, never a squat
55
-
56
- Where a 3D element SITS is as much of the craft as what it is. Every 3D
57
- prop/canvas object gets a reserved compositional berth negotiated with the
58
- layout at plan time an empty grid lane, a color-field stage, a gutter the
59
- type deliberately avoids exactly like DESIGN.md §15's travel map. Hard
60
- rules:
61
-
62
- - **Never parked on top of other imagery.** A 3D object overlapping a
63
- photograph or media plane (the floating-orb-over-the-hero-photo failure)
64
- is banned UNLESS it is composited INTO that scene for real: light
65
- direction, color temperature, and a contact/cast shadow all matched so it
66
- reads as part of the photo, not a sticker on it. "Semi-transparent so you
67
- can see the photo through it" is the sticker, not the integration.
68
- - **Never covering text or controls** DESIGN.md §15's occlusion rules
69
- apply at every scroll position.
70
- - The berth is named in the plan blueprint (which section, which lane,
71
- what the type does to make room). A prop with no reserved berth doesn't
72
- ship — the layout must be designed around the object, not the object
73
- dropped onto a finished layout.
74
- - The object is anchored to its berth by scene means: grounded by shadow,
75
- lit by the page's one light direction, cropped by the frame on purpose if
76
- oversized. An object that just floats centered in leftover space reads as
77
- clipart (see §2 grounding).
78
-
79
- ## 2. Scene fundamentals (where amateur scenes fail)
80
-
81
- - **Lighting is the craft.** Default: `<Environment preset="studio"|"city">` for
82
- image-based lighting + ONE key directional light for shadows. Ambient light
83
- alone = flat plastic. Match light temperature to the page palette.
84
- - **Color management:** renderer defaults in modern three are correct
85
- (`outputColorSpace: SRGBColorSpace`, `ACESFilmicToneMapping`) — don't disable
86
- them; DO set `toneMappingExposure` deliberately. Convert hex from the page
87
- palette with `new THREE.Color(hex)` scene colors and page colors must read as
88
- one system.
89
- - **Ground the object:** `<ContactShadows opacity={0.4} blur={2.5}>` or a real
90
- shadow plane. Floating unanchored objects read as clipart.
91
- - Camera: 35-50° FOV for product shots (85°+ distorts); frame with
92
- `<Bounds fit clip>` or `<Center>`; subtle idle via `<Float>` or damped
93
- mouse-parallax (`useFrame` + `THREE.MathUtils.damp`), amplitude ≤ 3°.
94
- - Materials: `meshStandardMaterial`/`meshPhysicalMaterial` with `roughness`/
95
- `metalness` chosen from the real object; `MeshTransmissionMaterial` for glass
96
- (expensive — one object max). Untextured default-gray = unfinished.
97
-
98
- ## 3. Models
99
-
100
- - glTF/GLB only, Draco or Meshopt compressed (`gltf-transform optimize in.glb
101
- out.glb --compress draco`). Budget: hero model ≤ 2-3 MB, ≤ 100k triangles.
102
- - `useGLTF.preload(url)`; wrap in `<Suspense>` with a poster (not a spinner).
103
-
104
- **No model available? Walk the realism ladder — in this order:**
105
-
106
- 1. **Real GLB** the repo/user already has, or one the user can supply.
107
- 2. **Image-billboard prop (the DEFAULT for any real-world subject).** Get
108
- the object as a transparent-background cutout — generate it if an image
109
- tool exists (media.md §1.5 pipeline — verify the alpha is real); with NO
110
- image-gen tool, source a real photo instead (a verified stock/CDN photo of
111
- the subject, matted to transparency with rembg/sharp/ImageMagick if
112
- available, or a photo whose own background already matches the scene so no
113
- matte is needed). Put it on a plane in the scene
114
- (`transparent`, `alphaTest ~0.5`, `toneMapped: false` if pre-graded), and
115
- sell the depth with scene means: parallax against other layers, damped
116
- mouse/scroll rotation of ±5-10° (a flat card barely rotating reads as
117
- dimensional), scroll-linked scale/drift, a soft contact shadow, and a rim
118
- of scene light via a subtle additive duplicate or shader fresnel. Generate
119
- 2-3 angles of the same subject and crossfade/swap by scroll chapter for a
120
- pseudo-orbit. This looks photoreal because it IS a photo — it beats coded
121
- geometry for any organic or textured subject, every time.
122
- 3. **Coded geometry — abstract SUPPORTING forms ONLY.** Primitives/extrusions
123
- are allowed for geometry that is genuinely abstract or hard-surface-simple
124
- (shader planes, ribbons, crystals, grids, a device from rounded boxes with
125
- an `Html` screen) — but only in a SUPPORTING role: background surface,
126
- particle field, atmosphere. **An abstract coded form may never be the
127
- promoted signature object.** A floating sphere/orb/blob/torus — however
128
- shader-textured, however poetic its name ("eclipse", "core", "monolith") —
129
- reads to a visitor as "a stupid orb"; the signature 3D element must be a
130
- RECOGNIZABLE subject a stranger names correctly: a rung-1 GLB, a rung-2
131
- generated/sourced cutout billboard, or a textured mesh of a nameable thing.
132
- If image-gen exists, the signature defaults to rung 2 — generate the subject
133
- as a transparent cutout and sell the depth with scene means. Compositing a
134
- translucent shader sphere ON TOP of a photograph is the canonical form of
135
- this failure and is a ship-blocker, not a signature.
136
- **Modeling an organic or richly-textured real object
137
- (food, beans, plants, fabric, skin, liquid, wood…) from primitives is
138
- BANNED as a visible element** — an untextured lathe/sphere "coffee bean"
139
- reads as a red blob, not a bean; that failure is worse than no 3D. If a
140
- realistic subject must be 3D and no GLB exists, use rung 2.
141
- 4. **Rung 2 unreachable does NOT unlock rung 3.** The organic-subject ban is
142
- unconditional — it does not relax because the environment has no image-gen
143
- tool or the cutout failed. If neither a GLB nor any photo source (rung 2's
144
- no-tool path) exists, the organic 3D element is CUT: replace it with an
145
- abstract signature (shader plane, particles, ribbons — rung-3-legal forms)
146
- or with the sourced photography itself as a scroll-reactive media plane
147
- (media.md §3), and tell the user what asset would unlock the real thing.
148
- (The rung-3 supporting-only restriction still applies to that replacement:
149
- it demotes the moment to atmosphere; it does not mint a new hero orb.)
150
- "We had no tools, so I coded the bean" is the exact failure this rung
151
- exists to stop.
152
-
153
- Any coded mesh that DOES ship must carry a real material identity per
154
- experimental.md §1 — and texture maps can be GENERATED: prompt the image tool
155
- for a tileable albedo/detail texture ("seamless tileable dark roast coffee-bean
156
- surface texture, matte, high detail"), load it as `map` + drive `bumpMap`/
157
- `roughnessMap` from it. With no image tool, source a tileable texture (a real
158
- photo crop, a CC0 texture CDN) or build material identity in a shader
159
- (procedural noise-driven roughness/normal, fresnel rim, environment
160
- reflection). A flat-color `meshStandardMaterial` on a visible custom mesh is a
161
- ship-blocker, not a style — and "no image tool" is not an exemption; if no
162
- texture path exists, the mesh doesn't ship.
163
-
164
- **The subject test is what the element REPRESENTS, not what the code names
165
- it.** If the plan, copy, aria-label, or your own verify prose describes the
166
- mesh as a real thing ("roast core… coffee bean", "the bottle", "a leaf"), it
167
- IS an organic/real subject and the ban applies — renaming a sphere-bean to an
168
- "abstract signature" while shaping and coloring it as a bean is the exact
169
- rationalization this section exists to stop. And texture is MECHANICAL, not
170
- rhetorical: a shipped custom mesh passes only if its material provably carries
171
- a `map`/`normalMap`/`roughnessMap` texture or a custom shader — point to the
172
- line in verify.md. `meshPhysicalMaterial` with a flat `color` plus clearcoat/
173
- roughness numbers is untextured, whatever the verify prose calls it.
174
-
175
- ## 4. Shaders (the highest-leverage 100 lines)
176
-
177
- A fullscreen/plane fragment shader is the cheapest way to a signature visual:
178
- animated gradient meshes, flowfields, displacement on hover, image transitions.
179
-
180
- - Structure: `shaderMaterial` (drei) with `uTime`, `uMouse`, `uResolution`,
181
- palette colors as `uColorA/B/C` uniforms fed FROM the page palette.
182
- - Vocabulary: fbm/simplex noise for organic movement (inline a noise fn; don't
183
- import a library for it), `smoothstep` for banding-free ramps, domain warping
184
- (`noise(p + noise(p))`) for the expensive look, `mix()` between palette colors
185
- only — never rainbow hue-rotation.
186
- - Displace vertices in the vertex shader for cloth/terrain/blob effects; compute
187
- normals or fake lighting with the noise derivative.
188
- - Animate `uTime` at 0.05-0.2 speed; slow reads as premium, fast as screensaver.
189
- - Image effects: sample two textures + a noise mask for transitions; barrel/flow
190
- distortion on scroll velocity for editorial galleries.
191
-
192
- ## 4.5 Media in the scene (images & video as textures)
193
-
194
- The other half of shader craft: real page media rendered THROUGH WebGL so
195
- effects can touch it (the unseen.co gallery mechanic — full pattern in
196
- `skills/media.md` §3):
197
-
198
- - **DOM-synced media planes**: the page's `<img>`/`<video>` elements stay in
199
- the DOM (a11y/layout/fallback, `opacity: 0` never `display:none`) while
200
- textured planes copy their `getBoundingClientRect()` per rAF (lerped).
201
- One scene owns ALL planes — never a canvas per image.
202
- - **Video textures**: `new THREE.VideoTexture(videoEl)` with the element
203
- `muted playsinline` and playing; `texture.colorSpace = SRGBColorSpace`;
204
- generated seamless loops (media.md §1) make the best texture sources —
205
- a pre-rendered loop as a texture often beats a live sim for cost.
206
- - Effects on media planes: hover ripple/lens (damped `uMouse` + radial UV
207
- displacement), velocity stretch + RGB split (clamped, damped decay),
208
- noise-mask dissolves between textures (§4), subtle vertex curvature for
209
- the floating-paper look.
210
- - Failure path is wired, not theoretical: WebGL missing/lost or
211
- reduced-motion → un-hide the DOM media (`opacity: 1`). Verify it fires.
212
-
213
- ## 5. Particles and points
214
-
215
- Points/instancing, never meshes-per-particle: `<Points>` + `BufferAttribute`
216
- positions animated in a shader (`uTime` in the vertex shader), or
217
- `<Instances>`/`InstancedMesh` for repeated geometry (≤ ~10k instances). Counts:
218
- 2-5k points desktop, halve on mobile. Particle color from the page palette at 1-2
219
- hues; size attenuation on; additive blending only on dark surfaces.
220
-
221
- ## 6. Scroll- and layout-integration
222
-
223
- - Canvas placement: either a bounded block IN the layout (preferred — it composes
224
- with the grid) or a full-bleed fixed background with content scrolling over.
225
- Full-page persistent canvases with DOM scrolled on top: use drei
226
- `ScrollControls` + `<Scroll html>` so 3D and DOM share one scroll.
227
- - Scroll-linked 3D: map scroll progress (Motion `useScroll` / ScrollTrigger /
228
- drei `useScroll`) to camera position along a path or object rotation — damped
229
- (`damp3`, `dampE`), never raw-set per frame.
230
- - DOM/3D registration (labels pinned to model parts): drei `<Html transform
231
- occlude>`; keep text as real DOM for accessibility, never texture-baked type.
232
- - The block's `data-dreative-id` goes on the wrapper div around the Canvas.
233
-
234
- ## 7. Performance & fallbacks (ship-blockers)
235
-
236
- - `<Canvas dpr={[1, 2]}>` (cap device pixel ratio), `frameloop="demand"` +
237
- `invalidate()` for static-until-interacted scenes; pause the loop when the
238
- canvas leaves the viewport (IntersectionObserver) and on `document.hidden`.
239
- - One `useFrame` per concern; no allocations inside it (reuse vectors created
240
- outside). Dispose on unmount (R3F handles it; imperative three must
241
- `dispose()` geometries/materials/textures).
242
- - Mobile: halve particle counts, drop post-processing, consider a poster image
243
- below 768px — a janky 3D hero is worse than none.
244
- - `prefers-reduced-motion`: stop idle rotation/particle drift; render one static
245
- well-lit frame (`frameloop="demand"` makes this free).
246
- - WebGL unavailable/context-lost → the poster fallback, never a blank block.
247
- - Keyboard/screen-reader: canvas gets `role="img"` + `aria-label`; any 3D-driven
248
- interaction has a DOM equivalent.
249
-
250
- ## 8. Recipes
251
-
252
- - **Product hero**: GLB + `Environment` + key light + `ContactShadows`, `Float`
253
- idle, damped mouse parallax, scroll scrubs a 90° orbit. Poster until loaded.
254
- **Variant trick (ciaoenergy.com):** ONE model, N variants — swap only the
255
- label/albedo texture (`TextureLoader`, one AVIF per flavor/colorway) on the
256
- same geometry as the user browses variants, and pair each with a
257
- pre-rendered background video loop. Photoreal product-line 3D for the cost
258
- of one GLB. The label texture can be GENERATED (image-gen at the label's
259
- unwrapped aspect) when no real artwork exists.
260
- - **Gradient-mesh hero background**: one plane, fbm + domain-warp fragment shader
261
- mixing 3 palette colors, `uTime` 0.08, `uMouse` warps locally. ~120 lines, no
262
- model, no lighting — the best effort/impact ratio in this file.
263
- - **Point-cloud globe**: sphere-distributed points, shader-animated shimmer,
264
- arcs as `TubeGeometry`/fat lines between coords, slow idle rotation, drag to
265
- spin (damped).
266
- - **Scroll story**: `ScrollControls pages={4}` + camera on a `CatmullRomCurve3`
267
- path, DOM copy in `<Scroll html>`, one damped lookAt target per section.
1
+ # Dreative Specialist Skill — 3D, WebGL & Shaders
2
+
3
+ ## Contract
4
+
5
+ Follow `../references/SKILL_CONTRACT.md`. Dependencies: `ux`, `mobile`; add
6
+ `motion` when scroll/time drives the scene. Deliver a named spatial purpose,
7
+ asset/material source, staged berth, budgets, semantic/poster fallback, and
8
+ runtime evidence.
9
+
10
+ Load for real spatial subjects, WebGL, three.js/R3F, shaders, particles, globes,
11
+ or a plan-defined dimensional signature. 3D is expensive in bytes, battery, and
12
+ attention; it must serve the subject or concept.
13
+
14
+ ## 0. Explore before recipes
15
+
16
+ Record three original brand-native spatial concepts before opening
17
+ `../recipes/3d-recipes.md`. Begin with subject, spatial purpose, recurrence,
18
+ interaction, and berth—not a primitive or shader technique.
19
+
20
+ ## 1. Hard gates
21
+
22
+ - **No coded organic subjects (`3d.noCodedOrganic`).** Food, plants, fabric,
23
+ skin, liquid, wood, or other richly textured real objects never ship as crude
24
+ primitives. Use a real GLB, photoreal cutout, sourced photo, or cut the object.
25
+ - WebGL/context loss/loading/low power/mobile/reduced motion always has a real
26
+ poster or DOM fallback (`effects.runtimeFallback`, `motion.reducedMotion`).
27
+ - Canvas and traveling objects never cover content or controls; pointer events
28
+ and keyboard paths remain intact (`spatial.noOcclusion`, `ux.functional`).
29
+ - Text remains semantic DOM, not texture-baked. Content is visible without 3D.
30
+ - Models/textures/materials named as shipped assets exist and are tracked.
31
+ - Verification proves a live context/draw, interaction, performance, and
32
+ fallback behavior with structured evidence.
33
+
34
+ ## 2. Award spatial signature
35
+
36
+ `award.spatialSignature` requires one unmistakable dimensional or spatial
37
+ signature with depth, recurrence, input response, and visual dominance on
38
+ desktop and mobile.
39
+
40
+ The proven default is:
41
+
42
+ 1. a recognizable real GLB; or
43
+ 2. a photoreal transparent cutout billboard staged with parallax, restrained
44
+ rotation, contact shadow, rim light, and—when useful—multiple angles.
45
+
46
+ This default exists because dogfood coded/shader hero objects repeatedly read as
47
+ generic demos. Valid registered alternatives include spatial typography,
48
+ layered photographic depth, a persistent interactive scene instrument, or a
49
+ data-driven spatial structure that meets declared observable criteria.
50
+
51
+ A generic orb, blob, sphere, torus, or untextured coded form remains invalid as
52
+ a signature. `3d.signatureRecognizable` permits a brand-native abstract
53
+ instrument only when it has a nameable function, material identity, recurrence,
54
+ and input response; ambient decoration does not qualify.
55
+
56
+ ## 3. Staging and material
57
+
58
+ Every object gets a planned berth: section/lane, space reserved by type/layout,
59
+ crop, light direction, shadow/ground, travel states, and hidden states when no
60
+ safe berth exists. It never floats over other imagery unless genuinely
61
+ composited with matched light and cast/contact shadow.
62
+
63
+ Realism comes from material and light, not geometry count:
64
+
65
+ - environment/IBL plus one coherent key direction;
66
+ - deliberate exposure/color management;
67
+ - contact/cast shadow or defensible weightlessness;
68
+ - texture/normal/roughness or a custom procedural shader for visible coded
69
+ geometry;
70
+ - camera FOV/framing appropriate to the subject;
71
+ - damped input and subtle idle behavior.
72
+
73
+ ## 4. Architecture
74
+
75
+ React uses R3F + drei unless the existing stack strongly dictates otherwise;
76
+ one simple shader plane may use OGL/three.js. Lazy-load the whole spatial bundle
77
+ outside the critical path. One scene owns related planes/objects. Reuse vectors
78
+ and buffers; avoid allocations in render loops.
79
+
80
+ Models use optimized GLB/glTF with measured bytes/triangles and a poster during
81
+ load. Particles use points/instancing, not mesh-per-particle. DOM-synced media
82
+ planes keep semantic source media for layout and fallback.
83
+
84
+ ## 5. Performance and verification
85
+
86
+ - Cap DPR and complexity; pause off-screen/hidden work.
87
+ - Mobile reduces particles/post effects or uses a purpose-designed poster.
88
+ - Reduced motion renders a stable, intentional frame.
89
+ - Dispose imperative resources and test route transitions/context restoration.
90
+ - Record transferred weight, frame-time/FPS sample, context/draw evidence,
91
+ object/material identity, desktop/mobile screenshots, input response, and
92
+ poster/context-loss fallback.
93
+
94
+ Recipe reference: `../recipes/3d-recipes.md`, after concept exploration only.