@vosjs/cli 0.46.1 → 0.48.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/README.md +15 -5
- package/dist/{chunk-UE66DC2K.js → chunk-ANKECV7F.js} +658 -60
- package/dist/chunk-ANKECV7F.js.map +1 -0
- package/dist/{chunk-ID4OUS5L.js → chunk-AUPGJJTL.js} +18 -1
- package/dist/chunk-AUPGJJTL.js.map +1 -0
- package/dist/{chunk-EFI3WUQB.js → chunk-P3X5KVA6.js} +15 -2
- package/dist/{chunk-EFI3WUQB.js.map → chunk-P3X5KVA6.js.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.js +3 -3
- package/dist/manifest-A4R367EM.js +8 -0
- package/dist/{run-2OZS25ER.js → run-CYHH56KA.js} +3 -3
- package/dist/{shotList-JC4A3FBT.js → shotList-7F2FE3RU.js} +2 -2
- package/package.json +9 -7
- package/schema/actions.schema.json +2 -2
- package/skills/VERSION +1 -0
- package/skills/launch-kit/SKILL.md +356 -0
- package/skills/launch-kit/references/channel-specs.md +56 -0
- package/skills/product-video/SKILL.md +263 -0
- package/skills/product-video/references/destinations.md +71 -0
- package/skills/product-video/references/sessions.md +226 -0
- package/skills/product-video/references/taste.md +115 -0
- package/skills/product-video/references/troubleshooting.md +116 -0
- package/skills/vos-authoring/SKILL.md +191 -0
- package/skills/vos-authoring/references/examples.md +239 -0
- package/skills/vos-authoring/references/schema-reference.md +468 -0
- package/skills/vos-create/SKILL.md +258 -0
- package/skills/vos-cut/SKILL.md +241 -0
- package/skills/vos-footage/SKILL.md +98 -0
- package/skills/vos-migrate/SKILL.md +108 -0
- package/skills/vos-remix/SKILL.md +136 -0
- package/skills/vos-remix/references/3d-recipe.md +37 -0
- package/skills/vos-remix/references/params-knobs.md +80 -0
- package/skills/vos-remix/references/remix-contract.md +81 -0
- package/dist/chunk-ID4OUS5L.js.map +0 -1
- package/dist/chunk-UE66DC2K.js.map +0 -1
- package/dist/manifest-UCS6OVWZ.js +0 -8
- /package/dist/{manifest-UCS6OVWZ.js.map → manifest-A4R367EM.js.map} +0 -0
- /package/dist/{run-2OZS25ER.js.map → run-CYHH56KA.js.map} +0 -0
- /package/dist/{shotList-JC4A3FBT.js.map → shotList-7F2FE3RU.js.map} +0 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
# VosConfigJson Schema Reference
|
|
2
|
+
|
|
3
|
+
Complete API reference for generating VosConfigJson configs.
|
|
4
|
+
|
|
5
|
+
## Top-Level Fields
|
|
6
|
+
|
|
7
|
+
| Field | Type | Required | Default | Description |
|
|
8
|
+
|-------|------|----------|---------|-------------|
|
|
9
|
+
| `version` | `number` | Yes | — | Always `2` |
|
|
10
|
+
| `duration` | `number` | Yes | — | Animation duration in seconds (typically 4-30) |
|
|
11
|
+
| `scene` | `SceneConfig` | No | — | Background color and fog |
|
|
12
|
+
| `camera` | `CameraConfig` | Yes | — | Camera preset and parameters |
|
|
13
|
+
| `postprocessing` | `PostprocessingEffect[]` | No | — | Global post-processing effects |
|
|
14
|
+
| `perLayerEffects` | `PostprocessingEffect[]` | No | — | Effects for objects with matching zIndex |
|
|
15
|
+
| `dynamicLayers` | `boolean` | No | `false` | Rebuild render groups when zIndex changes at runtime |
|
|
16
|
+
| `elements` | `ElementConfig[]` | No | — | 2D overlay elements |
|
|
17
|
+
| `setup` | `string` | No | — | Async function for loading assets |
|
|
18
|
+
| `createContent` | `string` | Yes | — | Function that builds scene content |
|
|
19
|
+
| `createTimeline` | `string` | Yes | — | Function that creates GSAP timeline |
|
|
20
|
+
| `onFrame` | `string` | No | — | Per-frame update callback (prefer onUpdate in timeline) |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Scene Config
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"scene": {
|
|
29
|
+
"background": "#1a1a2e",
|
|
30
|
+
"fog": { "type": "exp2", "color": 0, "density": 0.02 }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Field | Type | Description |
|
|
36
|
+
|-------|------|-------------|
|
|
37
|
+
| `background` | `number \| string` | Hex color: `0x1a1a2e` or `"#1a1a2e"` |
|
|
38
|
+
| `fog.type` | `"exp2" \| "linear"` | Fog falloff type |
|
|
39
|
+
| `fog.color` | `number \| string` | Fog color |
|
|
40
|
+
| `fog.density` | `number` | Exp2 fog density (0.01-0.1 typical) |
|
|
41
|
+
| `fog.near` | `number` | Linear fog start distance |
|
|
42
|
+
| `fog.far` | `number` | Linear fog end distance |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Camera Config
|
|
47
|
+
|
|
48
|
+
### Perspective
|
|
49
|
+
```json
|
|
50
|
+
{ "preset": "perspective", "fov": 60, "position": [0, 2, 8], "lookAt": [0, 0, 0], "near": 0.1, "far": 1000 }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Orthographic
|
|
54
|
+
```json
|
|
55
|
+
{ "preset": "orthographic", "zoom": 80, "position": [20, 20, 20], "lookAt": [0, 0, 0] }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Fullscreen (for shaders/2D)
|
|
59
|
+
```json
|
|
60
|
+
{ "preset": "fullscreen" }
|
|
61
|
+
```
|
|
62
|
+
Creates `OrthographicCamera(-1, 1, 1, -1, 0, 1)` for clip-space rendering.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Post-Processing Effects
|
|
67
|
+
|
|
68
|
+
Always end the array with `{ "type": "output" }`.
|
|
69
|
+
|
|
70
|
+
### Bloom
|
|
71
|
+
```json
|
|
72
|
+
{ "type": "bloom", "strength": 1.0, "radius": 0.5, "threshold": 0 }
|
|
73
|
+
```
|
|
74
|
+
| Param | Default | Description |
|
|
75
|
+
|-------|---------|-------------|
|
|
76
|
+
| `strength` | 1.0 | Glow intensity |
|
|
77
|
+
| `radius` | 0.5 | Glow spread |
|
|
78
|
+
| `threshold` | 0 | Brightness cutoff (0 = everything glows) |
|
|
79
|
+
|
|
80
|
+
### Glitch
|
|
81
|
+
```json
|
|
82
|
+
{ "type": "glitch", "goWild": false }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Film Grain
|
|
86
|
+
```json
|
|
87
|
+
{ "type": "filmGrain", "intensity": 0.5 }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Dot Screen
|
|
91
|
+
```json
|
|
92
|
+
{ "type": "dotScreen", "scale": 1.0 }
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Output (required last)
|
|
96
|
+
```json
|
|
97
|
+
{ "type": "output" }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Per-Layer Effects
|
|
103
|
+
|
|
104
|
+
Apply effects selectively to objects grouped by `userData.zIndex`:
|
|
105
|
+
|
|
106
|
+
**Config:**
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"perLayerEffects": [
|
|
110
|
+
{ "type": "bloom", "strength": 1.2, "radius": 0.4, "threshold": 0.2 },
|
|
111
|
+
{ "type": "output" }
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**In createContent:**
|
|
117
|
+
```javascript
|
|
118
|
+
sphere.userData.zIndex = 50
|
|
119
|
+
sphere.userData.postprocessing = [
|
|
120
|
+
{ type: 'bloom', strength: 1.2, radius: 0.4, threshold: 0.2 },
|
|
121
|
+
{ type: 'output' }
|
|
122
|
+
]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Objects without `userData.zIndex` stay on the default layer (no per-layer effects applied).
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## VosContext (ctx)
|
|
130
|
+
|
|
131
|
+
### Available in ALL functions
|
|
132
|
+
|
|
133
|
+
| Property | Type | Description |
|
|
134
|
+
|----------|------|-------------|
|
|
135
|
+
| `ctx.THREE` | `THREE` | Three.js library (r160+) |
|
|
136
|
+
| `ctx.resolution` | `Resolution` | `{ width, height, pixelRatio, drawingBufferWidth, drawingBufferHeight }` |
|
|
137
|
+
|
|
138
|
+
### Available in setup
|
|
139
|
+
|
|
140
|
+
| Property | Type | Description |
|
|
141
|
+
|----------|------|-------------|
|
|
142
|
+
| `ctx.loaders` | `object` | Loader constructors (see Loaders section) |
|
|
143
|
+
| `ctx.utils` | `object` | Utility constructors (see Utils section) |
|
|
144
|
+
|
|
145
|
+
### Available in createContent and createTimeline
|
|
146
|
+
|
|
147
|
+
| Property | Type | Description |
|
|
148
|
+
|----------|------|-------------|
|
|
149
|
+
| `ctx.gsap` | `gsap` | GSAP animation library |
|
|
150
|
+
| `ctx.scene` | `THREE.Scene` | Main scene |
|
|
151
|
+
| `ctx.camera` | `THREE.Camera` | Configured camera |
|
|
152
|
+
| `ctx.renderer` | `THREE.WebGLRenderer` | WebGL renderer |
|
|
153
|
+
| `ctx.elements` | `Map` | Element instances: `.get(id)` returns `{ props, segments? }` |
|
|
154
|
+
| `ctx.composer` | `EffectComposer` | Available when postprocessing is defined |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Function Signatures
|
|
159
|
+
|
|
160
|
+
### setup (optional)
|
|
161
|
+
```javascript
|
|
162
|
+
"async (ctx) => { /* load assets */ return { font, envMap, model } }"
|
|
163
|
+
```
|
|
164
|
+
- Load fonts, textures, models, HDR maps using `ctx.loaders`
|
|
165
|
+
- Return data object — passed as `setupData` to `createContent`
|
|
166
|
+
|
|
167
|
+
### createContent (required)
|
|
168
|
+
```javascript
|
|
169
|
+
"(ctx, setupData?) => { /* build scene */ return { objects, refs, dispose } }"
|
|
170
|
+
```
|
|
171
|
+
- Create meshes, lights, materials. Add to `ctx.scene`.
|
|
172
|
+
- Return:
|
|
173
|
+
- `objects`: `THREE.Object3D[]` — all objects added to scene (for cleanup)
|
|
174
|
+
- `refs`: `object` — named references passed to `createTimeline`
|
|
175
|
+
- `dispose`: `() => void` — cleanup function for geometries/materials/textures
|
|
176
|
+
|
|
177
|
+
### createTimeline (required)
|
|
178
|
+
```javascript
|
|
179
|
+
"(ctx, content, duration) => { /* animate */ return tl }"
|
|
180
|
+
```
|
|
181
|
+
- `content` is the return value of `createContent`
|
|
182
|
+
- Create timeline: `ctx.gsap.timeline({ paused: true })`
|
|
183
|
+
- Access refs via `content.refs`
|
|
184
|
+
- Return the timeline
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Loaders (via ctx.loaders)
|
|
189
|
+
|
|
190
|
+
### Constructors
|
|
191
|
+
| Loader | Usage |
|
|
192
|
+
|--------|-------|
|
|
193
|
+
| `new ctx.loaders.FontLoader()` | `.load(url, callback)` or wrap in Promise |
|
|
194
|
+
| `new ctx.loaders.GLTFLoader()` | `.loadAsync(url)` returns `{ scene, animations }` |
|
|
195
|
+
| `new ctx.loaders.DRACOLoader()` | DRACO mesh decompression |
|
|
196
|
+
| `new ctx.loaders.HDRLoader()` | `.loadAsync(url)` returns HDR texture |
|
|
197
|
+
| `new ctx.loaders.EXRLoader()` | `.loadAsync(url)` returns EXR texture |
|
|
198
|
+
| `new ctx.loaders.TextureLoader()` | `.loadAsync(url)` returns Texture |
|
|
199
|
+
| `new ctx.loaders.CubeTextureLoader()` | `.load([urls])` returns CubeTexture |
|
|
200
|
+
|
|
201
|
+
### Pre-configured Instances
|
|
202
|
+
| Instance | Description |
|
|
203
|
+
|----------|-------------|
|
|
204
|
+
| `ctx.loaders.gltf` | GLTFLoader with DRACO decoder auto-attached |
|
|
205
|
+
| `ctx.loaders.draco` | DRACOLoader with decoder path pre-set |
|
|
206
|
+
|
|
207
|
+
### Loading Patterns
|
|
208
|
+
|
|
209
|
+
**Font (callback-based):**
|
|
210
|
+
```javascript
|
|
211
|
+
const font = await new Promise((resolve) => {
|
|
212
|
+
new ctx.loaders.FontLoader().load(
|
|
213
|
+
'https://cdn.jsdelivr.net/npm/three@0.183.0/examples/fonts/helvetiker_bold.typeface.json',
|
|
214
|
+
resolve
|
|
215
|
+
)
|
|
216
|
+
})
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**HDR Environment:**
|
|
220
|
+
```javascript
|
|
221
|
+
const hdr = await new ctx.loaders.HDRLoader().loadAsync('https://dl.polyhaven.org/file/ph-assets/HDRIs/hdr/1k/royal_esplanade_1k.hdr')
|
|
222
|
+
hdr.mapping = ctx.THREE.EquirectangularReflectionMapping
|
|
223
|
+
return { envMap: hdr }
|
|
224
|
+
// In createContent: ctx.scene.environment = setupData.envMap
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**GLTF Model:**
|
|
228
|
+
```javascript
|
|
229
|
+
const gltf = await ctx.loaders.gltf.loadAsync(url)
|
|
230
|
+
return { model: gltf.scene, animations: gltf.animations }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Utilities (via ctx.utils)
|
|
236
|
+
|
|
237
|
+
| Utility | Usage |
|
|
238
|
+
|---------|-------|
|
|
239
|
+
| `ctx.utils.TextGeometry` | `new ctx.utils.TextGeometry('TEXT', { font, size, height, bevelEnabled, ... })` |
|
|
240
|
+
| `ctx.utils.MeshSurfaceSampler` | `new ctx.utils.MeshSurfaceSampler(mesh).build()` then `.sample(vec3)` |
|
|
241
|
+
| `ctx.utils.BufferGeometryUtils` | `.mergeGeometries([geo1, geo2])`, `.computeMorphedAttributes()` |
|
|
242
|
+
|
|
243
|
+
### TextGeometry Parameters
|
|
244
|
+
```javascript
|
|
245
|
+
new ctx.utils.TextGeometry('TEXT', {
|
|
246
|
+
font: loadedFont,
|
|
247
|
+
size: 10,
|
|
248
|
+
height: 2, // extrude depth
|
|
249
|
+
curveSegments: 12,
|
|
250
|
+
bevelEnabled: true,
|
|
251
|
+
bevelThickness: 1,
|
|
252
|
+
bevelSize: 0.5,
|
|
253
|
+
bevelSegments: 8
|
|
254
|
+
})
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Elements (2D Overlays)
|
|
260
|
+
|
|
261
|
+
Elements are 2D content rendered as textured planes in the WebGL scene. They are NOT HTML — no CSS properties.
|
|
262
|
+
|
|
263
|
+
### Common Fields (all types)
|
|
264
|
+
|
|
265
|
+
| Field | Type | Required | Default | Description |
|
|
266
|
+
|-------|------|----------|---------|-------------|
|
|
267
|
+
| `type` | `"text" \| "image" \| "svg" \| "video"` | Yes | — | Element type |
|
|
268
|
+
| `position` | `string \| {x, y}` | Yes | — | Position preset or coordinates |
|
|
269
|
+
| `id` | `string` | No | — | ID for referencing in createTimeline |
|
|
270
|
+
| `anchor` | `string` | No | `"center"` | Anchor point for positioning |
|
|
271
|
+
| `zIndex` | `number` | No | `100` | Layer order (higher = on top of 3D) |
|
|
272
|
+
| `opacity` | `number` | No | `1` | Opacity 0-1 |
|
|
273
|
+
| `transform` | `Transform` | No | — | 3D transform overrides |
|
|
274
|
+
|
|
275
|
+
### Position Presets
|
|
276
|
+
`"center"`, `"top-left"`, `"top-center"`, `"top-right"`, `"center-left"`, `"center-right"`, `"bottom-left"`, `"bottom-center"`, `"bottom-right"`
|
|
277
|
+
|
|
278
|
+
Or pixel/percentage: `{ "x": 100, "y": 50 }` / `{ "x": "50%", "y": "25%" }`
|
|
279
|
+
|
|
280
|
+
### Transform
|
|
281
|
+
```json
|
|
282
|
+
{ "translateX": 0, "translateY": 0, "translateZ": 0, "rotation": 0, "scale": 1, "scaleX": 1, "scaleY": 1 }
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Text Element
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"type": "text",
|
|
289
|
+
"id": "title",
|
|
290
|
+
"content": "Hello World",
|
|
291
|
+
"position": "center",
|
|
292
|
+
"font": { "family": "Inter, system-ui, sans-serif", "size": 64, "weight": "bold", "color": "#ffffff", "letterSpacing": -2, "lineHeight": 1.2, "align": "center" },
|
|
293
|
+
"stroke": { "color": "#000000", "width": 2 },
|
|
294
|
+
"shadow": { "color": "rgba(0,0,0,0.5)", "blur": 10, "offsetX": 2, "offsetY": 2 },
|
|
295
|
+
"split": { "type": "chars" }
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Image Element
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"type": "image",
|
|
303
|
+
"src": "https://example.com/img.png",
|
|
304
|
+
"position": "center",
|
|
305
|
+
"size": { "width": 400, "height": "auto", "fit": "contain" },
|
|
306
|
+
"filters": { "brightness": 1, "contrast": 1, "saturate": 1, "blur": 0, "hueRotate": 0, "grayscale": 0 },
|
|
307
|
+
"borderRadius": 10
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### SVG Element
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"type": "svg",
|
|
315
|
+
"src": "<svg>...</svg>",
|
|
316
|
+
"position": "center",
|
|
317
|
+
"size": { "width": 200, "height": "auto" },
|
|
318
|
+
"colors": { "#000": "#fff" }
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Video Element
|
|
323
|
+
```json
|
|
324
|
+
{
|
|
325
|
+
"type": "video",
|
|
326
|
+
"id": "myVideo",
|
|
327
|
+
"src": "https://example.com/video.mp4",
|
|
328
|
+
"position": "center",
|
|
329
|
+
"size": { "width": 640, "height": "auto", "fit": "cover" },
|
|
330
|
+
"loop": true,
|
|
331
|
+
"muted": true,
|
|
332
|
+
"playbackRate": 1,
|
|
333
|
+
"startTime": 0
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Animatable Element Properties
|
|
340
|
+
|
|
341
|
+
Access via `ctx.elements.get(id)`:
|
|
342
|
+
|
|
343
|
+
| Property | Type | Description |
|
|
344
|
+
|----------|------|-------------|
|
|
345
|
+
| `props.x` | `number` | X position offset |
|
|
346
|
+
| `props.y` | `number` | Y position offset |
|
|
347
|
+
| `props.z` | `number` | Z depth |
|
|
348
|
+
| `props.opacity` | `number` | Opacity 0-1 |
|
|
349
|
+
| `props.scale` | `number` | Uniform scale |
|
|
350
|
+
| `props.scaleX` | `number` | Horizontal scale |
|
|
351
|
+
| `props.scaleY` | `number` | Vertical scale |
|
|
352
|
+
| `props.rotation` | `number` | Z rotation (degrees) |
|
|
353
|
+
| `props.rotationX` | `number` | X rotation (degrees) |
|
|
354
|
+
| `props.rotationY` | `number` | Y rotation (degrees) |
|
|
355
|
+
| `props.fontSize` | `number` | Text font size |
|
|
356
|
+
| `props.letterSpacing` | `number` | Text letter spacing |
|
|
357
|
+
|
|
358
|
+
### Video-specific
|
|
359
|
+
| Property | Type | Description |
|
|
360
|
+
|----------|------|-------------|
|
|
361
|
+
| `props.currentTime` | `number` | Playback position in seconds |
|
|
362
|
+
| `props.playing` | `boolean` | Whether video is playing |
|
|
363
|
+
| `props.startOffset` | `number` | Playback start offset |
|
|
364
|
+
| `props.duration` | `number` | Video duration (read-only) |
|
|
365
|
+
|
|
366
|
+
### Split Text Segments
|
|
367
|
+
|
|
368
|
+
When `split` is configured, `el.segments` is an array of `ElementProps` — one per char/word/line:
|
|
369
|
+
```javascript
|
|
370
|
+
const el = ctx.elements.get('title')
|
|
371
|
+
if (el?.segments) {
|
|
372
|
+
el.segments.forEach((seg, i) => {
|
|
373
|
+
tl.fromTo(seg, { opacity: 0, y: 50 }, { opacity: 1, y: 0, duration: 0.5 }, i * 0.05)
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Common Material Recipes
|
|
381
|
+
|
|
382
|
+
### Glass / Crystal
|
|
383
|
+
```javascript
|
|
384
|
+
new THREE.MeshPhysicalMaterial({
|
|
385
|
+
color: 0xffffff,
|
|
386
|
+
transmission: 1.0,
|
|
387
|
+
roughness: 0.0,
|
|
388
|
+
ior: 1.5,
|
|
389
|
+
thickness: 2.0,
|
|
390
|
+
dispersion: 4.0, // Rainbow effects
|
|
391
|
+
clearcoat: 1.0,
|
|
392
|
+
envMapIntensity: 1.5,
|
|
393
|
+
side: THREE.DoubleSide
|
|
394
|
+
})
|
|
395
|
+
// Requires: scene.environment = hdrTexture
|
|
396
|
+
// Local renders only: for configs pushed to vos.so, drop `dispersion` and
|
|
397
|
+
// never DoubleSide a transmission material (the server fleet renders on
|
|
398
|
+
// software GL — see the SKILL.md server-render caution).
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Emissive Glow (with bloom)
|
|
402
|
+
```javascript
|
|
403
|
+
new THREE.MeshStandardMaterial({
|
|
404
|
+
color: 0xff6b6b,
|
|
405
|
+
emissive: 0xff6b6b,
|
|
406
|
+
emissiveIntensity: 0.5
|
|
407
|
+
})
|
|
408
|
+
// Add bloom postprocessing for visible glow
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Wireframe
|
|
412
|
+
```javascript
|
|
413
|
+
new THREE.MeshBasicMaterial({ color: 0xff00cc, wireframe: true, transparent: true, opacity: 0.3 })
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Premium Solid
|
|
417
|
+
```javascript
|
|
418
|
+
new THREE.MeshPhysicalMaterial({ color: 0xffffff, roughness: 0.1, clearcoat: 1.0, clearcoatRoughness: 0.1 })
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Common Geometry Recipes
|
|
424
|
+
|
|
425
|
+
### Fullscreen Shader Quad
|
|
426
|
+
```javascript
|
|
427
|
+
const geometry = new THREE.PlaneGeometry(2, 2)
|
|
428
|
+
const material = new THREE.ShaderMaterial({
|
|
429
|
+
uniforms: { iTime: { value: 0 }, iResolution: { value: new THREE.Vector3(resolution.drawingBufferWidth, resolution.drawingBufferHeight, 1) } },
|
|
430
|
+
vertexShader: 'void main() { gl_Position = vec4(position, 1.0); }',
|
|
431
|
+
fragmentShader: '/* your GLSL */',
|
|
432
|
+
depthWrite: false, depthTest: false
|
|
433
|
+
})
|
|
434
|
+
const mesh = new THREE.Mesh(geometry, material)
|
|
435
|
+
mesh.frustumCulled = false
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Rounded Box (ExtrudeGeometry)
|
|
439
|
+
```javascript
|
|
440
|
+
const shape = new THREE.Shape()
|
|
441
|
+
const w = 0.8, d = 0.8, r = 0.1, x = -w/2, y = -d/2
|
|
442
|
+
shape.moveTo(x + r, y)
|
|
443
|
+
shape.lineTo(x + w - r, y)
|
|
444
|
+
shape.quadraticCurveTo(x + w, y, x + w, y + r)
|
|
445
|
+
shape.lineTo(x + w, y + d - r)
|
|
446
|
+
shape.quadraticCurveTo(x + w, y + d, x + w - r, y + d)
|
|
447
|
+
shape.lineTo(x + r, y + d)
|
|
448
|
+
shape.quadraticCurveTo(x, y + d, x, y + d - r)
|
|
449
|
+
shape.lineTo(x, y + r)
|
|
450
|
+
shape.quadraticCurveTo(x, y, x + r, y)
|
|
451
|
+
const geometry = new THREE.ExtrudeGeometry(shape, { depth: 0.8, bevelEnabled: true, bevelSegments: 2, bevelSize: r, bevelThickness: r })
|
|
452
|
+
geometry.center()
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Canvas Texture
|
|
456
|
+
```javascript
|
|
457
|
+
const canvas = document.createElement('canvas')
|
|
458
|
+
const c = canvas.getContext('2d')
|
|
459
|
+
canvas.width = 2048; canvas.height = 1200
|
|
460
|
+
c.fillStyle = '#080808'
|
|
461
|
+
c.fillRect(0, 0, canvas.width, canvas.height)
|
|
462
|
+
c.font = 'bold 110px Inter, system-ui, sans-serif'
|
|
463
|
+
c.fillStyle = '#cccccc'
|
|
464
|
+
c.textAlign = 'center'
|
|
465
|
+
c.fillText('TEXT', canvas.width / 2, canvas.height / 2)
|
|
466
|
+
const texture = new THREE.CanvasTexture(canvas)
|
|
467
|
+
texture.colorSpace = THREE.SRGBColorSpace
|
|
468
|
+
```
|