bsmnt 0.0.0
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.
- package/.changeset/2026-02-11-test-patch-bump.md +5 -0
- package/.changeset/README.md +10 -0
- package/.changeset/config.json +16 -0
- package/.cursor/rules/README.md +184 -0
- package/.cursor/rules/architecture.mdc +437 -0
- package/.cursor/rules/components.mdc +436 -0
- package/.cursor/rules/integrations.mdc +447 -0
- package/.cursor/rules/main.mdc +278 -0
- package/.cursor/rules/styling.mdc +433 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/.github/workflows/.gitkeep +0 -0
- package/.github/workflows/ci.yml +37 -0
- package/.github/workflows/release.yml +54 -0
- package/.tldr/cache/call_graph.json +7 -0
- package/.tldr/languages.json +6 -0
- package/.tldr/status +1 -0
- package/.tldrignore +84 -0
- package/.vscode/extensions.json +20 -0
- package/.vscode/settings.json +98 -0
- package/CHANGELOG.md +13 -0
- package/CLAUDE.md +138 -0
- package/README.md +176 -0
- package/bin/index.js +262 -0
- package/biome.json +44 -0
- package/bun.lock +496 -0
- package/changelog/04-02-26.md +86 -0
- package/changelog/05-02-26.md +101 -0
- package/changelog/09-02-26.md +83 -0
- package/docs/fix-studio-hydration.md +46 -0
- package/docs/plans/2026-01-29-sanity-smart-merge-design.md +196 -0
- package/docs/plans/2026-01-29-sanity-smart-merge-implementation.md +695 -0
- package/docs/sanity-setup-steps.md +199 -0
- package/integrations/basehub/README.md +3 -0
- package/integrations/sanity/app/api/draft-mode/disable/route.ts +7 -0
- package/integrations/sanity/app/api/draft-mode/enable/route.ts +21 -0
- package/integrations/sanity/app/api/revalidate/route.ts +37 -0
- package/integrations/sanity/app/layout.tsx +111 -0
- package/integrations/sanity/app/sitemap.ts +80 -0
- package/integrations/sanity/app/studio/[[...tool]]/page.tsx +8 -0
- package/integrations/sanity/app/studio/layout.tsx +7 -0
- package/integrations/sanity/components/ui/sanity-image/index.tsx +37 -0
- package/integrations/sanity/lib/integrations/README.md +58 -0
- package/integrations/sanity/lib/integrations/check-integration.ts +62 -0
- package/integrations/sanity/lib/integrations/sanity/README.md +144 -0
- package/integrations/sanity/lib/integrations/sanity/client.ts +30 -0
- package/integrations/sanity/lib/integrations/sanity/components/disable-draft-mode.tsx +29 -0
- package/integrations/sanity/lib/integrations/sanity/components/rich-text.tsx +73 -0
- package/integrations/sanity/lib/integrations/sanity/env.ts +38 -0
- package/integrations/sanity/lib/integrations/sanity/live/index.tsx +34 -0
- package/integrations/sanity/lib/integrations/sanity/queries.ts +99 -0
- package/integrations/sanity/lib/integrations/sanity/sanity.cli.ts +20 -0
- package/integrations/sanity/lib/integrations/sanity/sanity.config.ts +94 -0
- package/integrations/sanity/lib/integrations/sanity/sanity.types.ts +337 -0
- package/integrations/sanity/lib/integrations/sanity/schema.json +1850 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/article.ts +132 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/example.ts +203 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/index.ts +37 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/link.ts +127 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/metadata.ts +68 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/navigation.ts +39 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/page.ts +77 -0
- package/integrations/sanity/lib/integrations/sanity/schemas/richText.ts +59 -0
- package/integrations/sanity/lib/integrations/sanity/structure.ts +5 -0
- package/integrations/sanity/lib/integrations/sanity/utils/image.ts +11 -0
- package/integrations/sanity/lib/integrations/sanity/utils/link.ts +61 -0
- package/integrations/sanity/lib/scripts/copy-sanity-mcp.ts +23 -0
- package/integrations/sanity/lib/scripts/generate-page.ts +310 -0
- package/integrations/sanity/lib/utils/metadata.ts +190 -0
- package/layers/experiment/components/layout/header/index.tsx +58 -0
- package/layers/experiment/components/layout/navigation-menu.tsx +127 -0
- package/layers/experiment/lib/constants.ts +12 -0
- package/layers/webgl/app/page.tsx +10 -0
- package/layers/webgl/components/webgl/canvas/dynamic.tsx +34 -0
- package/layers/webgl/components/webgl/canvas/index.tsx +43 -0
- package/layers/webgl/components/webgl/components/scene/index.tsx +21 -0
- package/layers/webgpu/.gitkeep +0 -0
- package/package.json +44 -0
- package/plugins/README.md +21 -0
- package/plugins/no-anchor-element.grit +11 -0
- package/plugins/no-relative-parent-imports.grit +6 -0
- package/plugins/no-unnecessary-forwardref.grit +5 -0
- package/src/commands/add-integration.js +325 -0
- package/src/commands/create.js +415 -0
- package/src/commands/setup-sanity.js +426 -0
- package/src/commands/worktree.js +805 -0
- package/src/mergers/check-integration-merger.js +105 -0
- package/src/mergers/config.js +137 -0
- package/src/mergers/index.js +355 -0
- package/src/mergers/layout-merger.js +223 -0
- package/src/mergers/next-config-merger.js +63 -0
- package/src/mergers/sitemap-merger.js +121 -0
- package/tasks/prd-next-starter-dynamic-layers.md +184 -0
- package/tasks/prd.json +153 -0
- package/tasks/progress.txt +115 -0
- package/template-hooks/use-battery.ts +126 -0
- package/template-hooks/use-device-perf.ts +184 -0
- package/template-hooks/use-intersection-observer.ts +32 -0
- package/template-hooks/use-media.ts +33 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
---
|
|
4
|
+
---
|
|
5
|
+
description: React component patterns and WebGL integration
|
|
6
|
+
globs: *.tsx, *.jsx, *.js, *.ts
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Component Guidelines
|
|
10
|
+
|
|
11
|
+
## Imports and Dependencies
|
|
12
|
+
|
|
13
|
+
### Utility Functions
|
|
14
|
+
Always use `cn` from `@/styles/cn` for className conditionals
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { cn } from '@/styles/cn'
|
|
18
|
+
|
|
19
|
+
function MyComponent({ className }) {
|
|
20
|
+
return <div className={cn(s.component, className)} />
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Animation Libraries
|
|
25
|
+
- Use `motion` for animations
|
|
26
|
+
- Use `react-use` for DOM utilities
|
|
27
|
+
|
|
28
|
+
## Component Structure
|
|
29
|
+
|
|
30
|
+
### CSS Modules
|
|
31
|
+
Use CSS modules for component styling. Import styles as `s`
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import s from './component-name.module.css'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Client Components
|
|
38
|
+
Add 'use client' directive for client components
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
'use client'
|
|
42
|
+
|
|
43
|
+
import { useState } from 'react'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Props Interface
|
|
47
|
+
Define props interface at the top of the file. Extend HTML attributes when appropriate.
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import type { ComponentProps } from 'react'
|
|
51
|
+
|
|
52
|
+
interface ButtonProps extends ComponentProps<'button'> {
|
|
53
|
+
variant?: 'primary' | 'secondary'
|
|
54
|
+
size?: 'sm' | 'md' | 'lg'
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### React 19 Ref Handling
|
|
59
|
+
In React 19, ref is passed as a regular prop (no forwardRef needed)
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
// Old pattern (React 18)
|
|
63
|
+
// const Button = forwardRef<HTMLButtonElement, ButtonProps>(...)
|
|
64
|
+
|
|
65
|
+
// New pattern (React 19)
|
|
66
|
+
function Button({ ref, variant = 'primary', ...props }: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) {
|
|
67
|
+
return <button ref={ref} {...props} />
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Default Exports
|
|
72
|
+
Use named function declarations for components. Export the component as default.
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
function Button({ variant = 'primary', size = 'md', ...props }: ButtonProps) {
|
|
76
|
+
// component logic
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default Button
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Form Components
|
|
83
|
+
|
|
84
|
+
-- TODO: Add form handling rules
|
|
85
|
+
|
|
86
|
+
### Server Actions
|
|
87
|
+
Use Server Actions for form submissions when possible. Implement proper error handling.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
async function submitForm(formData: FormData) {
|
|
91
|
+
'use server'
|
|
92
|
+
// server-side logic
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Responsive Design
|
|
97
|
+
|
|
98
|
+
### Device Detection
|
|
99
|
+
Use `useDeviceDetection` hook from `@/hooks/use-device-detection` for device specific logic
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { useDeviceDetection } from '@/hooks/use-device-detection'
|
|
103
|
+
|
|
104
|
+
function ResponsiveComponent() {
|
|
105
|
+
const { isMobile } = useDeviceDetection()
|
|
106
|
+
return isMobile ? <MobileVersion /> : <DesktopVersion />
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Media Breakpoints
|
|
111
|
+
Use `useMediaBreakpoint` hook from `@/hooks/use-media-breakpoint` for media breakpoints detection
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { useMediaBreakpoint } from '@/hooks/use-media-breakpoint'
|
|
115
|
+
|
|
116
|
+
function ResponsiveComponent() {
|
|
117
|
+
const isDesktop = useMediaBreakpoint('desktop')
|
|
118
|
+
return isDesktop ? <DesktopVersion /> : <MobileVersion />
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Viewport Units
|
|
123
|
+
Use custom viewport units for responsive values (see styling.mdc for details)
|
|
124
|
+
|
|
125
|
+
```css
|
|
126
|
+
.element {
|
|
127
|
+
width: tovw(150);
|
|
128
|
+
margin-top: torem(100);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Performance Best Practices
|
|
133
|
+
|
|
134
|
+
### Code Splitting
|
|
135
|
+
Use `next/dynamic` for heavy components
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import dynamic from 'next/dynamic'
|
|
139
|
+
|
|
140
|
+
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
|
|
141
|
+
loading: () => <div>Loading...</div>,
|
|
142
|
+
ssr: false // if needed
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Memoization
|
|
147
|
+
See main.mdc for React Compiler guidance - manual memoization is rarely needed.
|
|
148
|
+
|
|
149
|
+
## Error Handling
|
|
150
|
+
|
|
151
|
+
### Error Boundaries
|
|
152
|
+
Implement error boundaries for critical sections. Provide meaningful fallback UI.
|
|
153
|
+
|
|
154
|
+
### Loading States
|
|
155
|
+
Always handle loading states. Use Suspense boundaries where appropriate.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# WebGL Components
|
|
160
|
+
|
|
161
|
+
## React Three Fiber Setup
|
|
162
|
+
|
|
163
|
+
### Canvas Component
|
|
164
|
+
-- TODO: Add Canvas component rules
|
|
165
|
+
|
|
166
|
+
## WebGL File Organization
|
|
167
|
+
|
|
168
|
+
Separate WebGL logic into `webgl.tsx` files. Keep React logic in main component files.
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
components/
|
|
172
|
+
scene/
|
|
173
|
+
index.tsx # React component
|
|
174
|
+
webgl.tsx # Three.js logic
|
|
175
|
+
scene.module.css # Styles
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### WebGL Component Pattern
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
// scene/webgl.tsx
|
|
182
|
+
import { useFrame } from '@react-three/fiber'
|
|
183
|
+
import { useRef } from 'react'
|
|
184
|
+
import type { Mesh } from 'three'
|
|
185
|
+
|
|
186
|
+
export default function SceneWebGL() {
|
|
187
|
+
const meshRef = useRef<Mesh>(null)
|
|
188
|
+
|
|
189
|
+
useFrame((state, delta) => {
|
|
190
|
+
if (meshRef.current) {
|
|
191
|
+
meshRef.current.rotation.y += delta
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
// Simple logs are auto-stripped in production by Next.js
|
|
196
|
+
console.log('SceneWebGL rendered')
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<mesh ref={meshRef}>
|
|
200
|
+
<boxGeometry args={[1, 1, 1]} />
|
|
201
|
+
<meshStandardMaterial color="hotpink" />
|
|
202
|
+
</mesh>
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Drei Components
|
|
208
|
+
|
|
209
|
+
### Common Helpers
|
|
210
|
+
Use Drei components for common functionality
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import {
|
|
214
|
+
OrbitControls,
|
|
215
|
+
PerspectiveCamera,
|
|
216
|
+
Environment,
|
|
217
|
+
useGLTF,
|
|
218
|
+
useTexture
|
|
219
|
+
} from '@react-three/drei'
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Loading Assets
|
|
223
|
+
Preload assets using Drei hooks. Implement proper loading states.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
// Preload in separate component
|
|
227
|
+
function Preload() {
|
|
228
|
+
const start = performance.now()
|
|
229
|
+
useGLTF.preload('/models/model.glb')
|
|
230
|
+
useTexture.preload('/textures/texture.jpg')
|
|
231
|
+
// Console logs auto-stripped in production by Next.js
|
|
232
|
+
console.log(`Preload took ${performance.now() - start}ms`)
|
|
233
|
+
return null
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Custom Shaders
|
|
238
|
+
|
|
239
|
+
### Shader Materials
|
|
240
|
+
Use template literals for GLSL. Implement proper uniforms.
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
import { shaderMaterial } from '@react-three/drei'
|
|
244
|
+
import { extend } from '@react-three/fiber'
|
|
245
|
+
|
|
246
|
+
const CustomMaterial = shaderMaterial(
|
|
247
|
+
{ uTime: 0, uColor: new THREE.Color(0.0, 0.0, 0.0) },
|
|
248
|
+
vertexShader,
|
|
249
|
+
fragmentShader
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
extend({ CustomMaterial })
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### GLSL Best Practices
|
|
256
|
+
- Keep shaders in separate files when complex
|
|
257
|
+
- Use proper precision qualifiers
|
|
258
|
+
- Comment complex calculations
|
|
259
|
+
|
|
260
|
+
```glsl
|
|
261
|
+
precision mediump float;
|
|
262
|
+
|
|
263
|
+
uniform float uTime;
|
|
264
|
+
varying vec2 vUv;
|
|
265
|
+
|
|
266
|
+
void main() {
|
|
267
|
+
// Shader logic
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Animation & Interaction
|
|
272
|
+
|
|
273
|
+
### Animation Loops
|
|
274
|
+
Use `useFrame` for frame-based animations. Consider performance impact.
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
useFrame((state, delta) => {
|
|
278
|
+
// Animation logic
|
|
279
|
+
}, priority) // Lower priority = runs first
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Interaction
|
|
283
|
+
Use Drei's interaction helpers. Implement proper hover/click states.
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
import { useCursor } from '@react-three/drei'
|
|
287
|
+
|
|
288
|
+
function InteractiveObject() {
|
|
289
|
+
const [hovered, setHovered] = useState(false)
|
|
290
|
+
useCursor(hovered)
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<mesh
|
|
294
|
+
onPointerOver={() => setHovered(true)}
|
|
295
|
+
onPointerOut={() => setHovered(false)}
|
|
296
|
+
>
|
|
297
|
+
{/* geometry and material */}
|
|
298
|
+
</mesh>
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Post-Processing
|
|
304
|
+
|
|
305
|
+
### Effect Composer
|
|
306
|
+
Use postprocessing library for effects. Chain effects efficiently.
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'
|
|
310
|
+
|
|
311
|
+
function Effects() {
|
|
312
|
+
return (
|
|
313
|
+
<EffectComposer>
|
|
314
|
+
<Bloom intensity={1.5} />
|
|
315
|
+
<ChromaticAberration offset={[0.002, 0.002]} />
|
|
316
|
+
</EffectComposer>
|
|
317
|
+
)
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Performance Considerations
|
|
322
|
+
- Limit number of passes
|
|
323
|
+
- Use lower resolution for effects when possible
|
|
324
|
+
- Profile performance impact
|
|
325
|
+
|
|
326
|
+
## WebGL Best Practices
|
|
327
|
+
|
|
328
|
+
### Memory Management
|
|
329
|
+
Dispose of geometries and materials when components unmount. Clean up in useEffect return for complex resources. React Compiler handles most cleanup automatically.
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
useEffect(() => {
|
|
333
|
+
// Only for complex resources that need explicit disposal
|
|
334
|
+
return () => {
|
|
335
|
+
geometry.dispose()
|
|
336
|
+
material.dispose()
|
|
337
|
+
texture.dispose()
|
|
338
|
+
}
|
|
339
|
+
}, [geometry, material, texture])
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Performance Optimization
|
|
343
|
+
See main.mdc for React Compiler guidance. For WebGL-specific object instantiation, always use `useRef`:
|
|
344
|
+
|
|
345
|
+
```tsx
|
|
346
|
+
// ⚠️ EXCEPTION: Object instantiation MUST use useRef to prevent infinite loops
|
|
347
|
+
// Creating new objects on every render creates new references that trigger effects
|
|
348
|
+
|
|
349
|
+
// ❌ DON'T: This causes infinite re-renders
|
|
350
|
+
const flowmap = new Flowmap()
|
|
351
|
+
|
|
352
|
+
// ✅ DO: Use useRef for object instantiation
|
|
353
|
+
const flowmapRef = useRef<Flowmap | null>(null)
|
|
354
|
+
if (!flowmapRef.current) {
|
|
355
|
+
flowmapRef.current = new Flowmap(gl, { size: 128 })
|
|
356
|
+
}
|
|
357
|
+
const flowmap = flowmapRef.current
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Responsive Design
|
|
361
|
+
Handle window resizing. Adjust quality based on device capabilities.
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
const { viewport } = useThree()
|
|
365
|
+
// Use viewport.width, viewport.height for responsive sizing
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## React 19.2 Activity Integration
|
|
369
|
+
|
|
370
|
+
Use `<Activity />` to optimize WebGL performance by deferring off-screen scenes:
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
import { Activity, useEffect, useRef, useState } from 'react'
|
|
374
|
+
import { useRect } from 'hamo'
|
|
375
|
+
import { WebGLTunnel } from '@/lib/webgl/components/tunnel'
|
|
376
|
+
|
|
377
|
+
export function WebGLScene({ className }) {
|
|
378
|
+
const [setRectRef, rect] = useRect()
|
|
379
|
+
const [isVisible, setIsVisible] = useState(true)
|
|
380
|
+
const elementRef = useRef<HTMLDivElement | null>(null)
|
|
381
|
+
|
|
382
|
+
// Intersection Observer with 200px margin for pre-activation
|
|
383
|
+
useEffect(() => {
|
|
384
|
+
const element = elementRef.current
|
|
385
|
+
if (!element) return
|
|
386
|
+
|
|
387
|
+
const observer = new IntersectionObserver(
|
|
388
|
+
([entry]) => setIsVisible(entry.isIntersecting),
|
|
389
|
+
{ rootMargin: '200px' }
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
observer.observe(element)
|
|
393
|
+
return () => observer.disconnect()
|
|
394
|
+
}, [])
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
// Wrap DOM container - defers rect tracking when off-screen
|
|
398
|
+
<Activity mode={isVisible ? 'visible' : 'hidden'}>
|
|
399
|
+
<div ref={(el) => { setRectRef(el); elementRef.current = el }} className={className}>
|
|
400
|
+
{/* WebGL content goes in WebGLTunnel (no Activity wrapper needed) */}
|
|
401
|
+
<WebGLTunnel>
|
|
402
|
+
<WebGLComponent rect={rect} />
|
|
403
|
+
</WebGLTunnel>
|
|
404
|
+
</div>
|
|
405
|
+
</Activity>
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Pattern**: `<Activity />` → DOM container → `WebGLTunnel` → WebGL content
|
|
411
|
+
|
|
412
|
+
### Debugging
|
|
413
|
+
- Use Theatre.js for animation debugging
|
|
414
|
+
- Enable WebGL inspector in development
|
|
415
|
+
- **Always gate debug UI components** - these are NOT auto-removed
|
|
416
|
+
- Simple console logs are auto-stripped in production by Next.js
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
// Simple logs: Auto-stripped in production
|
|
420
|
+
console.log('WebGL state:', { fps, drawCalls, triangles })
|
|
421
|
+
|
|
422
|
+
// Debug components: MUST be gated (not auto-removed)
|
|
423
|
+
{process.env.NODE_ENV === 'development' && <Stats />}
|
|
424
|
+
{process.env.NODE_ENV === 'development' && <Perf />}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Mobile Optimization
|
|
428
|
+
- Reduce polygon count for mobile
|
|
429
|
+
- Use simpler shaders
|
|
430
|
+
- Implement touch controls
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Last updated: 2026-01-26
|