sumulige-claude 1.4.1 → 1.5.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/.claude/MEMORY.md +26 -0
- package/.claude/hooks/hook-registry.json +15 -0
- package/.claude/hooks/live-quality.cjs +286 -0
- package/.claude/hooks/plan-gate.cjs +173 -0
- package/.claude/hooks/pre-commit.cjs +15 -4
- package/.claude/quality-gate.json +19 -4
- package/.claude/rules/linus-style.md +54 -0
- package/.claude/settings.json +19 -1
- package/.claude/settings.local.json +12 -3
- package/.claude/skills/react-best-practices/SKILL.md +125 -0
- package/.claude/skills/threejs-fundamentals/SKILL.md +488 -0
- package/.claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/AGENTS.md +0 -54
- package/CHANGELOG.md +58 -0
- package/demos/power-3d-scatter.html +683 -0
- package/package.json +1 -1
- package/prompts/linus-architect.md +71 -0
|
@@ -135,7 +135,16 @@
|
|
|
135
135
|
"Bash(CLAUDE_PROJECT_DIR=\"/Users/sumulige/Documents/Antigravity/sumulige-claude\" /opt/homebrew/Cellar/node/25.3.0/bin/node .claude/hooks/memory-saver.cjs)",
|
|
136
136
|
"Bash(du:*)",
|
|
137
137
|
"Bash(wc:*)",
|
|
138
|
-
"Bash(/Users/sumulige/.local/share/fnm/node-versions/v24.3.0/installation/bin/node /Users/sumulige/.local/share/fnm/node-versions/v24.3.0/installation/lib/node_modules/npm/bin/npm-cli.js test)"
|
|
138
|
+
"Bash(/Users/sumulige/.local/share/fnm/node-versions/v24.3.0/installation/bin/node /Users/sumulige/.local/share/fnm/node-versions/v24.3.0/installation/lib/node_modules/npm/bin/npm-cli.js test)",
|
|
139
|
+
"Bash(npx skills add:*)",
|
|
140
|
+
"Bash(npx --version)",
|
|
141
|
+
"WebFetch(domain:api.github.com)",
|
|
142
|
+
"Bash(xargs:*)",
|
|
143
|
+
"Bash(CLAUDE_PROJECT_DIR=\"/Users/sumulige/Documents/Antigravity/sumulige-claude\" CLAUDE_TOOL_NAME=\"Write\" CLAUDE_TOOL_INPUT='{\"\"file_path\"\":\"\"/tmp/test.js\"\"}' /opt/homebrew/Cellar/node/25.3.0/bin/node:*)",
|
|
144
|
+
"Bash(CLAUDE_PROJECT_DIR=\"/Users/sumulige/Documents/Antigravity/sumulige-claude\" CLAUDE_TOOL_NAME=\"Write\" CLAUDE_TOOL_INPUT='{\"\"file_path\"\":\"\"/Users/sumulige/Documents/Antigravity/sumulige-claude/lib/commands.js\"\"}' /opt/homebrew/Cellar/node/25.3.0/bin/node /Users/sumulige/Documents/Antigravity/sumulige-claude/.claude/hooks/live-quality.cjs)",
|
|
145
|
+
"Bash(CLAUDE_PROJECT_DIR=\"/Users/sumulige/Documents/Antigravity/sumulige-claude\" CLAUDE_TOOL_NAME=\"Write\" CLAUDE_TOOL_INPUT='{\"\"file_path\"\":\"\"/tmp/test-flow.js\"\"}' /opt/homebrew/Cellar/node/25.3.0/bin/node:*)",
|
|
146
|
+
"Bash(CLAUDE_PROJECT_DIR=\"/Users/sumulige/Documents/Antigravity/sumulige-claude\" CLAUDE_TOOL_NAME=\"Edit\" CLAUDE_TOOL_INPUT='{\"\"file_path\"\":\"\"/Users/sumulige/Documents/Antigravity/sumulige-claude/.claude/hooks/plan-gate.cjs\"\"}' /opt/homebrew/Cellar/node/25.3.0/bin/node:*)",
|
|
147
|
+
"Bash(/opt/homebrew/Cellar/node/25.3.0/bin/npm version 1.5.0 --no-git-tag-version)"
|
|
139
148
|
]
|
|
140
149
|
},
|
|
141
150
|
"hooks": {
|
|
@@ -145,7 +154,7 @@
|
|
|
145
154
|
"hooks": [
|
|
146
155
|
{
|
|
147
156
|
"type": "command",
|
|
148
|
-
"command": "node .claude/hooks/conversation-recorder.cjs user \"$ARGUMENTS\""
|
|
157
|
+
"command": "cd \"$CLAUDE_PROJECT_DIR\" && node .claude/hooks/conversation-recorder.cjs user \"$ARGUMENTS\""
|
|
149
158
|
}
|
|
150
159
|
]
|
|
151
160
|
}
|
|
@@ -156,7 +165,7 @@
|
|
|
156
165
|
"hooks": [
|
|
157
166
|
{
|
|
158
167
|
"type": "command",
|
|
159
|
-
"command": "node .claude/hooks/conversation-recorder.cjs today"
|
|
168
|
+
"command": "cd \"$CLAUDE_PROJECT_DIR\" && node .claude/hooks/conversation-recorder.cjs today"
|
|
160
169
|
}
|
|
161
170
|
]
|
|
162
171
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vercel-react-best-practices
|
|
3
|
+
description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: vercel
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Vercel React Best Practices
|
|
11
|
+
|
|
12
|
+
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
|
|
13
|
+
|
|
14
|
+
## When to Apply
|
|
15
|
+
|
|
16
|
+
Reference these guidelines when:
|
|
17
|
+
- Writing new React components or Next.js pages
|
|
18
|
+
- Implementing data fetching (client or server-side)
|
|
19
|
+
- Reviewing code for performance issues
|
|
20
|
+
- Refactoring existing React/Next.js code
|
|
21
|
+
- Optimizing bundle size or load times
|
|
22
|
+
|
|
23
|
+
## Rule Categories by Priority
|
|
24
|
+
|
|
25
|
+
| Priority | Category | Impact | Prefix |
|
|
26
|
+
|----------|----------|--------|--------|
|
|
27
|
+
| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
|
|
28
|
+
| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
|
|
29
|
+
| 3 | Server-Side Performance | HIGH | `server-` |
|
|
30
|
+
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
|
|
31
|
+
| 5 | Re-render Optimization | MEDIUM | `rerender-` |
|
|
32
|
+
| 6 | Rendering Performance | MEDIUM | `rendering-` |
|
|
33
|
+
| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
|
|
34
|
+
| 8 | Advanced Patterns | LOW | `advanced-` |
|
|
35
|
+
|
|
36
|
+
## Quick Reference
|
|
37
|
+
|
|
38
|
+
### 1. Eliminating Waterfalls (CRITICAL)
|
|
39
|
+
|
|
40
|
+
- `async-defer-await` - Move await into branches where actually used
|
|
41
|
+
- `async-parallel` - Use Promise.all() for independent operations
|
|
42
|
+
- `async-dependencies` - Use better-all for partial dependencies
|
|
43
|
+
- `async-api-routes` - Start promises early, await late in API routes
|
|
44
|
+
- `async-suspense-boundaries` - Use Suspense to stream content
|
|
45
|
+
|
|
46
|
+
### 2. Bundle Size Optimization (CRITICAL)
|
|
47
|
+
|
|
48
|
+
- `bundle-barrel-imports` - Import directly, avoid barrel files
|
|
49
|
+
- `bundle-dynamic-imports` - Use next/dynamic for heavy components
|
|
50
|
+
- `bundle-defer-third-party` - Load analytics/logging after hydration
|
|
51
|
+
- `bundle-conditional` - Load modules only when feature is activated
|
|
52
|
+
- `bundle-preload` - Preload on hover/focus for perceived speed
|
|
53
|
+
|
|
54
|
+
### 3. Server-Side Performance (HIGH)
|
|
55
|
+
|
|
56
|
+
- `server-cache-react` - Use React.cache() for per-request deduplication
|
|
57
|
+
- `server-cache-lru` - Use LRU cache for cross-request caching
|
|
58
|
+
- `server-serialization` - Minimize data passed to client components
|
|
59
|
+
- `server-parallel-fetching` - Restructure components to parallelize fetches
|
|
60
|
+
- `server-after-nonblocking` - Use after() for non-blocking operations
|
|
61
|
+
|
|
62
|
+
### 4. Client-Side Data Fetching (MEDIUM-HIGH)
|
|
63
|
+
|
|
64
|
+
- `client-swr-dedup` - Use SWR for automatic request deduplication
|
|
65
|
+
- `client-event-listeners` - Deduplicate global event listeners
|
|
66
|
+
|
|
67
|
+
### 5. Re-render Optimization (MEDIUM)
|
|
68
|
+
|
|
69
|
+
- `rerender-defer-reads` - Don't subscribe to state only used in callbacks
|
|
70
|
+
- `rerender-memo` - Extract expensive work into memoized components
|
|
71
|
+
- `rerender-dependencies` - Use primitive dependencies in effects
|
|
72
|
+
- `rerender-derived-state` - Subscribe to derived booleans, not raw values
|
|
73
|
+
- `rerender-functional-setstate` - Use functional setState for stable callbacks
|
|
74
|
+
- `rerender-lazy-state-init` - Pass function to useState for expensive values
|
|
75
|
+
- `rerender-transitions` - Use startTransition for non-urgent updates
|
|
76
|
+
|
|
77
|
+
### 6. Rendering Performance (MEDIUM)
|
|
78
|
+
|
|
79
|
+
- `rendering-animate-svg-wrapper` - Animate div wrapper, not SVG element
|
|
80
|
+
- `rendering-content-visibility` - Use content-visibility for long lists
|
|
81
|
+
- `rendering-hoist-jsx` - Extract static JSX outside components
|
|
82
|
+
- `rendering-svg-precision` - Reduce SVG coordinate precision
|
|
83
|
+
- `rendering-hydration-no-flicker` - Use inline script for client-only data
|
|
84
|
+
- `rendering-activity` - Use Activity component for show/hide
|
|
85
|
+
- `rendering-conditional-render` - Use ternary, not && for conditionals
|
|
86
|
+
|
|
87
|
+
### 7. JavaScript Performance (LOW-MEDIUM)
|
|
88
|
+
|
|
89
|
+
- `js-batch-dom-css` - Group CSS changes via classes or cssText
|
|
90
|
+
- `js-index-maps` - Build Map for repeated lookups
|
|
91
|
+
- `js-cache-property-access` - Cache object properties in loops
|
|
92
|
+
- `js-cache-function-results` - Cache function results in module-level Map
|
|
93
|
+
- `js-cache-storage` - Cache localStorage/sessionStorage reads
|
|
94
|
+
- `js-combine-iterations` - Combine multiple filter/map into one loop
|
|
95
|
+
- `js-length-check-first` - Check array length before expensive comparison
|
|
96
|
+
- `js-early-exit` - Return early from functions
|
|
97
|
+
- `js-hoist-regexp` - Hoist RegExp creation outside loops
|
|
98
|
+
- `js-min-max-loop` - Use loop for min/max instead of sort
|
|
99
|
+
- `js-set-map-lookups` - Use Set/Map for O(1) lookups
|
|
100
|
+
- `js-tosorted-immutable` - Use toSorted() for immutability
|
|
101
|
+
|
|
102
|
+
### 8. Advanced Patterns (LOW)
|
|
103
|
+
|
|
104
|
+
- `advanced-event-handler-refs` - Store event handlers in refs
|
|
105
|
+
- `advanced-use-latest` - useLatest for stable callback refs
|
|
106
|
+
|
|
107
|
+
## How to Use
|
|
108
|
+
|
|
109
|
+
Read individual rule files for detailed explanations and code examples:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
rules/async-parallel.md
|
|
113
|
+
rules/bundle-barrel-imports.md
|
|
114
|
+
rules/_sections.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Each rule file contains:
|
|
118
|
+
- Brief explanation of why it matters
|
|
119
|
+
- Incorrect code example with explanation
|
|
120
|
+
- Correct code example with explanation
|
|
121
|
+
- Additional context and references
|
|
122
|
+
|
|
123
|
+
## Full Compiled Document
|
|
124
|
+
|
|
125
|
+
For the complete guide with all rules expanded: `AGENTS.md`
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: threejs-fundamentals
|
|
3
|
+
description: Three.js scene setup, cameras, renderer, Object3D hierarchy, coordinate systems. Use when setting up 3D scenes, creating cameras, configuring renderers, managing object hierarchies, or working with transforms.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Three.js Fundamentals
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
import * as THREE from "three";
|
|
12
|
+
|
|
13
|
+
// Create scene, camera, renderer
|
|
14
|
+
const scene = new THREE.Scene();
|
|
15
|
+
const camera = new THREE.PerspectiveCamera(
|
|
16
|
+
75,
|
|
17
|
+
window.innerWidth / window.innerHeight,
|
|
18
|
+
0.1,
|
|
19
|
+
1000,
|
|
20
|
+
);
|
|
21
|
+
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
|
22
|
+
|
|
23
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
24
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
25
|
+
document.body.appendChild(renderer.domElement);
|
|
26
|
+
|
|
27
|
+
// Add a mesh
|
|
28
|
+
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
29
|
+
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
|
30
|
+
const cube = new THREE.Mesh(geometry, material);
|
|
31
|
+
scene.add(cube);
|
|
32
|
+
|
|
33
|
+
// Add light
|
|
34
|
+
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
|
|
35
|
+
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
|
|
36
|
+
dirLight.position.set(5, 5, 5);
|
|
37
|
+
scene.add(dirLight);
|
|
38
|
+
|
|
39
|
+
camera.position.z = 5;
|
|
40
|
+
|
|
41
|
+
// Animation loop
|
|
42
|
+
function animate() {
|
|
43
|
+
requestAnimationFrame(animate);
|
|
44
|
+
cube.rotation.x += 0.01;
|
|
45
|
+
cube.rotation.y += 0.01;
|
|
46
|
+
renderer.render(scene, camera);
|
|
47
|
+
}
|
|
48
|
+
animate();
|
|
49
|
+
|
|
50
|
+
// Handle resize
|
|
51
|
+
window.addEventListener("resize", () => {
|
|
52
|
+
camera.aspect = window.innerWidth / window.innerHeight;
|
|
53
|
+
camera.updateProjectionMatrix();
|
|
54
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Core Classes
|
|
59
|
+
|
|
60
|
+
### Scene
|
|
61
|
+
|
|
62
|
+
Container for all 3D objects, lights, and cameras.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const scene = new THREE.Scene();
|
|
66
|
+
scene.background = new THREE.Color(0x000000); // Solid color
|
|
67
|
+
scene.background = texture; // Skybox texture
|
|
68
|
+
scene.background = cubeTexture; // Cubemap
|
|
69
|
+
scene.environment = envMap; // Environment map for PBR
|
|
70
|
+
scene.fog = new THREE.Fog(0xffffff, 1, 100); // Linear fog
|
|
71
|
+
scene.fog = new THREE.FogExp2(0xffffff, 0.02); // Exponential fog
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Cameras
|
|
75
|
+
|
|
76
|
+
**PerspectiveCamera** - Most common, simulates human eye.
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
// PerspectiveCamera(fov, aspect, near, far)
|
|
80
|
+
const camera = new THREE.PerspectiveCamera(
|
|
81
|
+
75, // Field of view (degrees)
|
|
82
|
+
window.innerWidth / window.innerHeight, // Aspect ratio
|
|
83
|
+
0.1, // Near clipping plane
|
|
84
|
+
1000, // Far clipping plane
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
camera.position.set(0, 5, 10);
|
|
88
|
+
camera.lookAt(0, 0, 0);
|
|
89
|
+
camera.updateProjectionMatrix(); // Call after changing fov, aspect, near, far
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**OrthographicCamera** - No perspective distortion, good for 2D/isometric.
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// OrthographicCamera(left, right, top, bottom, near, far)
|
|
96
|
+
const aspect = window.innerWidth / window.innerHeight;
|
|
97
|
+
const frustumSize = 10;
|
|
98
|
+
const camera = new THREE.OrthographicCamera(
|
|
99
|
+
(frustumSize * aspect) / -2,
|
|
100
|
+
(frustumSize * aspect) / 2,
|
|
101
|
+
frustumSize / 2,
|
|
102
|
+
frustumSize / -2,
|
|
103
|
+
0.1,
|
|
104
|
+
1000,
|
|
105
|
+
);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**ArrayCamera** - Multiple viewports with sub-cameras.
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const cameras = [];
|
|
112
|
+
for (let i = 0; i < 4; i++) {
|
|
113
|
+
const subcamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);
|
|
114
|
+
subcamera.viewport = new THREE.Vector4(
|
|
115
|
+
Math.floor(i % 2) * 0.5,
|
|
116
|
+
Math.floor(i / 2) * 0.5,
|
|
117
|
+
0.5,
|
|
118
|
+
0.5,
|
|
119
|
+
);
|
|
120
|
+
cameras.push(subcamera);
|
|
121
|
+
}
|
|
122
|
+
const arrayCamera = new THREE.ArrayCamera(cameras);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**CubeCamera** - Renders environment maps for reflections.
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256);
|
|
129
|
+
const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
|
|
130
|
+
scene.add(cubeCamera);
|
|
131
|
+
|
|
132
|
+
// Use for reflections
|
|
133
|
+
material.envMap = cubeRenderTarget.texture;
|
|
134
|
+
|
|
135
|
+
// Update each frame (expensive!)
|
|
136
|
+
cubeCamera.position.copy(reflectiveMesh.position);
|
|
137
|
+
cubeCamera.update(renderer, scene);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### WebGLRenderer
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
const renderer = new THREE.WebGLRenderer({
|
|
144
|
+
canvas: document.querySelector("#canvas"), // Optional existing canvas
|
|
145
|
+
antialias: true, // Smooth edges
|
|
146
|
+
alpha: true, // Transparent background
|
|
147
|
+
powerPreference: "high-performance", // GPU hint
|
|
148
|
+
preserveDrawingBuffer: true, // For screenshots
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
renderer.setSize(width, height);
|
|
152
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
153
|
+
|
|
154
|
+
// Tone mapping
|
|
155
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
156
|
+
renderer.toneMappingExposure = 1.0;
|
|
157
|
+
|
|
158
|
+
// Color space (Three.js r152+)
|
|
159
|
+
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
160
|
+
|
|
161
|
+
// Shadows
|
|
162
|
+
renderer.shadowMap.enabled = true;
|
|
163
|
+
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
164
|
+
|
|
165
|
+
// Clear color
|
|
166
|
+
renderer.setClearColor(0x000000, 1);
|
|
167
|
+
|
|
168
|
+
// Render
|
|
169
|
+
renderer.render(scene, camera);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Object3D
|
|
173
|
+
|
|
174
|
+
Base class for all 3D objects. Mesh, Group, Light, Camera all extend Object3D.
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const obj = new THREE.Object3D();
|
|
178
|
+
|
|
179
|
+
// Transform
|
|
180
|
+
obj.position.set(x, y, z);
|
|
181
|
+
obj.rotation.set(x, y, z); // Euler angles (radians)
|
|
182
|
+
obj.quaternion.set(x, y, z, w); // Quaternion rotation
|
|
183
|
+
obj.scale.set(x, y, z);
|
|
184
|
+
|
|
185
|
+
// Local vs World transforms
|
|
186
|
+
obj.getWorldPosition(targetVector);
|
|
187
|
+
obj.getWorldQuaternion(targetQuaternion);
|
|
188
|
+
obj.getWorldDirection(targetVector);
|
|
189
|
+
|
|
190
|
+
// Hierarchy
|
|
191
|
+
obj.add(child);
|
|
192
|
+
obj.remove(child);
|
|
193
|
+
obj.parent;
|
|
194
|
+
obj.children;
|
|
195
|
+
|
|
196
|
+
// Visibility
|
|
197
|
+
obj.visible = false;
|
|
198
|
+
|
|
199
|
+
// Layers (for selective rendering/raycasting)
|
|
200
|
+
obj.layers.set(1);
|
|
201
|
+
obj.layers.enable(2);
|
|
202
|
+
obj.layers.disable(0);
|
|
203
|
+
|
|
204
|
+
// Traverse hierarchy
|
|
205
|
+
obj.traverse((child) => {
|
|
206
|
+
if (child.isMesh) child.material.color.set(0xff0000);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Matrix updates
|
|
210
|
+
obj.matrixAutoUpdate = true; // Default: auto-update matrices
|
|
211
|
+
obj.updateMatrix(); // Manual matrix update
|
|
212
|
+
obj.updateMatrixWorld(true); // Update world matrix recursively
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Group
|
|
216
|
+
|
|
217
|
+
Empty container for organizing objects.
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
const group = new THREE.Group();
|
|
221
|
+
group.add(mesh1);
|
|
222
|
+
group.add(mesh2);
|
|
223
|
+
scene.add(group);
|
|
224
|
+
|
|
225
|
+
// Transform entire group
|
|
226
|
+
group.position.x = 5;
|
|
227
|
+
group.rotation.y = Math.PI / 4;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Mesh
|
|
231
|
+
|
|
232
|
+
Combines geometry and material.
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
236
|
+
|
|
237
|
+
// Multiple materials (one per geometry group)
|
|
238
|
+
const mesh = new THREE.Mesh(geometry, [material1, material2]);
|
|
239
|
+
|
|
240
|
+
// Useful properties
|
|
241
|
+
mesh.geometry;
|
|
242
|
+
mesh.material;
|
|
243
|
+
mesh.castShadow = true;
|
|
244
|
+
mesh.receiveShadow = true;
|
|
245
|
+
|
|
246
|
+
// Frustum culling
|
|
247
|
+
mesh.frustumCulled = true; // Default: skip if outside camera view
|
|
248
|
+
|
|
249
|
+
// Render order
|
|
250
|
+
mesh.renderOrder = 10; // Higher = rendered later
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Coordinate System
|
|
254
|
+
|
|
255
|
+
Three.js uses a **right-handed coordinate system**:
|
|
256
|
+
|
|
257
|
+
- **+X** points right
|
|
258
|
+
- **+Y** points up
|
|
259
|
+
- **+Z** points toward viewer (out of screen)
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
// Axes helper
|
|
263
|
+
const axesHelper = new THREE.AxesHelper(5);
|
|
264
|
+
scene.add(axesHelper); // Red=X, Green=Y, Blue=Z
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Math Utilities
|
|
268
|
+
|
|
269
|
+
### Vector3
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const v = new THREE.Vector3(x, y, z);
|
|
273
|
+
v.set(x, y, z);
|
|
274
|
+
v.copy(otherVector);
|
|
275
|
+
v.clone();
|
|
276
|
+
|
|
277
|
+
// Operations (modify in place)
|
|
278
|
+
v.add(v2);
|
|
279
|
+
v.sub(v2);
|
|
280
|
+
v.multiply(v2);
|
|
281
|
+
v.multiplyScalar(2);
|
|
282
|
+
v.divideScalar(2);
|
|
283
|
+
v.normalize();
|
|
284
|
+
v.negate();
|
|
285
|
+
v.clamp(min, max);
|
|
286
|
+
v.lerp(target, alpha);
|
|
287
|
+
|
|
288
|
+
// Calculations (return new value)
|
|
289
|
+
v.length();
|
|
290
|
+
v.lengthSq(); // Faster than length()
|
|
291
|
+
v.distanceTo(v2);
|
|
292
|
+
v.dot(v2);
|
|
293
|
+
v.cross(v2); // Modifies v
|
|
294
|
+
v.angleTo(v2);
|
|
295
|
+
|
|
296
|
+
// Transform
|
|
297
|
+
v.applyMatrix4(matrix);
|
|
298
|
+
v.applyQuaternion(q);
|
|
299
|
+
v.project(camera); // World to NDC
|
|
300
|
+
v.unproject(camera); // NDC to world
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Matrix4
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
const m = new THREE.Matrix4();
|
|
307
|
+
m.identity();
|
|
308
|
+
m.copy(other);
|
|
309
|
+
m.clone();
|
|
310
|
+
|
|
311
|
+
// Build transforms
|
|
312
|
+
m.makeTranslation(x, y, z);
|
|
313
|
+
m.makeRotationX(theta);
|
|
314
|
+
m.makeRotationY(theta);
|
|
315
|
+
m.makeRotationZ(theta);
|
|
316
|
+
m.makeRotationFromQuaternion(q);
|
|
317
|
+
m.makeScale(x, y, z);
|
|
318
|
+
|
|
319
|
+
// Compose/decompose
|
|
320
|
+
m.compose(position, quaternion, scale);
|
|
321
|
+
m.decompose(position, quaternion, scale);
|
|
322
|
+
|
|
323
|
+
// Operations
|
|
324
|
+
m.multiply(m2); // m = m * m2
|
|
325
|
+
m.premultiply(m2); // m = m2 * m
|
|
326
|
+
m.invert();
|
|
327
|
+
m.transpose();
|
|
328
|
+
|
|
329
|
+
// Camera matrices
|
|
330
|
+
m.makePerspective(left, right, top, bottom, near, far);
|
|
331
|
+
m.makeOrthographic(left, right, top, bottom, near, far);
|
|
332
|
+
m.lookAt(eye, target, up);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Quaternion
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
const q = new THREE.Quaternion();
|
|
339
|
+
q.setFromEuler(euler);
|
|
340
|
+
q.setFromAxisAngle(axis, angle);
|
|
341
|
+
q.setFromRotationMatrix(matrix);
|
|
342
|
+
|
|
343
|
+
q.multiply(q2);
|
|
344
|
+
q.slerp(target, t); // Spherical interpolation
|
|
345
|
+
q.normalize();
|
|
346
|
+
q.invert();
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Euler
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
const euler = new THREE.Euler(x, y, z, "XYZ"); // Order matters!
|
|
353
|
+
euler.setFromQuaternion(q);
|
|
354
|
+
euler.setFromRotationMatrix(m);
|
|
355
|
+
|
|
356
|
+
// Rotation orders: 'XYZ', 'YXZ', 'ZXY', 'XZY', 'YZX', 'ZYX'
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Color
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
const color = new THREE.Color(0xff0000);
|
|
363
|
+
const color = new THREE.Color("red");
|
|
364
|
+
const color = new THREE.Color("rgb(255, 0, 0)");
|
|
365
|
+
const color = new THREE.Color("#ff0000");
|
|
366
|
+
|
|
367
|
+
color.setHex(0x00ff00);
|
|
368
|
+
color.setRGB(r, g, b); // 0-1 range
|
|
369
|
+
color.setHSL(h, s, l); // 0-1 range
|
|
370
|
+
|
|
371
|
+
color.lerp(otherColor, alpha);
|
|
372
|
+
color.multiply(otherColor);
|
|
373
|
+
color.multiplyScalar(2);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### MathUtils
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
THREE.MathUtils.clamp(value, min, max);
|
|
380
|
+
THREE.MathUtils.lerp(start, end, alpha);
|
|
381
|
+
THREE.MathUtils.mapLinear(value, inMin, inMax, outMin, outMax);
|
|
382
|
+
THREE.MathUtils.degToRad(degrees);
|
|
383
|
+
THREE.MathUtils.radToDeg(radians);
|
|
384
|
+
THREE.MathUtils.randFloat(min, max);
|
|
385
|
+
THREE.MathUtils.randInt(min, max);
|
|
386
|
+
THREE.MathUtils.smoothstep(x, min, max);
|
|
387
|
+
THREE.MathUtils.smootherstep(x, min, max);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Common Patterns
|
|
391
|
+
|
|
392
|
+
### Proper Cleanup
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
function dispose() {
|
|
396
|
+
// Dispose geometries
|
|
397
|
+
mesh.geometry.dispose();
|
|
398
|
+
|
|
399
|
+
// Dispose materials
|
|
400
|
+
if (Array.isArray(mesh.material)) {
|
|
401
|
+
mesh.material.forEach((m) => m.dispose());
|
|
402
|
+
} else {
|
|
403
|
+
mesh.material.dispose();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Dispose textures
|
|
407
|
+
texture.dispose();
|
|
408
|
+
|
|
409
|
+
// Remove from scene
|
|
410
|
+
scene.remove(mesh);
|
|
411
|
+
|
|
412
|
+
// Dispose renderer
|
|
413
|
+
renderer.dispose();
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Clock for Animation
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
const clock = new THREE.Clock();
|
|
421
|
+
|
|
422
|
+
function animate() {
|
|
423
|
+
const delta = clock.getDelta(); // Time since last frame (seconds)
|
|
424
|
+
const elapsed = clock.getElapsedTime(); // Total time (seconds)
|
|
425
|
+
|
|
426
|
+
mesh.rotation.y += delta * 0.5; // Consistent speed regardless of framerate
|
|
427
|
+
|
|
428
|
+
requestAnimationFrame(animate);
|
|
429
|
+
renderer.render(scene, camera);
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Responsive Canvas
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
function onWindowResize() {
|
|
437
|
+
const width = window.innerWidth;
|
|
438
|
+
const height = window.innerHeight;
|
|
439
|
+
|
|
440
|
+
camera.aspect = width / height;
|
|
441
|
+
camera.updateProjectionMatrix();
|
|
442
|
+
|
|
443
|
+
renderer.setSize(width, height);
|
|
444
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
445
|
+
}
|
|
446
|
+
window.addEventListener("resize", onWindowResize);
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Loading Manager
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
const manager = new THREE.LoadingManager();
|
|
453
|
+
|
|
454
|
+
manager.onStart = (url, loaded, total) => console.log("Started loading");
|
|
455
|
+
manager.onLoad = () => console.log("All loaded");
|
|
456
|
+
manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}`);
|
|
457
|
+
manager.onError = (url) => console.error(`Error loading ${url}`);
|
|
458
|
+
|
|
459
|
+
const textureLoader = new THREE.TextureLoader(manager);
|
|
460
|
+
const gltfLoader = new GLTFLoader(manager);
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Performance Tips
|
|
464
|
+
|
|
465
|
+
1. **Limit draw calls**: Merge geometries, use instancing, atlas textures
|
|
466
|
+
2. **Frustum culling**: Enabled by default, ensure bounding boxes are correct
|
|
467
|
+
3. **LOD (Level of Detail)**: Use `THREE.LOD` for distance-based mesh switching
|
|
468
|
+
4. **Object pooling**: Reuse objects instead of creating/destroying
|
|
469
|
+
5. **Avoid `getWorldPosition` in loops**: Cache results
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
// Merge static geometries
|
|
473
|
+
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
474
|
+
const merged = mergeGeometries([geo1, geo2, geo3]);
|
|
475
|
+
|
|
476
|
+
// LOD
|
|
477
|
+
const lod = new THREE.LOD();
|
|
478
|
+
lod.addLevel(highDetailMesh, 0);
|
|
479
|
+
lod.addLevel(medDetailMesh, 50);
|
|
480
|
+
lod.addLevel(lowDetailMesh, 100);
|
|
481
|
+
scene.add(lod);
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## See Also
|
|
485
|
+
|
|
486
|
+
- `threejs-geometry` - Geometry creation and manipulation
|
|
487
|
+
- `threejs-materials` - Material types and properties
|
|
488
|
+
- `threejs-lighting` - Light types and shadows
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: web-design-guidelines
|
|
3
|
+
description: Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
|
|
4
|
+
metadata:
|
|
5
|
+
author: vercel
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
argument-hint: <file-or-pattern>
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Web Interface Guidelines
|
|
11
|
+
|
|
12
|
+
Review files for compliance with Web Interface Guidelines.
|
|
13
|
+
|
|
14
|
+
## How It Works
|
|
15
|
+
|
|
16
|
+
1. Fetch the latest guidelines from the source URL below
|
|
17
|
+
2. Read the specified files (or prompt user for files/pattern)
|
|
18
|
+
3. Check against all rules in the fetched guidelines
|
|
19
|
+
4. Output findings in the terse `file:line` format
|
|
20
|
+
|
|
21
|
+
## Guidelines Source
|
|
22
|
+
|
|
23
|
+
Fetch fresh guidelines before each review:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Use WebFetch to retrieve the latest rules. The fetched content contains all the rules and output format instructions.
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
When a user provides a file or pattern argument:
|
|
34
|
+
1. Fetch guidelines from the source URL above
|
|
35
|
+
2. Read the specified files
|
|
36
|
+
3. Apply all rules from the fetched guidelines
|
|
37
|
+
4. Output findings using the format specified in the guidelines
|
|
38
|
+
|
|
39
|
+
If no files specified, ask the user which files to review.
|