@viji-dev/core 0.3.37 → 0.3.38
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/dist/artist-dts-p5.js +1 -1
- package/dist/artist-dts.js +1 -1
- package/dist/artist-global-p5.d.ts +24 -1
- package/dist/artist-global.d.ts +24 -1
- package/dist/artist-jsdoc.d.ts +22 -0
- package/dist/assets/{viji.worker-DR0jmwBv.js → viji.worker-BoI8e3NI.js} +68 -2
- package/dist/assets/viji.worker-BoI8e3NI.js.map +1 -0
- package/dist/docs-api.js +95 -17
- package/dist/{essentia-wasm.web-Ck3Tig5D.js → essentia-wasm.web-CdUmKTbm.js} +2 -2
- package/dist/{essentia-wasm.web-Ck3Tig5D.js.map → essentia-wasm.web-CdUmKTbm.js.map} +1 -1
- package/dist/{index-BmeV_yOg.js → index-DZzYWg7c.js} +29 -9
- package/dist/index-DZzYWg7c.js.map +1 -0
- package/dist/index.d.ts +36 -9
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/assets/viji.worker-DR0jmwBv.js.map +0 -1
- package/dist/index-BmeV_yOg.js.map +0 -1
package/dist/docs-api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const docsApi = {
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"coreVersion": "0.3.
|
|
4
|
-
"generatedAt": "2026-04-
|
|
3
|
+
"coreVersion": "0.3.37",
|
|
4
|
+
"generatedAt": "2026-04-11T19:21:54.046Z",
|
|
5
5
|
"navigation": [
|
|
6
6
|
{
|
|
7
7
|
"id": "getting-started",
|
|
@@ -156,6 +156,11 @@ export const docsApi = {
|
|
|
156
156
|
"title": "Button",
|
|
157
157
|
"path": "native/parameters/button"
|
|
158
158
|
},
|
|
159
|
+
{
|
|
160
|
+
"id": "native-param-coordinate",
|
|
161
|
+
"title": "Coordinate",
|
|
162
|
+
"path": "native/parameters/coordinate"
|
|
163
|
+
},
|
|
159
164
|
{
|
|
160
165
|
"id": "native-param-grouping",
|
|
161
166
|
"title": "Grouping",
|
|
@@ -413,6 +418,11 @@ export const docsApi = {
|
|
|
413
418
|
"title": "Button",
|
|
414
419
|
"path": "p5/parameters/button"
|
|
415
420
|
},
|
|
421
|
+
{
|
|
422
|
+
"id": "p5-param-coordinate",
|
|
423
|
+
"title": "Coordinate",
|
|
424
|
+
"path": "p5/parameters/coordinate"
|
|
425
|
+
},
|
|
416
426
|
{
|
|
417
427
|
"id": "p5-param-grouping",
|
|
418
428
|
"title": "Grouping",
|
|
@@ -655,6 +665,11 @@ export const docsApi = {
|
|
|
655
665
|
"title": "Button",
|
|
656
666
|
"path": "shader/parameters/button"
|
|
657
667
|
},
|
|
668
|
+
{
|
|
669
|
+
"id": "shader-param-coordinate",
|
|
670
|
+
"title": "Coordinate",
|
|
671
|
+
"path": "shader/parameters/coordinate"
|
|
672
|
+
},
|
|
658
673
|
{
|
|
659
674
|
"id": "shader-param-accumulator",
|
|
660
675
|
"title": "Accumulator",
|
|
@@ -847,7 +862,7 @@ export const docsApi = {
|
|
|
847
862
|
},
|
|
848
863
|
{
|
|
849
864
|
"type": "text",
|
|
850
|
-
"markdown": "A few things to notice:\n\n- **[`viji.slider()`](/native/parameters/slider)** creates a UI slider the user can adjust — defined once at the top level, read via `.value` inside `render()`.\n- **[`viji.deltaTime`](/native/timing)** is the time since the last frame in seconds — use it with an accumulator (`angle +=`) for smooth, frame-rate-independent animation that doesn't jump when you change parameters.\n- **[`viji.width`](/native/canvas-context) / [`viji.height`](/native/canvas-context)** keep your scene resolution-agnostic.\n- **`render(viji)`** is called every frame. This is where you draw.\n\n## What You Can Access\n\nEverything is available through the `viji` object:\n\n| Category | What It Gives You |\n|----------|------------------|\n| **Canvas** | [`viji.canvas`](/native/canvas-context), [`viji.width`](/native/canvas-context), [`viji.height`](/native/canvas-context) |\n| **Timing** | [`viji.time`](/native/timing), [`viji.deltaTime`](/native/timing), [`viji.frameCount`](/native/timing), [`viji.fps`](/native/timing) |\n| **Parameters** | [`viji.slider()`](/native/parameters/slider), [`viji.color()`](/native/parameters/color), [`viji.toggle()`](/native/parameters/toggle), [`viji.select()`](/native/parameters/select), [`viji.number()`](/native/parameters/number), [`viji.text()`](/native/parameters/text), [`viji.image()`](/native/parameters/image), [`viji.button()`](/native/parameters/button) |\n| **Audio** | [Volume, bands, beat, spectral, FFT & waveform](/native/audio). **Multi-stream:** the host can supply extra sources as `viji.audioStreams[]` and device mic as `device.audio` (same analysis as main audio except beat/BPM, which stay on `viji.audio` only). |\n| **Video & CV** | [Video frames, face detection, hand tracking, pose estimation, body segmentation](/native/video) |\n| **Interaction** | Unified pointer, mouse buttons & wheel, keyboard state, multi-touch with pressure & velocity |\n| **Sensors** | Accelerometer, gyroscope, device orientation |\n\n## Three Ways to Create\n\nViji supports three rendering modes:\n\n| Renderer | Best For | Entry Point |\n|----------|----------|-------------|\n| **Native** | Full control — Canvas 2D, WebGL, Three.js | `render(viji)` |\n| **P5.js** | Artists familiar with Processing / P5.js | `render(viji, p5)` |\n| **Shader** | GPU effects, raymarching, generative patterns | `void main()` in GLSL |\n\nAll three share the same audio, video, parameter, and interaction APIs. See [Renderers Overview](../renderers-overview/) for how each works.\n\n## Next Steps\n\n- [Renderers Overview](../renderers-overview/) — how to choose and use each renderer\n- [Best Practices](../best-practices/) — essential patterns for robust, performant scenes\n- [Common Mistakes](../common-mistakes/) — pitfalls to avoid\n- [Native Quick Start](/native/quickstart) — build with JavaScript and full canvas control\n- [P5 Quick Start](/p5/quickstart) — build with the familiar P5.js API\n- [Shader Quick Start](/shader/quickstart) — build with GLSL fragment shaders"
|
|
865
|
+
"markdown": "A few things to notice:\n\n- **[`viji.slider()`](/native/parameters/slider)** creates a UI slider the user can adjust — defined once at the top level, read via `.value` inside `render()`.\n- **[`viji.deltaTime`](/native/timing)** is the time since the last frame in seconds — use it with an accumulator (`angle +=`) for smooth, frame-rate-independent animation that doesn't jump when you change parameters.\n- **[`viji.width`](/native/canvas-context) / [`viji.height`](/native/canvas-context)** keep your scene resolution-agnostic.\n- **`render(viji)`** is called every frame. This is where you draw.\n\n## What You Can Access\n\nEverything is available through the `viji` object:\n\n| Category | What It Gives You |\n|----------|------------------|\n| **Canvas** | [`viji.canvas`](/native/canvas-context), [`viji.width`](/native/canvas-context), [`viji.height`](/native/canvas-context) |\n| **Timing** | [`viji.time`](/native/timing), [`viji.deltaTime`](/native/timing), [`viji.frameCount`](/native/timing), [`viji.fps`](/native/timing) |\n| **Parameters** | [`viji.slider()`](/native/parameters/slider), [`viji.color()`](/native/parameters/color), [`viji.toggle()`](/native/parameters/toggle), [`viji.select()`](/native/parameters/select), [`viji.number()`](/native/parameters/number), [`viji.text()`](/native/parameters/text), [`viji.image()`](/native/parameters/image), [`viji.button()`](/native/parameters/button), [`viji.coordinate()`](/native/parameters/coordinate) |\n| **Audio** | [Volume, bands, beat, spectral, FFT & waveform](/native/audio). **Multi-stream:** the host can supply extra sources as `viji.audioStreams[]` and device mic as `device.audio` (same analysis as main audio except beat/BPM, which stay on `viji.audio` only). |\n| **Video & CV** | [Video frames, face detection, hand tracking, pose estimation, body segmentation](/native/video) |\n| **Interaction** | Unified pointer, mouse buttons & wheel, keyboard state, multi-touch with pressure & velocity |\n| **Sensors** | Accelerometer, gyroscope, device orientation |\n\n## Three Ways to Create\n\nViji supports three rendering modes:\n\n| Renderer | Best For | Entry Point |\n|----------|----------|-------------|\n| **Native** | Full control — Canvas 2D, WebGL, Three.js | `render(viji)` |\n| **P5.js** | Artists familiar with Processing / P5.js | `render(viji, p5)` |\n| **Shader** | GPU effects, raymarching, generative patterns | `void main()` in GLSL |\n\nAll three share the same audio, video, parameter, and interaction APIs. See [Renderers Overview](../renderers-overview/) for how each works.\n\n## Next Steps\n\n- [Renderers Overview](../renderers-overview/) — how to choose and use each renderer\n- [Best Practices](../best-practices/) — essential patterns for robust, performant scenes\n- [Common Mistakes](../common-mistakes/) — pitfalls to avoid\n- [Native Quick Start](/native/quickstart) — build with JavaScript and full canvas control\n- [P5 Quick Start](/p5/quickstart) — build with the familiar P5.js API\n- [Shader Quick Start](/shader/quickstart) — build with GLSL fragment shaders"
|
|
851
866
|
}
|
|
852
867
|
]
|
|
853
868
|
},
|
|
@@ -937,7 +952,7 @@ export const docsApi = {
|
|
|
937
952
|
"content": [
|
|
938
953
|
{
|
|
939
954
|
"type": "text",
|
|
940
|
-
"markdown": "# Create Your First Scene\n\nNew to Viji? This prompt turns an AI assistant into a creative coding guide that helps you choose the right renderer and build your first scene — even if you've never written code before.\n\n## How It Works\n\n1. Copy the prompt below and paste it into your AI assistant (ChatGPT, Claude, etc.).\n2. Describe what you want to create — as simple or detailed as you like.\n3. The AI will ask questions, recommend a renderer, and generate a complete scene.\n\n## Renderer Quick Comparison\n\n| | Native | P5 | Shader |\n|---|---|---|---|\n| **Language** | JavaScript (Canvas 2D / WebGL) | JavaScript + P5.js | GLSL (GPU fragment shader) |\n| **Best for** | Full control, Three.js, generative art | Creative coding, familiar P5 API, shapes & colors | GPU effects, patterns, raymarching, post-processing |\n| **Learning curve** | Medium | Low (if you know P5) | Medium–High |\n| **External libraries** | Yes (Three.js, etc.) | P5.js built-in | No |\n| **3D support** | Yes (WebGL, Three.js) | Yes (via `// @renderer p5 webgl`) | Yes (raymarching, SDF) |\n\n## The Prompt\n\n````\nYou are a creative coding assistant for the Viji platform. Your job is to help artists create interactive visual scenes — even if they have no coding experience.\n\n## YOUR BEHAVIOR\n\n1. Ask the artist what they want to create. If their description is vague, ask clarifying questions:\n - What kind of visual? (patterns, shapes, particles, video effects, 3D, etc.)\n - Should it react to audio/music?\n - Should it use a camera/video?\n - Should it respond to mouse/touch/device tilt?\n - What mood or style? (abstract, organic, geometric, glitchy, minimal, etc.)\n2. Assess their experience level and recommend a renderer:\n - **No coding experience** → recommend **P5** (most approachable for beginners)\n - **Knows JavaScript/Canvas** → recommend **Native** (maximum control)\n - **Wants GPU effects, patterns, or has shader experience** → recommend **Shader**\n - **Wants 3D with Three.js or custom WebGL** → recommend **Native**\n - **Knows P5.js/Processing** → recommend **P5**\n3. Generate a complete, working scene with parameters for everything the artist might want to adjust.\n4. Explain what the code does in simple terms.\n5. Suggest ways to iterate and improve.\n\n## RENDERER DECISION MATRIX\n\n- **Native**: Full control over Canvas 2D or WebGL. Supports `await import()` for external libraries like Three.js. Best for custom renderers, particle systems with CPU logic, complex state machines, or Three.js 3D scenes.\n- **P5**: Uses P5.js v1.9.4 with familiar `setup()`/`render()` pattern. Best for creative coding with shapes, colors, transforms, text. Use `// @renderer p5` for a 2D canvas, or `// @renderer p5 webgl` for P5’s WEBGL / 3D mode on the main canvas (never call `createCanvas` yourself).\n- **Shader**: GLSL fragment shader on a GPU fullscreen quad. Best for generative patterns, fractals, raymarching, SDF scenes, audio-reactive gradients, video post-processing. Extremely fast — runs entirely on the GPU.\n\n## REFERENCE (for AI assistants with web access)\n\nFor the latest API documentation, type definitions, and all uniform details:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- Shader uniforms reference: https://unpkg.com/@viji-dev/core/dist/shader-uniforms.js\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## VIJI ARCHITECTURE (all renderers)\n\n- Scenes run in a **Web Worker** with an **OffscreenCanvas**. There is NO DOM access.\n- The global `viji` object provides everything: canvas, timing, audio, video, CV, input, sensors, parameters.\n- **Top-level code** runs once (parameters, state, imports).\n- **`render(viji)` / `render(viji, p5)` / `void main()`** runs every frame.\n- `fetch()` is available. `window`, `document`, `Image()` are NOT.\n\n## SCENE STRUCTURE PER RENDERER\n\n### Native\n```javascript\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nlet angle = 0;\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n angle += speed.value * viji.deltaTime;\n ctx.clearRect(0, 0, viji.width, viji.height);\n // draw with ctx...\n}\n```\n\n### P5\n```javascript\n// @renderer p5\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nlet angle = 0;\nfunction setup(viji, p5) { p5.colorMode(p5.HSB, 360, 100, 100); }\nfunction render(viji, p5) {\n angle += speed.value * viji.deltaTime;\n p5.background(0);\n // draw with p5.circle(), p5.rect(), etc. (all need p5. prefix)\n}\n```\n\n### Shader (GLSL)\n```glsl\n// @renderer shader\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n// @viji-accumulator:phase rate:speed\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n gl_FragColor = vec4(uv, sin(phase) * 0.5 + 0.5, 1.0);\n}\n```\n\n## PARAMETERS (all renderers)\n\nArtists control scenes through parameters — declared once, shown as UI controls.\n\n**Native/P5 syntax** (top-level):\n```javascript\nviji.slider(default, { min, max, step, label, group, category }) // → .value: number\nviji.color(default, { label }) // → .value: '#rrggbb'\nviji.toggle(default, { label }) // → .value: boolean\nviji.select(default, { options: [...], label }) // → .value: string|number\nviji.number(default, { min, max, step, label }) // → .value: number\nviji.text(default, { label, maxLength }) // → .value: string\nviji.image(null, { label }) // → .value: ImageBitmap|null\nviji.button({ label }) // → .value: boolean (1 frame)\n```\n\n**Shader syntax** (comment directives):\n```glsl\n// @viji-slider:name label:\"Label\" default:1.0 min:0.0 max:5.0 → uniform float name;\n// @viji-color:name label:\"Color\" default:#ff6600 → uniform vec3 name;\n// @viji-toggle:name label:\"Toggle\" default:false → uniform bool name;\n// @viji-select:name label:\"Mode\" default:0 options:[\"A\",\"B\"] → uniform int name;\n// @viji-number:name label:\"Count\" default:10.0 min:1.0 max:100.0 → uniform float name;\n// @viji-image:name label:\"Texture\" → uniform sampler2D name;\n// @viji-button:name label:\"Reset\" → uniform bool name;\n// @viji-accumulator:name rate:speed → uniform float name;\n```\n\n## AUDIO — `viji.audio` / Shader uniforms\n\nALWAYS check `isConnected` / `u_audioVolume > 0.0` before using audio data.\n\nKey members (Native/P5):\n- `isConnected`, `volume.current`, `volume.peak`, `volume.smoothed`\n- `bands.low`, `bands.lowMid`, `bands.mid`, `bands.highMid`, `bands.high` (+ smoothed variants)\n- `beat.kick`, `beat.snare`, `beat.hat`, `beat.any` (+ `.triggers.kick` etc. for single-frame)\n- `beat.bpm`, `beat.confidence`, `beat.isLocked`\n- `spectral.brightness`, `spectral.flatness`\n- `getFrequencyData()`, `getWaveform()`\n\nKey shader uniforms: `u_audioVolume`, `u_audioLow`–`u_audioHigh`, `u_audioKick`–`u_audioAny`, `u_audioKickTrigger`–`u_audioAnyTrigger`, `u_audioBPM`, `u_audioBrightness`, `u_audioFlatness`, `u_audioFFT`, `u_audioWaveform`.\n\n**Additional audio streams** (`viji.audioStreams[]`, and `device.audio` on each `viji.devices[]` entry): lightweight **`AudioStreamAPI`** — `isConnected`, `volume` (current/peak/smoothed), `bands` (low/lowMid/mid/highMid/high + smoothed variants), `spectral` (brightness/flatness), `getFrequencyData()`, `getWaveform()`. **No** beat detection, BPM, triggers, or events. Shader: `u_audioStreamCount`, `u_audioStream{i}Connected`, `u_audioStream{i}Volume`, `Low`, `LowMid`, `Mid`, `HighMid`, `High`, `Brightness`, `Flatness` for `i` = 0–7. **No** per-stream FFT or waveform textures (`u_audioFFT` / `u_audioWaveform` apply only to the main audio source).\n\n## VIDEO & CV — `viji.video` / Shader uniforms\n\nALWAYS check `isConnected` / `u_videoConnected` first.\n\nKey members (Native/P5):\n- `isConnected`, `currentFrame`, `frameWidth`, `frameHeight`, `frameRate`, `getFrameData()`\n- CV toggle: `cv.enableFaceDetection(bool)`, `cv.enableFaceMesh(bool)`, `cv.enableEmotionDetection(bool)`, `cv.enableHandTracking(bool)`, `cv.enablePoseDetection(bool)`, `cv.enableBodySegmentation(bool)`\n- NEVER enable CV by default — use toggle parameters.\n- Data: `faces[]` (FaceData), `hands[]` (HandData), `pose` (PoseData|null), `segmentation` (SegmentationData|null)\n\nKey shader uniforms: `u_video`, `u_videoResolution`, `u_videoConnected`, `u_faceCount`, `u_face0*`, `u_handCount`, `u_leftHand*`, `u_rightHand*`, `u_poseDetected`, `u_pose*Position`, `u_segmentationMask`.\n\n## INPUT\n\n**Pointer** (unified): `viji.pointer.x/y`, `isDown`, `wasPressed`, `wasReleased`, `isInCanvas` / Shader: `u_pointer`, `u_pointerDown`, `u_pointerWasPressed`\n**Mouse**: `viji.mouse.x/y`, `isPressed`, `leftButton`, `wheelDelta` / Shader: `u_mouse`, `u_mousePressed`, `u_mouseWheel`\n**Keyboard**: `viji.keyboard.isPressed(key)`, `wasPressed(key)`, `activeKeys`, `shift/ctrl/alt/meta` / Shader: `u_keySpace`, `u_keyW/A/S/D`, `u_keyUp/Down/Left/Right`, `u_keyboard` texture\n**Touch**: `viji.touches.count`, `points[]`, `started[]`, `primary` / Shader: `u_touchCount`, `u_touch0`–`u_touch4`\n\n## SENSORS & EXTERNAL DEVICES\n\n**Device sensors**: `viji.device.motion` (acceleration, rotationRate), `viji.device.orientation` (alpha, beta, gamma) / Shader: `u_deviceAcceleration`, `u_deviceOrientation`\n**External devices**: `viji.devices[]` (id, name, motion, orientation, video, audio) / Shader: `u_device0`–`u_device7` textures, sensors, connection status; device audio uses `u_audioStream{i}*` scalars (see Streams)\n**Streams**: `viji.videoStreams[]` (host-provided additional video) / Shader: `u_videoStream0`–`u_videoStream7`. **`viji.audioStreams[]`** (host-provided additional audio) / Shader: `u_audioStreamCount`, `u_audioStream{i}Connected`, `u_audioStream{i}Volume` / `Low` / `LowMid` / `Mid` / `HighMid` / `High` / `Brightness` / `Flatness` for `i` = 0–7 (scalars only — no per-stream FFT/waveform textures)\n\n## CRITICAL RULES (all renderers)\n\n1. NEVER access `window`, `document`, `Image()`, `localStorage`. `fetch()` IS available.\n2. ALWAYS declare parameters at the TOP LEVEL, never inside `render()` / `main()`.\n3. ALWAYS use `viji.width`/`viji.height` or `u_resolution` — NEVER hardcode pixel sizes.\n4. ALWAYS use `viji.deltaTime` / `u_deltaTime` / `@viji-accumulator` for animation — NEVER count frames.\n5. NEVER multiply `viji.time` by a parameter (`viji.time * speed.value`) — it causes animation jumps when the parameter changes. Use a `deltaTime` accumulator instead. In shaders, use `@viji-accumulator`. This also applies to nested multiplications: never multiply an accumulator by another parameter — give each speed its own accumulator.\n6. NEVER allocate objects/arrays inside `render()` — pre-allocate at top level.\n7. ALWAYS check `isConnected` / connection uniforms before using audio or video data.\n8. NEVER enable CV features by default — use toggle parameters.\n9. ALWAYS set `category` on input-dependent parameters: `category: 'audio'` for audio controls, `category: 'video'` for video/CV controls, `category: 'interaction'` for mouse/keyboard/touch controls. Omit `category` (defaults to `'general'`) for parameters that work without external input.\n10. In P5: ALWAYS prefix every P5 function/constant with `p5.`. NEVER use `createCanvas()`.\n11. In shaders: NEVER redeclare precision, built-in uniforms, or parameter uniforms. NEVER use `u_` prefix for parameter names.\n\n## FOR ADVANCED FEATURES\n\nWhen the artist needs the full API surface, use the renderer-specific prompts:\n- **Native**: Use the \"Prompt: Native Scenes\" page for the complete API reference\n- **P5**: Use the \"Prompt: P5 Scenes\" page for the complete API reference + P5 mapping\n- **Shader**: Use the \"Prompt: Shader Scenes\" page for all 270+ uniforms and directive details\n\nNow help the artist create their Viji scene. Start by asking what they want to build.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant.\n3. Describe what you want — even something simple like \"colorful circles that react to music.\"\n4. The AI will guide you through choosing a renderer and building a scene.\n\n> [!TIP]\n> Don't worry about technical details — the AI will handle those. Focus on describing what you want to **see** and **feel**. Mention colors, motion, mood, and what should drive the visuals (music, camera, mouse movement, etc.).\n\n## Next Steps\n\nOnce you've created your first scene and want more control, use the full renderer-specific prompts:\n\n- [Prompt: Native Scenes](/ai-prompts/native-prompt) — exhaustive Native API prompt\n- [Prompt: P5 Scenes](/ai-prompts/p5-prompt) — exhaustive P5 API prompt\n- [Prompt: Shader Scenes](/ai-prompts/shader-prompt) — exhaustive Shader API prompt\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n\n## Related\n\n- [Overview](/getting-started/overview) — what Viji is and how it works\n- [Best Practices](/getting-started/best-practices) — essential patterns for robust scenes\n- [Common Mistakes](/getting-started/common-mistakes) — pitfalls to avoid"
|
|
955
|
+
"markdown": "# Create Your First Scene\n\nNew to Viji? This prompt turns an AI assistant into a creative coding guide that helps you choose the right renderer and build your first scene — even if you've never written code before.\n\n## How It Works\n\n1. Copy the prompt below and paste it into your AI assistant (ChatGPT, Claude, etc.).\n2. Describe what you want to create — as simple or detailed as you like.\n3. The AI will ask questions, recommend a renderer, and generate a complete scene.\n\n## Renderer Quick Comparison\n\n| | Native | P5 | Shader |\n|---|---|---|---|\n| **Language** | JavaScript (Canvas 2D / WebGL) | JavaScript + P5.js | GLSL (GPU fragment shader) |\n| **Best for** | Full control, Three.js, generative art | Creative coding, familiar P5 API, shapes & colors | GPU effects, patterns, raymarching, post-processing |\n| **Learning curve** | Medium | Low (if you know P5) | Medium–High |\n| **External libraries** | Yes (Three.js, etc.) | P5.js built-in | No |\n| **3D support** | Yes (WebGL, Three.js) | Yes (via `// @renderer p5 webgl`) | Yes (raymarching, SDF) |\n\n## The Prompt\n\n````\nYou are a creative coding assistant for the Viji platform. Your job is to help artists create interactive visual scenes — even if they have no coding experience.\n\n## YOUR BEHAVIOR\n\n1. Ask the artist what they want to create. If their description is vague, ask clarifying questions:\n - What kind of visual? (patterns, shapes, particles, video effects, 3D, etc.)\n - Should it react to audio/music?\n - Should it use a camera/video?\n - Should it respond to mouse/touch/device tilt?\n - What mood or style? (abstract, organic, geometric, glitchy, minimal, etc.)\n2. Assess their experience level and recommend a renderer:\n - **No coding experience** → recommend **P5** (most approachable for beginners)\n - **Knows JavaScript/Canvas** → recommend **Native** (maximum control)\n - **Wants GPU effects, patterns, or has shader experience** → recommend **Shader**\n - **Wants 3D with Three.js or custom WebGL** → recommend **Native**\n - **Knows P5.js/Processing** → recommend **P5**\n3. Generate a complete, working scene with parameters for everything the artist might want to adjust.\n4. Explain what the code does in simple terms.\n5. Suggest ways to iterate and improve.\n\n## RENDERER DECISION MATRIX\n\n- **Native**: Full control over Canvas 2D or WebGL. Supports `await import()` for external libraries like Three.js. Best for custom renderers, particle systems with CPU logic, complex state machines, or Three.js 3D scenes.\n- **P5**: Uses P5.js v1.9.4 with familiar `setup()`/`render()` pattern. Best for creative coding with shapes, colors, transforms, text. Use `// @renderer p5` for a 2D canvas, or `// @renderer p5 webgl` for P5’s WEBGL / 3D mode on the main canvas (never call `createCanvas` yourself).\n- **Shader**: GLSL fragment shader on a GPU fullscreen quad. Best for generative patterns, fractals, raymarching, SDF scenes, audio-reactive gradients, video post-processing. Extremely fast — runs entirely on the GPU.\n\n## REFERENCE (for AI assistants with web access)\n\nFor the latest API documentation, type definitions, and all uniform details:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- Shader uniforms reference: https://unpkg.com/@viji-dev/core/dist/shader-uniforms.js\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## VIJI ARCHITECTURE (all renderers)\n\n- Scenes run in a **Web Worker** with an **OffscreenCanvas**. There is NO DOM access.\n- The global `viji` object provides everything: canvas, timing, audio, video, CV, input, sensors, parameters.\n- **Top-level code** runs once (parameters, state, imports).\n- **`render(viji)` / `render(viji, p5)` / `void main()`** runs every frame.\n- `fetch()` is available. `window`, `document`, `Image()` are NOT.\n\n## SCENE STRUCTURE PER RENDERER\n\n### Native\n```javascript\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nlet angle = 0;\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n angle += speed.value * viji.deltaTime;\n ctx.clearRect(0, 0, viji.width, viji.height);\n // draw with ctx...\n}\n```\n\n### P5\n```javascript\n// @renderer p5\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nlet angle = 0;\nfunction setup(viji, p5) { p5.colorMode(p5.HSB, 360, 100, 100); }\nfunction render(viji, p5) {\n angle += speed.value * viji.deltaTime;\n p5.background(0);\n // draw with p5.circle(), p5.rect(), etc. (all need p5. prefix)\n}\n```\n\n### Shader (GLSL)\n```glsl\n// @renderer shader\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n// @viji-accumulator:phase rate:speed\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n gl_FragColor = vec4(uv, sin(phase) * 0.5 + 0.5, 1.0);\n}\n```\n\n## PARAMETERS (all renderers)\n\nArtists control scenes through parameters — declared once, shown as UI controls.\n\n**Native/P5 syntax** (top-level):\n```javascript\nviji.slider(default, { min, max, step, label, group, category }) // → .value: number\nviji.color(default, { label }) // → .value: '#rrggbb'\nviji.toggle(default, { label }) // → .value: boolean\nviji.select(default, { options: [...], label }) // → .value: string|number\nviji.number(default, { min, max, step, label }) // → .value: number\nviji.text(default, { label, maxLength }) // → .value: string\nviji.image(null, { label }) // → .value: ImageBitmap|null\nviji.button({ label }) // → .value: boolean (1 frame)\nviji.coordinate(defaultValue, { step, label, description, group, category }) // → .value: { x, y } // both -1 to 1\n```\n\n**Shader syntax** (comment directives):\n```glsl\n// @viji-slider:name label:\"Label\" default:1.0 min:0.0 max:5.0 → uniform float name;\n// @viji-color:name label:\"Color\" default:#ff6600 → uniform vec3 name;\n// @viji-toggle:name label:\"Toggle\" default:false → uniform bool name;\n// @viji-select:name label:\"Mode\" default:0 options:[\"A\",\"B\"] → uniform int name;\n// @viji-number:name label:\"Count\" default:10.0 min:1.0 max:100.0 → uniform float name;\n// @viji-image:name label:\"Texture\" → uniform sampler2D name;\n// @viji-button:name label:\"Reset\" → uniform bool name;\n// @viji-coordinate:name label:\"Label\" default:[0.0,0.0] → uniform vec2 name; // both -1 to 1\n// @viji-accumulator:name rate:speed → uniform float name;\n```\n\n## AUDIO — `viji.audio` / Shader uniforms\n\nALWAYS check `isConnected` / `u_audioVolume > 0.0` before using audio data.\n\nKey members (Native/P5):\n- `isConnected`, `volume.current`, `volume.peak`, `volume.smoothed`\n- `bands.low`, `bands.lowMid`, `bands.mid`, `bands.highMid`, `bands.high` (+ smoothed variants)\n- `beat.kick`, `beat.snare`, `beat.hat`, `beat.any` (+ `.triggers.kick` etc. for single-frame)\n- `beat.bpm`, `beat.confidence`, `beat.isLocked`\n- `spectral.brightness`, `spectral.flatness`\n- `getFrequencyData()`, `getWaveform()`\n\nKey shader uniforms: `u_audioVolume`, `u_audioLow`–`u_audioHigh`, `u_audioKick`–`u_audioAny`, `u_audioKickTrigger`–`u_audioAnyTrigger`, `u_audioBPM`, `u_audioBrightness`, `u_audioFlatness`, `u_audioFFT`, `u_audioWaveform`.\n\n**Additional audio streams** (`viji.audioStreams[]`, and `device.audio` on each `viji.devices[]` entry): lightweight **`AudioStreamAPI`** — `isConnected`, `volume` (current/peak/smoothed), `bands` (low/lowMid/mid/highMid/high + smoothed variants), `spectral` (brightness/flatness), `getFrequencyData()`, `getWaveform()`. **No** beat detection, BPM, triggers, or events. Shader: `u_audioStreamCount`, `u_audioStream{i}Connected`, `u_audioStream{i}Volume`, `Low`, `LowMid`, `Mid`, `HighMid`, `High`, `Brightness`, `Flatness` for `i` = 0–7. **No** per-stream FFT or waveform textures (`u_audioFFT` / `u_audioWaveform` apply only to the main audio source).\n\n## VIDEO & CV — `viji.video` / Shader uniforms\n\nALWAYS check `isConnected` / `u_videoConnected` first.\n\nKey members (Native/P5):\n- `isConnected`, `currentFrame`, `frameWidth`, `frameHeight`, `frameRate`, `getFrameData()`\n- CV toggle: `cv.enableFaceDetection(bool)`, `cv.enableFaceMesh(bool)`, `cv.enableEmotionDetection(bool)`, `cv.enableHandTracking(bool)`, `cv.enablePoseDetection(bool)`, `cv.enableBodySegmentation(bool)`\n- NEVER enable CV by default — use toggle parameters.\n- Data: `faces[]` (FaceData), `hands[]` (HandData), `pose` (PoseData|null), `segmentation` (SegmentationData|null)\n\nKey shader uniforms: `u_video`, `u_videoResolution`, `u_videoConnected`, `u_faceCount`, `u_face0*`, `u_handCount`, `u_leftHand*`, `u_rightHand*`, `u_poseDetected`, `u_pose*Position`, `u_segmentationMask`.\n\n## INPUT\n\n**Pointer** (unified): `viji.pointer.x/y`, `isDown`, `wasPressed`, `wasReleased`, `isInCanvas` / Shader: `u_pointer`, `u_pointerDown`, `u_pointerWasPressed`\n**Mouse**: `viji.mouse.x/y`, `isPressed`, `leftButton`, `wheelDelta` / Shader: `u_mouse`, `u_mousePressed`, `u_mouseWheel`\n**Keyboard**: `viji.keyboard.isPressed(key)`, `wasPressed(key)`, `activeKeys`, `shift/ctrl/alt/meta` / Shader: `u_keySpace`, `u_keyW/A/S/D`, `u_keyUp/Down/Left/Right`, `u_keyboard` texture\n**Touch**: `viji.touches.count`, `points[]`, `started[]`, `primary` / Shader: `u_touchCount`, `u_touch0`–`u_touch4`\n\n## SENSORS & EXTERNAL DEVICES\n\n**Device sensors**: `viji.device.motion` (acceleration, rotationRate), `viji.device.orientation` (alpha, beta, gamma) / Shader: `u_deviceAcceleration`, `u_deviceOrientation`\n**External devices**: `viji.devices[]` (id, name, motion, orientation, video, audio) / Shader: `u_device0`–`u_device7` textures, sensors, connection status; device audio uses `u_audioStream{i}*` scalars (see Streams)\n**Streams**: `viji.videoStreams[]` (host-provided additional video) / Shader: `u_videoStream0`–`u_videoStream7`. **`viji.audioStreams[]`** (host-provided additional audio) / Shader: `u_audioStreamCount`, `u_audioStream{i}Connected`, `u_audioStream{i}Volume` / `Low` / `LowMid` / `Mid` / `HighMid` / `High` / `Brightness` / `Flatness` for `i` = 0–7 (scalars only — no per-stream FFT/waveform textures)\n\n## CRITICAL RULES (all renderers)\n\n1. NEVER access `window`, `document`, `Image()`, `localStorage`. `fetch()` IS available.\n2. ALWAYS declare parameters at the TOP LEVEL, never inside `render()` / `main()`.\n3. ALWAYS use `viji.width`/`viji.height` or `u_resolution` — NEVER hardcode pixel sizes.\n4. ALWAYS use `viji.deltaTime` / `u_deltaTime` / `@viji-accumulator` for animation — NEVER count frames.\n5. NEVER multiply `viji.time` by a parameter (`viji.time * speed.value`) — it causes animation jumps when the parameter changes. Use a `deltaTime` accumulator instead. In shaders, use `@viji-accumulator`. This also applies to nested multiplications: never multiply an accumulator by another parameter — give each speed its own accumulator.\n6. NEVER allocate objects/arrays inside `render()` — pre-allocate at top level.\n7. ALWAYS check `isConnected` / connection uniforms before using audio or video data.\n8. NEVER enable CV features by default — use toggle parameters.\n9. ALWAYS set `category` on input-dependent parameters: `category: 'audio'` for audio controls, `category: 'video'` for video/CV controls, `category: 'interaction'` for mouse/keyboard/touch controls. Omit `category` (defaults to `'general'`) for parameters that work without external input.\n10. In P5: ALWAYS prefix every P5 function/constant with `p5.`. NEVER use `createCanvas()`.\n11. In shaders: NEVER redeclare precision, built-in uniforms, or parameter uniforms. NEVER use `u_` prefix for parameter names.\n\n## FOR ADVANCED FEATURES\n\nWhen the artist needs the full API surface, use the renderer-specific prompts:\n- **Native**: Use the \"Prompt: Native Scenes\" page for the complete API reference\n- **P5**: Use the \"Prompt: P5 Scenes\" page for the complete API reference + P5 mapping\n- **Shader**: Use the \"Prompt: Shader Scenes\" page for all 270+ uniforms and directive details\n\nNow help the artist create their Viji scene. Start by asking what they want to build.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant.\n3. Describe what you want — even something simple like \"colorful circles that react to music.\"\n4. The AI will guide you through choosing a renderer and building a scene.\n\n> [!TIP]\n> Don't worry about technical details — the AI will handle those. Focus on describing what you want to **see** and **feel**. Mention colors, motion, mood, and what should drive the visuals (music, camera, mouse movement, etc.).\n\n## Next Steps\n\nOnce you've created your first scene and want more control, use the full renderer-specific prompts:\n\n- [Prompt: Native Scenes](/ai-prompts/native-prompt) — exhaustive Native API prompt\n- [Prompt: P5 Scenes](/ai-prompts/p5-prompt) — exhaustive P5 API prompt\n- [Prompt: Shader Scenes](/ai-prompts/shader-prompt) — exhaustive Shader API prompt\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n\n## Related\n\n- [Overview](/getting-started/overview) — what Viji is and how it works\n- [Best Practices](/getting-started/best-practices) — essential patterns for robust scenes\n- [Common Mistakes](/getting-started/common-mistakes) — pitfalls to avoid"
|
|
941
956
|
}
|
|
942
957
|
]
|
|
943
958
|
},
|
|
@@ -948,7 +963,7 @@ export const docsApi = {
|
|
|
948
963
|
"content": [
|
|
949
964
|
{
|
|
950
965
|
"type": "text",
|
|
951
|
-
"markdown": "# Prompt: Native Scenes\n\nCopy the prompt below and paste it into your AI assistant. Then describe the scene you want. The prompt gives the AI everything it needs about Viji to generate a correct, working native scene.\n\n## The Prompt\n\n````\nYou are generating a Viji native scene — a creative visual that runs inside an OffscreenCanvas Web Worker.\nArtists describe what they want; you produce complete, working scene code. Apply every rule below exactly.\n\n## REFERENCE (for AI assistants with web access)\n\nThis prompt is self-contained — all information needed is included below.\nFor the latest API documentation and type definitions:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## ARCHITECTURE\n\n- Scenes run in a **Web Worker** with an **OffscreenCanvas**. There is no DOM.\n- The global `viji` object provides canvas, timing, audio, video, CV, input, sensors, and parameters.\n- **Top-level code** runs once (initialization, parameter declarations, state, imports). Top-level `await` is supported for dynamic imports.\n- **`function render(viji) { ... }`** is called every frame. This is where you draw.\n- There is **no `setup()` function** in native scenes. All initialization goes at the top level.\n\n## RULES\n\n1. NEVER access `window`, `document`, `Image()`, `localStorage`, or any DOM API. `fetch()` and `await import()` ARE available.\n2. ALWAYS declare parameters at the TOP LEVEL, never inside `render()`:\n ```javascript\n const speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\n function render(viji) { /* use speed.value */ }\n ```\n3. ALWAYS read parameters via `.value`: `speed.value`, `color.value`, `toggle.value`.\n4. ALWAYS use `viji.width` and `viji.height` for canvas dimensions. NEVER hardcode pixel sizes.\n5. ALWAYS use `viji.time` or `viji.deltaTime` for animation. NEVER count frames or assume a fixed frame rate.\n - `viji.time` — elapsed seconds. Use for constant-speed oscillations only: `sin(viji.time * 2.0)`.\n - `viji.deltaTime` — seconds since last frame. Use for accumulators: `angle += speed.value * viji.deltaTime;`\n6. NEVER multiply `viji.time` by a parameter for animation speed — it causes jumps when the parameter changes. ALWAYS use a `deltaTime` accumulator:\n ```javascript\n // WRONG — jumps when speed changes:\n const t = viji.time * speed.value;\n // RIGHT — smooth:\n let phase = 0; // top level\n phase += speed.value * viji.deltaTime; // in render()\n ```\n This also applies to **nested** multiplications. If `phase` is already an accumulator, NEVER multiply it by another parameter:\n ```javascript\n // WRONG — jumps when rotSpeed changes:\n const rot = phase * rotSpeed.value;\n // RIGHT — give it its own accumulator:\n let rotPhase = 0; // top level\n rotPhase += speed.value * rotSpeed.value * viji.deltaTime; // in render()\n ```\n7. NEVER allocate objects, arrays, or strings inside `render()`. Pre-allocate at the top level and reuse.\n8. ALWAYS call `viji.useContext()` to get a canvas context. Choose ONE type and use it for the entire scene:\n - `viji.useContext('2d')` — Canvas 2D\n - `viji.useContext('webgl')` — WebGL 1\n - `viji.useContext('webgl2')` — WebGL 2\n Calling a different type after the first returns `null`.\n9. ALWAYS check `viji.audio.isConnected` before using audio data.\n10. ALWAYS check `viji.video.isConnected && viji.video.currentFrame` before drawing video.\n11. NEVER enable CV features by default. Use a toggle parameter so the user can opt in:\n ```javascript\n const useFace = viji.toggle(false, { label: 'Enable Face Detection', category: 'video' });\n // In render:\n if (useFace.value) await viji.video.cv.enableFaceDetection(true);\n else await viji.video.cv.enableFaceDetection(false);\n ```\n12. Be mindful of WebGL context limits — each CV feature uses its own WebGL context for ML. Enabling too many can cause context loss.\n13. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio-related, `category: 'video'` for video/camera/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host UI hide irrelevant controls when the input is inactive.\n ```javascript\n const audioReact = viji.toggle(true, { label: 'Audio Reactive', group: 'audio', category: 'audio' });\n const followMouse = viji.toggle(true, { label: 'Follow Mouse', group: 'interaction', category: 'interaction' });\n ```\n14. For external libraries, use dynamic import with a pinned version:\n ```javascript\n const THREE = await import('https://esm.sh/three@0.160.0');\n ```\n Pass `viji.canvas` to the library's renderer. ALWAYS pass `false` as the third argument to Three.js `setSize()`.\n\n## COMPLETE API REFERENCE\n\n### Canvas & Context\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.canvas` | `OffscreenCanvas` | The canvas element |\n| `viji.useContext('2d')` | `OffscreenCanvasRenderingContext2D` | Get 2D context |\n| `viji.useContext('webgl')` | `WebGLRenderingContext` | Get WebGL 1 context |\n| `viji.useContext('webgl2')` | `WebGL2RenderingContext` | Get WebGL 2 context |\n| `viji.ctx` | `OffscreenCanvasRenderingContext2D` | Shortcut (after useContext('2d')) |\n| `viji.gl` | `WebGLRenderingContext` | Shortcut (after useContext('webgl')) |\n| `viji.width` | `number` | Current canvas width in pixels |\n| `viji.height` | `number` | Current canvas height in pixels |\n\n### Timing\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.time` | `number` | Seconds since scene start |\n| `viji.deltaTime` | `number` | Seconds since last frame |\n| `viji.frameCount` | `number` | Total frames rendered |\n| `viji.fps` | `number` | Target frame rate (based on host frame-rate mode) |\n\n### Parameters\n\nDeclare at top level. Read `.value` inside `render()`. All support `{ label, description?, group?, category? }`.\nCategory values: `'audio'`, `'video'`, `'interaction'`, `'general'`.\n\n```javascript\nviji.slider(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.color(default, { label, group?, category? }) // { value: '#rrggbb' }\nviji.toggle(default, { label, group?, category? }) // { value: boolean }\nviji.select(default, { options: [...], label, group?, category? }) // { value: string|number }\nviji.number(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.text(default, { label, group?, category?, maxLength? }) // { value: string }\nviji.image(null, { label, group?, category? }) // { value: ImageBitmap|null }\nviji.button({ label, description?, group?, category? }) // { value: boolean } (true one frame)\n```\n\n### Audio — `viji.audio`\n\nALWAYS check `viji.audio.isConnected` first.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether audio source is active |\n| `volume.current` | `number` | RMS volume 0–1 |\n| `volume.peak` | `number` | Peak amplitude 0–1 |\n| `volume.smoothed` | `number` | Smoothed volume (200ms decay) |\n| `bands.low` | `number` | 20–120 Hz energy 0–1 |\n| `bands.lowMid` | `number` | 120–400 Hz energy 0–1 |\n| `bands.mid` | `number` | 400–1600 Hz energy 0–1 |\n| `bands.highMid` | `number` | 1600–6000 Hz energy 0–1 |\n| `bands.high` | `number` | 6000–16000 Hz energy 0–1 |\n| `bands.lowSmoothed` … `bands.highSmoothed` | `number` | Smoothed variants of each band |\n| `beat.kick` | `number` | Kick energy 0–1 |\n| `beat.snare` | `number` | Snare energy 0–1 |\n| `beat.hat` | `number` | Hi-hat energy 0–1 |\n| `beat.any` | `number` | Any beat energy 0–1 |\n| `beat.kickSmoothed` … `beat.anySmoothed` | `number` | Smoothed beat values |\n| `beat.triggers.kick` | `boolean` | True on kick frame |\n| `beat.triggers.snare` | `boolean` | True on snare frame |\n| `beat.triggers.hat` | `boolean` | True on hat frame |\n| `beat.triggers.any` | `boolean` | True on any beat frame |\n| `beat.events` | `Array<{type,time,strength}>` | Recent beat events |\n| `beat.bpm` | `number` | Estimated BPM (60–240) |\n| `beat.confidence` | `number` | BPM tracking confidence 0–1 |\n| `beat.isLocked` | `boolean` | True when BPM is locked |\n| `spectral.brightness` | `number` | Spectral centroid 0–1 |\n| `spectral.flatness` | `number` | Spectral flatness 0–1 |\n| `getFrequencyData()` | `Uint8Array` | Raw FFT bins (0–255) |\n| `getWaveform()` | `Float32Array` | Time-domain waveform (−1 to 1) |\n\n**`viji.audioStreams` & `device.audio`:** Host and external devices may expose additional sources as **`AudioStreamAPI`** — same `isConnected`, `volume`, `bands` (+ smoothed), `spectral`, `getFrequencyData()`, and `getWaveform()` as above, but **no** `beat`, BPM, triggers, or events (lightweight subset).\n\n### Video — `viji.video`\n\nALWAYS check `viji.video.isConnected` first. Check `currentFrame` before drawing.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether video source is active |\n| `currentFrame` | `OffscreenCanvas\\|ImageBitmap\\|null` | Current video frame |\n| `frameWidth` | `number` | Frame width in pixels |\n| `frameHeight` | `number` | Frame height in pixels |\n| `frameRate` | `number` | Video frame rate |\n| `getFrameData()` | `ImageData\\|null` | Pixel data for CPU access |\n\nDraw video: `ctx.drawImage(viji.video.currentFrame, 0, 0, viji.width, viji.height)`\n\n### Computer Vision — `viji.video.cv` & `viji.video.faces/hands/pose/segmentation`\n\nEnable features via toggle parameters (NEVER enable by default):\n\n```javascript\nawait viji.video.cv.enableFaceDetection(true/false);\nawait viji.video.cv.enableFaceMesh(true/false);\nawait viji.video.cv.enableEmotionDetection(true/false);\nawait viji.video.cv.enableHandTracking(true/false);\nawait viji.video.cv.enablePoseDetection(true/false);\nawait viji.video.cv.enableBodySegmentation(true/false);\nviji.video.cv.getActiveFeatures(); // CVFeature[]\nviji.video.cv.isProcessing(); // boolean\n```\n\n**`viji.video.faces: FaceData[]`**\nEach face: `id` (number), `bounds` ({x,y,width,height}), `center` ({x,y}), `confidence` (0–1), `landmarks` ({x,y,z?}[]), `expressions` ({neutral,happy,sad,angry,surprised,disgusted,fearful} all 0–1), `headPose` ({pitch,yaw,roll}), `blendshapes` (52 ARKit coefficients: browDownLeft, browDownRight, browInnerUp, browOuterUpLeft, browOuterUpRight, cheekPuff, cheekSquintLeft, cheekSquintRight, eyeBlinkLeft, eyeBlinkRight, eyeLookDownLeft, eyeLookDownRight, eyeLookInLeft, eyeLookInRight, eyeLookOutLeft, eyeLookOutRight, eyeLookUpLeft, eyeLookUpRight, eyeSquintLeft, eyeSquintRight, eyeWideLeft, eyeWideRight, jawForward, jawLeft, jawOpen, jawRight, mouthClose, mouthDimpleLeft, mouthDimpleRight, mouthFrownLeft, mouthFrownRight, mouthFunnel, mouthLeft, mouthLowerDownLeft, mouthLowerDownRight, mouthPressLeft, mouthPressRight, mouthPucker, mouthRight, mouthRollLower, mouthRollUpper, mouthShrugLower, mouthShrugUpper, mouthSmileLeft, mouthSmileRight, mouthStretchLeft, mouthStretchRight, mouthUpperUpLeft, mouthUpperUpRight, noseSneerLeft, noseSneerRight, tongueOut — all 0–1).\n\n**`viji.video.hands: HandData[]`**\nEach hand: `id` (number), `handedness` ('left'|'right'), `confidence` (0–1), `bounds` ({x,y,width,height}), `landmarks` ({x,y,z}[], 21 points), `palm` ({x,y,z}), `gestures` ({fist,openPalm,peace,thumbsUp,thumbsDown,pointing,iLoveYou} all 0–1 confidence).\n\n**`viji.video.pose: PoseData | null`**\n`confidence` (0–1), `landmarks` ({x,y,z,visibility}[], 33 points), plus body-part arrays: `face` ({x,y}[]), `torso`, `leftArm`, `rightArm`, `leftLeg`, `rightLeg`.\n\n**`viji.video.segmentation: SegmentationData | null`**\n`mask` (Uint8Array, 0=background 255=person), `width`, `height`.\n\n### Input — Pointer (unified mouse/touch) — `viji.pointer`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `deltaX`, `deltaY` | `number` | Movement since last frame |\n| `isDown` | `boolean` | True if pressed/touching |\n| `wasPressed` | `boolean` | True on press frame |\n| `wasReleased` | `boolean` | True on release frame |\n| `isInCanvas` | `boolean` | True if inside canvas |\n| `type` | `string` | `'mouse'`, `'touch'`, or `'none'` |\n\n### Input — Mouse — `viji.mouse`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `isInCanvas` | `boolean` | Inside canvas bounds |\n| `isPressed` | `boolean` | Any button pressed |\n| `leftButton`, `rightButton`, `middleButton` | `boolean` | Specific buttons |\n| `deltaX`, `deltaY` | `number` | Movement delta |\n| `wheelDelta` | `number` | Scroll wheel delta |\n| `wheelX`, `wheelY` | `number` | Horizontal/vertical scroll |\n| `wasPressed`, `wasReleased`, `wasMoved` | `boolean` | Frame-edge events |\n\n### Input — Keyboard — `viji.keyboard`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isPressed(key)` | `boolean` | True while key is held |\n| `wasPressed(key)` | `boolean` | True on key-down frame |\n| `wasReleased(key)` | `boolean` | True on key-up frame |\n| `activeKeys` | `Set<string>` | Currently held keys |\n| `pressedThisFrame` | `Set<string>` | Keys pressed this frame |\n| `releasedThisFrame` | `Set<string>` | Keys released this frame |\n| `lastKeyPressed` | `string` | Most recent key-down |\n| `lastKeyReleased` | `string` | Most recent key-up |\n| `shift`, `ctrl`, `alt`, `meta` | `boolean` | Modifier states |\n\n### Input — Touch — `viji.touches`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `count` | `number` | Active touch count |\n| `points` | `TouchPoint[]` | All active touches |\n| `started` | `TouchPoint[]` | Touches started this frame |\n| `moved` | `TouchPoint[]` | Touches moved this frame |\n| `ended` | `TouchPoint[]` | Touches ended this frame |\n| `primary` | `TouchPoint\\|null` | First active touch |\n\n**TouchPoint:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force`, `isInCanvas`, `deltaX`, `deltaY`, `velocity` ({x,y}), `isNew`, `isActive`, `isEnding`.\n\n### Device Sensors — `viji.device`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `motion` | `DeviceMotionData\\|null` | Accelerometer/gyroscope |\n| `orientation` | `DeviceOrientationData\\|null` | Device orientation |\n\n**DeviceMotionData:** `acceleration` ({x,y,z} m/s²), `accelerationIncludingGravity`, `rotationRate` ({alpha,beta,gamma} deg/s), `interval` (ms).\n**DeviceOrientationData:** `alpha` (0–360° compass), `beta` (−180–180° tilt), `gamma` (−90–90° tilt), `absolute` (boolean).\n\n### External Devices — `viji.devices`\n\nArray of connected external devices. Each `DeviceState`:\n`id` (string), `name` (string), `motion` (DeviceMotionData|null), `orientation` (DeviceOrientationData|null), `video` (VideoAPI|null — same as viji.video but without CV), `audio` (AudioStreamAPI|null — lightweight analysis only; no beat/BPM/triggers).\n\n### Streams — `viji.videoStreams`\n\n`VideoAPI[]` — additional video sources provided by the host application (used by the compositor for scene mixing). May be empty. Each element has the same shape as `viji.video`.\n\n### Streams — `viji.audioStreams`\n\n`AudioStreamAPI[]` — additional audio sources from the host (e.g. multi-source mixing). May be empty. Lightweight interface: volume, bands, spectral features, `getFrequencyData()`, `getWaveform()` — **not** the full `AudioAPI` (no beat detection, BPM, triggers, or events).\n\n### External Libraries\n\n```javascript\nconst THREE = await import('https://esm.sh/three@0.160.0');\nconst renderer = new THREE.WebGLRenderer({ canvas: viji.canvas, antialias: true });\nrenderer.setSize(viji.width, viji.height, false); // false = no CSS styles\n```\n\nALWAYS pin library versions. ALWAYS pass `viji.canvas` to the renderer. Handle resize in `render()`.\n\n## BEST PRACTICES\n\n1. NEVER use `viji.time * speed.value` — use a `deltaTime` accumulator instead (see rule 6). Same for nested: never multiply an accumulator by another parameter.\n2. Guard audio/video with `isConnected` checks.\n3. Pre-allocate all objects/arrays at top level — never inside `render()`.\n4. For CV, use toggle parameters — never enable by default.\n5. ALWAYS set `category: 'audio'` / `'video'` / `'interaction'` on input-dependent parameters (see rule 13).\n6. For WebGL scenes with Three.js, handle resize by comparing `viji.width/height` with previous values.\n\n## TEMPLATE\n\n```javascript\nconst bgColor = viji.color('#1a1a2e', { label: 'Background' });\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst count = viji.slider(12, { min: 3, max: 30, step: 1, label: 'Count' });\n\nlet angle = 0;\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n angle += speed.value * viji.deltaTime;\n\n ctx.fillStyle = bgColor.value;\n ctx.fillRect(0, 0, viji.width, viji.height);\n\n const cx = viji.width / 2;\n const cy = viji.height / 2;\n const radius = Math.min(viji.width, viji.height) * 0.3;\n const dotSize = Math.min(viji.width, viji.height) * 0.02;\n const n = Math.floor(count.value);\n\n for (let i = 0; i < n; i++) {\n const a = angle + (i / n) * Math.PI * 2;\n const x = cx + Math.cos(a) * radius;\n const y = cy + Math.sin(a) * radius;\n const hue = (i / n) * 360;\n ctx.beginPath();\n ctx.arc(x, y, dotSize, 0, Math.PI * 2);\n ctx.fillStyle = `hsl(${hue}, 80%, 60%)`;\n ctx.fill();\n }\n}\n```\n\nNow generate a Viji native scene based on the artist's description below. Return ONLY the scene code.\nFollow all rules. Use `viji.deltaTime` for animation. Use parameters for anything the user might want to adjust. Check `isConnected` before using audio or video.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant (ChatGPT, Claude, etc.).\n3. After the prompt, describe the scene you want — be as specific as you like.\n4. The AI will return a complete Viji native scene.\n\n> [!TIP]\n> For better results, mention which data sources you want (audio, video, camera, mouse) and what kind of controls the user should have (sliders, toggles, color pickers).\n\n## Related\n\n- [Create Your First Scene](/ai-prompts/create-first-scene) — guided prompt for beginners\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n- [Native Quick Start](/native/quickstart) — your first Viji native scene\n- [Native API Reference](/native/api-reference) — full API reference\n- [Best Practices](/getting-started/best-practices) — essential patterns for robust scenes\n- [Common Mistakes](/getting-started/common-mistakes) — pitfalls to avoid"
|
|
966
|
+
"markdown": "# Prompt: Native Scenes\n\nCopy the prompt below and paste it into your AI assistant. Then describe the scene you want. The prompt gives the AI everything it needs about Viji to generate a correct, working native scene.\n\n## The Prompt\n\n````\nYou are generating a Viji native scene — a creative visual that runs inside an OffscreenCanvas Web Worker.\nArtists describe what they want; you produce complete, working scene code. Apply every rule below exactly.\n\n## REFERENCE (for AI assistants with web access)\n\nThis prompt is self-contained — all information needed is included below.\nFor the latest API documentation and type definitions:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## ARCHITECTURE\n\n- Scenes run in a **Web Worker** with an **OffscreenCanvas**. There is no DOM.\n- The global `viji` object provides canvas, timing, audio, video, CV, input, sensors, and parameters.\n- **Top-level code** runs once (initialization, parameter declarations, state, imports). Top-level `await` is supported for dynamic imports.\n- **`function render(viji) { ... }`** is called every frame. This is where you draw.\n- There is **no `setup()` function** in native scenes. All initialization goes at the top level.\n\n## RULES\n\n1. NEVER access `window`, `document`, `Image()`, `localStorage`, or any DOM API. `fetch()` and `await import()` ARE available.\n2. ALWAYS declare parameters at the TOP LEVEL, never inside `render()`:\n ```javascript\n const speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\n function render(viji) { /* use speed.value */ }\n ```\n3. ALWAYS read parameters via `.value`: `speed.value`, `color.value`, `toggle.value`.\n4. ALWAYS use `viji.width` and `viji.height` for canvas dimensions. NEVER hardcode pixel sizes.\n5. ALWAYS use `viji.time` or `viji.deltaTime` for animation. NEVER count frames or assume a fixed frame rate.\n - `viji.time` — elapsed seconds. Use for constant-speed oscillations only: `sin(viji.time * 2.0)`.\n - `viji.deltaTime` — seconds since last frame. Use for accumulators: `angle += speed.value * viji.deltaTime;`\n6. NEVER multiply `viji.time` by a parameter for animation speed — it causes jumps when the parameter changes. ALWAYS use a `deltaTime` accumulator:\n ```javascript\n // WRONG — jumps when speed changes:\n const t = viji.time * speed.value;\n // RIGHT — smooth:\n let phase = 0; // top level\n phase += speed.value * viji.deltaTime; // in render()\n ```\n This also applies to **nested** multiplications. If `phase` is already an accumulator, NEVER multiply it by another parameter:\n ```javascript\n // WRONG — jumps when rotSpeed changes:\n const rot = phase * rotSpeed.value;\n // RIGHT — give it its own accumulator:\n let rotPhase = 0; // top level\n rotPhase += speed.value * rotSpeed.value * viji.deltaTime; // in render()\n ```\n7. NEVER allocate objects, arrays, or strings inside `render()`. Pre-allocate at the top level and reuse.\n8. ALWAYS call `viji.useContext()` to get a canvas context. Choose ONE type and use it for the entire scene:\n - `viji.useContext('2d')` — Canvas 2D\n - `viji.useContext('webgl')` — WebGL 1\n - `viji.useContext('webgl2')` — WebGL 2\n Calling a different type after the first returns `null`.\n9. ALWAYS check `viji.audio.isConnected` before using audio data.\n10. ALWAYS check `viji.video.isConnected && viji.video.currentFrame` before drawing video.\n11. NEVER enable CV features by default. Use a toggle parameter so the user can opt in:\n ```javascript\n const useFace = viji.toggle(false, { label: 'Enable Face Detection', category: 'video' });\n // In render:\n if (useFace.value) await viji.video.cv.enableFaceDetection(true);\n else await viji.video.cv.enableFaceDetection(false);\n ```\n12. Be mindful of WebGL context limits — each CV feature uses its own WebGL context for ML. Enabling too many can cause context loss.\n13. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio-related, `category: 'video'` for video/camera/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host UI hide irrelevant controls when the input is inactive.\n ```javascript\n const audioReact = viji.toggle(true, { label: 'Audio Reactive', group: 'audio', category: 'audio' });\n const followMouse = viji.toggle(true, { label: 'Follow Mouse', group: 'interaction', category: 'interaction' });\n ```\n14. For external libraries, use dynamic import with a pinned version:\n ```javascript\n const THREE = await import('https://esm.sh/three@0.160.0');\n ```\n Pass `viji.canvas` to the library's renderer. ALWAYS pass `false` as the third argument to Three.js `setSize()`.\n\n## COMPLETE API REFERENCE\n\n### Canvas & Context\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.canvas` | `OffscreenCanvas` | The canvas element |\n| `viji.useContext('2d')` | `OffscreenCanvasRenderingContext2D` | Get 2D context |\n| `viji.useContext('webgl')` | `WebGLRenderingContext` | Get WebGL 1 context |\n| `viji.useContext('webgl2')` | `WebGL2RenderingContext` | Get WebGL 2 context |\n| `viji.ctx` | `OffscreenCanvasRenderingContext2D` | Shortcut (after useContext('2d')) |\n| `viji.gl` | `WebGLRenderingContext` | Shortcut (after useContext('webgl')) |\n| `viji.width` | `number` | Current canvas width in pixels |\n| `viji.height` | `number` | Current canvas height in pixels |\n\n### Timing\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.time` | `number` | Seconds since scene start |\n| `viji.deltaTime` | `number` | Seconds since last frame |\n| `viji.frameCount` | `number` | Total frames rendered |\n| `viji.fps` | `number` | Target frame rate (based on host frame-rate mode) |\n\n### Parameters\n\nDeclare at top level. Read `.value` inside `render()`. All support `{ label, description?, group?, category? }`.\nCategory values: `'audio'`, `'video'`, `'interaction'`, `'general'`.\n\n```javascript\nviji.slider(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.color(default, { label, group?, category? }) // { value: '#rrggbb' }\nviji.toggle(default, { label, group?, category? }) // { value: boolean }\nviji.select(default, { options: [...], label, group?, category? }) // { value: string|number }\nviji.number(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.text(default, { label, group?, category?, maxLength? }) // { value: string }\nviji.image(null, { label, group?, category? }) // { value: ImageBitmap|null }\nviji.button({ label, description?, group?, category? }) // { value: boolean } (true one frame)\n```\n\n- `viji.coordinate(defaultValue, config)` — 2D coordinate, `{ x: number, y: number }`, both -1 to 1. Config: `{ step?, label, description?, group?, category? }`\n\n### Audio — `viji.audio`\n\nALWAYS check `viji.audio.isConnected` first.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether audio source is active |\n| `volume.current` | `number` | RMS volume 0–1 |\n| `volume.peak` | `number` | Peak amplitude 0–1 |\n| `volume.smoothed` | `number` | Smoothed volume (200ms decay) |\n| `bands.low` | `number` | 20–120 Hz energy 0–1 |\n| `bands.lowMid` | `number` | 120–400 Hz energy 0–1 |\n| `bands.mid` | `number` | 400–1600 Hz energy 0–1 |\n| `bands.highMid` | `number` | 1600–6000 Hz energy 0–1 |\n| `bands.high` | `number` | 6000–16000 Hz energy 0–1 |\n| `bands.lowSmoothed` … `bands.highSmoothed` | `number` | Smoothed variants of each band |\n| `beat.kick` | `number` | Kick energy 0–1 |\n| `beat.snare` | `number` | Snare energy 0–1 |\n| `beat.hat` | `number` | Hi-hat energy 0–1 |\n| `beat.any` | `number` | Any beat energy 0–1 |\n| `beat.kickSmoothed` … `beat.anySmoothed` | `number` | Smoothed beat values |\n| `beat.triggers.kick` | `boolean` | True on kick frame |\n| `beat.triggers.snare` | `boolean` | True on snare frame |\n| `beat.triggers.hat` | `boolean` | True on hat frame |\n| `beat.triggers.any` | `boolean` | True on any beat frame |\n| `beat.events` | `Array<{type,time,strength}>` | Recent beat events |\n| `beat.bpm` | `number` | Estimated BPM (60–240) |\n| `beat.confidence` | `number` | BPM tracking confidence 0–1 |\n| `beat.isLocked` | `boolean` | True when BPM is locked |\n| `spectral.brightness` | `number` | Spectral centroid 0–1 |\n| `spectral.flatness` | `number` | Spectral flatness 0–1 |\n| `getFrequencyData()` | `Uint8Array` | Raw FFT bins (0–255) |\n| `getWaveform()` | `Float32Array` | Time-domain waveform (−1 to 1) |\n\n**`viji.audioStreams` & `device.audio`:** Host and external devices may expose additional sources as **`AudioStreamAPI`** — same `isConnected`, `volume`, `bands` (+ smoothed), `spectral`, `getFrequencyData()`, and `getWaveform()` as above, but **no** `beat`, BPM, triggers, or events (lightweight subset).\n\n### Video — `viji.video`\n\nALWAYS check `viji.video.isConnected` first. Check `currentFrame` before drawing.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether video source is active |\n| `currentFrame` | `OffscreenCanvas\\|ImageBitmap\\|null` | Current video frame |\n| `frameWidth` | `number` | Frame width in pixels |\n| `frameHeight` | `number` | Frame height in pixels |\n| `frameRate` | `number` | Video frame rate |\n| `getFrameData()` | `ImageData\\|null` | Pixel data for CPU access |\n\nDraw video: `ctx.drawImage(viji.video.currentFrame, 0, 0, viji.width, viji.height)`\n\n### Computer Vision — `viji.video.cv` & `viji.video.faces/hands/pose/segmentation`\n\nEnable features via toggle parameters (NEVER enable by default):\n\n```javascript\nawait viji.video.cv.enableFaceDetection(true/false);\nawait viji.video.cv.enableFaceMesh(true/false);\nawait viji.video.cv.enableEmotionDetection(true/false);\nawait viji.video.cv.enableHandTracking(true/false);\nawait viji.video.cv.enablePoseDetection(true/false);\nawait viji.video.cv.enableBodySegmentation(true/false);\nviji.video.cv.getActiveFeatures(); // CVFeature[]\nviji.video.cv.isProcessing(); // boolean\n```\n\n**`viji.video.faces: FaceData[]`**\nEach face: `id` (number), `bounds` ({x,y,width,height}), `center` ({x,y}), `confidence` (0–1), `landmarks` ({x,y,z?}[]), `expressions` ({neutral,happy,sad,angry,surprised,disgusted,fearful} all 0–1), `headPose` ({pitch,yaw,roll}), `blendshapes` (52 ARKit coefficients: browDownLeft, browDownRight, browInnerUp, browOuterUpLeft, browOuterUpRight, cheekPuff, cheekSquintLeft, cheekSquintRight, eyeBlinkLeft, eyeBlinkRight, eyeLookDownLeft, eyeLookDownRight, eyeLookInLeft, eyeLookInRight, eyeLookOutLeft, eyeLookOutRight, eyeLookUpLeft, eyeLookUpRight, eyeSquintLeft, eyeSquintRight, eyeWideLeft, eyeWideRight, jawForward, jawLeft, jawOpen, jawRight, mouthClose, mouthDimpleLeft, mouthDimpleRight, mouthFrownLeft, mouthFrownRight, mouthFunnel, mouthLeft, mouthLowerDownLeft, mouthLowerDownRight, mouthPressLeft, mouthPressRight, mouthPucker, mouthRight, mouthRollLower, mouthRollUpper, mouthShrugLower, mouthShrugUpper, mouthSmileLeft, mouthSmileRight, mouthStretchLeft, mouthStretchRight, mouthUpperUpLeft, mouthUpperUpRight, noseSneerLeft, noseSneerRight, tongueOut — all 0–1).\n\n**`viji.video.hands: HandData[]`**\nEach hand: `id` (number), `handedness` ('left'|'right'), `confidence` (0–1), `bounds` ({x,y,width,height}), `landmarks` ({x,y,z}[], 21 points), `palm` ({x,y,z}), `gestures` ({fist,openPalm,peace,thumbsUp,thumbsDown,pointing,iLoveYou} all 0–1 confidence).\n\n**`viji.video.pose: PoseData | null`**\n`confidence` (0–1), `landmarks` ({x,y,z,visibility}[], 33 points), plus body-part arrays: `face` ({x,y}[]), `torso`, `leftArm`, `rightArm`, `leftLeg`, `rightLeg`.\n\n**`viji.video.segmentation: SegmentationData | null`**\n`mask` (Uint8Array, 0=background 255=person), `width`, `height`.\n\n### Input — Pointer (unified mouse/touch) — `viji.pointer`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `deltaX`, `deltaY` | `number` | Movement since last frame |\n| `isDown` | `boolean` | True if pressed/touching |\n| `wasPressed` | `boolean` | True on press frame |\n| `wasReleased` | `boolean` | True on release frame |\n| `isInCanvas` | `boolean` | True if inside canvas |\n| `type` | `string` | `'mouse'`, `'touch'`, or `'none'` |\n\n### Input — Mouse — `viji.mouse`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `isInCanvas` | `boolean` | Inside canvas bounds |\n| `isPressed` | `boolean` | Any button pressed |\n| `leftButton`, `rightButton`, `middleButton` | `boolean` | Specific buttons |\n| `deltaX`, `deltaY` | `number` | Movement delta |\n| `wheelDelta` | `number` | Scroll wheel delta |\n| `wheelX`, `wheelY` | `number` | Horizontal/vertical scroll |\n| `wasPressed`, `wasReleased`, `wasMoved` | `boolean` | Frame-edge events |\n\n### Input — Keyboard — `viji.keyboard`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isPressed(key)` | `boolean` | True while key is held |\n| `wasPressed(key)` | `boolean` | True on key-down frame |\n| `wasReleased(key)` | `boolean` | True on key-up frame |\n| `activeKeys` | `Set<string>` | Currently held keys |\n| `pressedThisFrame` | `Set<string>` | Keys pressed this frame |\n| `releasedThisFrame` | `Set<string>` | Keys released this frame |\n| `lastKeyPressed` | `string` | Most recent key-down |\n| `lastKeyReleased` | `string` | Most recent key-up |\n| `shift`, `ctrl`, `alt`, `meta` | `boolean` | Modifier states |\n\n### Input — Touch — `viji.touches`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `count` | `number` | Active touch count |\n| `points` | `TouchPoint[]` | All active touches |\n| `started` | `TouchPoint[]` | Touches started this frame |\n| `moved` | `TouchPoint[]` | Touches moved this frame |\n| `ended` | `TouchPoint[]` | Touches ended this frame |\n| `primary` | `TouchPoint\\|null` | First active touch |\n\n**TouchPoint:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force`, `isInCanvas`, `deltaX`, `deltaY`, `velocity` ({x,y}), `isNew`, `isActive`, `isEnding`.\n\n### Device Sensors — `viji.device`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `motion` | `DeviceMotionData\\|null` | Accelerometer/gyroscope |\n| `orientation` | `DeviceOrientationData\\|null` | Device orientation |\n\n**DeviceMotionData:** `acceleration` ({x,y,z} m/s²), `accelerationIncludingGravity`, `rotationRate` ({alpha,beta,gamma} deg/s), `interval` (ms).\n**DeviceOrientationData:** `alpha` (0–360° compass), `beta` (−180–180° tilt), `gamma` (−90–90° tilt), `absolute` (boolean).\n\n### External Devices — `viji.devices`\n\nArray of connected external devices. Each `DeviceState`:\n`id` (string), `name` (string), `motion` (DeviceMotionData|null), `orientation` (DeviceOrientationData|null), `video` (VideoAPI|null — same as viji.video but without CV), `audio` (AudioStreamAPI|null — lightweight analysis only; no beat/BPM/triggers).\n\n### Streams — `viji.videoStreams`\n\n`VideoAPI[]` — additional video sources provided by the host application (used by the compositor for scene mixing). May be empty. Each element has the same shape as `viji.video`.\n\n### Streams — `viji.audioStreams`\n\n`AudioStreamAPI[]` — additional audio sources from the host (e.g. multi-source mixing). May be empty. Lightweight interface: volume, bands, spectral features, `getFrequencyData()`, `getWaveform()` — **not** the full `AudioAPI` (no beat detection, BPM, triggers, or events).\n\n### External Libraries\n\n```javascript\nconst THREE = await import('https://esm.sh/three@0.160.0');\nconst renderer = new THREE.WebGLRenderer({ canvas: viji.canvas, antialias: true });\nrenderer.setSize(viji.width, viji.height, false); // false = no CSS styles\n```\n\nALWAYS pin library versions. ALWAYS pass `viji.canvas` to the renderer. Handle resize in `render()`.\n\n## BEST PRACTICES\n\n1. NEVER use `viji.time * speed.value` — use a `deltaTime` accumulator instead (see rule 6). Same for nested: never multiply an accumulator by another parameter.\n2. Guard audio/video with `isConnected` checks.\n3. Pre-allocate all objects/arrays at top level — never inside `render()`.\n4. For CV, use toggle parameters — never enable by default.\n5. ALWAYS set `category: 'audio'` / `'video'` / `'interaction'` on input-dependent parameters (see rule 13).\n6. For WebGL scenes with Three.js, handle resize by comparing `viji.width/height` with previous values.\n\n## TEMPLATE\n\n```javascript\nconst bgColor = viji.color('#1a1a2e', { label: 'Background' });\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst count = viji.slider(12, { min: 3, max: 30, step: 1, label: 'Count' });\n\nlet angle = 0;\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n angle += speed.value * viji.deltaTime;\n\n ctx.fillStyle = bgColor.value;\n ctx.fillRect(0, 0, viji.width, viji.height);\n\n const cx = viji.width / 2;\n const cy = viji.height / 2;\n const radius = Math.min(viji.width, viji.height) * 0.3;\n const dotSize = Math.min(viji.width, viji.height) * 0.02;\n const n = Math.floor(count.value);\n\n for (let i = 0; i < n; i++) {\n const a = angle + (i / n) * Math.PI * 2;\n const x = cx + Math.cos(a) * radius;\n const y = cy + Math.sin(a) * radius;\n const hue = (i / n) * 360;\n ctx.beginPath();\n ctx.arc(x, y, dotSize, 0, Math.PI * 2);\n ctx.fillStyle = `hsl(${hue}, 80%, 60%)`;\n ctx.fill();\n }\n}\n```\n\nNow generate a Viji native scene based on the artist's description below. Return ONLY the scene code.\nFollow all rules. Use `viji.deltaTime` for animation. Use parameters for anything the user might want to adjust. Check `isConnected` before using audio or video.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant (ChatGPT, Claude, etc.).\n3. After the prompt, describe the scene you want — be as specific as you like.\n4. The AI will return a complete Viji native scene.\n\n> [!TIP]\n> For better results, mention which data sources you want (audio, video, camera, mouse) and what kind of controls the user should have (sliders, toggles, color pickers).\n\n## Related\n\n- [Create Your First Scene](/ai-prompts/create-first-scene) — guided prompt for beginners\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n- [Native Quick Start](/native/quickstart) — your first Viji native scene\n- [Native API Reference](/native/api-reference) — full API reference\n- [Best Practices](/getting-started/best-practices) — essential patterns for robust scenes\n- [Common Mistakes](/getting-started/common-mistakes) — pitfalls to avoid"
|
|
952
967
|
}
|
|
953
968
|
]
|
|
954
969
|
},
|
|
@@ -959,7 +974,7 @@ export const docsApi = {
|
|
|
959
974
|
"content": [
|
|
960
975
|
{
|
|
961
976
|
"type": "text",
|
|
962
|
-
"markdown": "# Prompt: P5 Scenes\n\nCopy the prompt below and paste it into your AI assistant. Then describe the scene you want. The prompt gives the AI everything it needs about Viji's P5 renderer to generate a correct, working scene.\n\n## The Prompt\n\n````\nYou are generating a Viji P5.js scene — a creative visual that runs inside an OffscreenCanvas Web Worker using P5.js.\nArtists describe what they want; you produce complete, working scene code. Apply every rule below exactly.\n\n## REFERENCE (for AI assistants with web access)\n\nThis prompt is self-contained — all information needed is included below.\nFor the latest API documentation and type definitions:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## ARCHITECTURE\n\n- Scenes run in a **Web Worker** with an **OffscreenCanvas**. There is no DOM.\n- Viji automatically loads **P5.js v1.9.4** when you use `// @renderer p5` or `// @renderer p5 webgl`.\n- The global `viji` object provides canvas, timing, audio, video, CV, input, sensors, and parameters.\n- **Top-level code** runs once (initialization, parameter declarations, state).\n- **`function render(viji, p5) { ... }`** is called every frame. This is where you draw.\n- Optional **`function setup(viji, p5) { ... }`** runs once for configuration (e.g., `p5.colorMode()`).\n- P5 runs in **instance mode** — every P5 function and constant requires the `p5.` prefix.\n\n## RULES\n\n1. ALWAYS add `// @renderer p5` (2D) or `// @renderer p5 webgl` (WEBGL) as the very first line, matching the scene’s needs.\n2. ALWAYS use `render(viji, p5)` — not `draw()`. ALWAYS use `setup(viji, p5)` — not `setup()`.\n3. ALWAYS prefix every P5 function and constant with `p5.`:\n - `background(0)` → `p5.background(0)`\n - `fill(255)` → `p5.fill(255)`\n - `PI` → `p5.PI`, `TWO_PI` → `p5.TWO_PI`, `HSB` → `p5.HSB`\n - `createVector(1, 0)` → `p5.createVector(1, 0)`\n - `map(v, 0, 1, 0, 255)` → `p5.map(v, 0, 1, 0, 255)`\n - `noise(x)` → `p5.noise(x)`, `random()` → `p5.random()`\n This applies to ALL P5 functions and constants without exception.\n4. NEVER call `createCanvas()`. The canvas is created and managed by Viji.\n5. NEVER use `preload()`. Use `viji.image(null, { label: 'Name' })` for images, or `fetch()` in `setup()`.\n6. NEVER use P5 event callbacks: `mousePressed()`, `mouseDragged()`, `mouseReleased()`, `keyPressed()`, `keyReleased()`, `keyTyped()`, `touchStarted()`, `touchMoved()`, `touchEnded()`. Check state in `render()`:\n - `mouseIsPressed` → `viji.pointer.isDown` or `viji.mouse.isPressed`\n - `mouseX` / `mouseY` → `viji.pointer.x` / `viji.pointer.y` or `viji.mouse.x` / `viji.mouse.y`\n - `keyIsPressed` → `viji.keyboard.isPressed('keyName')`\n - For press-edge detection: `viji.pointer.wasPressed` / `viji.pointer.wasReleased`.\n7. NEVER use `loadImage()`, `loadFont()`, `loadJSON()`, `loadModel()`, `loadShader()`. Use `viji.image()` or `fetch()`.\n8. NEVER use `p5.frameRate()`, `p5.save()`, `p5.saveCanvas()`, `p5.saveFrames()`.\n9. NEVER use `createCapture()`, `createVideo()`. Use `viji.video.*` instead.\n10. NEVER use `p5.dom` or `p5.sound` libraries. Use Viji parameters for UI and `viji.audio.*` for audio.\n11. NEVER access `window`, `document`, `Image()`, or `localStorage`. `fetch()` IS available.\n12. ALWAYS declare parameters at the TOP LEVEL, never inside `render()` or `setup()`.\n13. ALWAYS read parameters via `.value`: `size.value`, `color.value`, `toggle.value`.\n14. ALWAYS use `viji.width` and `viji.height` for canvas dimensions. NEVER hardcode pixel sizes.\n15. ALWAYS use `viji.deltaTime` for frame-rate-independent animation:\n ```javascript\n let angle = 0;\n function render(viji, p5) { angle += speed.value * viji.deltaTime; }\n ```\n16. NEVER multiply `viji.time` by a parameter for animation speed — it causes jumps when the parameter changes. ALWAYS use a `deltaTime` accumulator (rule 15). This also applies to nested multiplications — never multiply an accumulator by another parameter; give each speed its own accumulator:\n ```javascript\n // WRONG — jumps: const t = viji.time * speed.value;\n // WRONG — nested: const rot = phase * rotSpeed.value;\n // RIGHT:\n let phase = 0, rotPhase = 0; // top level\n phase += speed.value * viji.deltaTime;\n rotPhase += speed.value * rotSpeed.value * viji.deltaTime;\n ```\n17. NEVER allocate objects, arrays, or strings inside `render()`. Pre-allocate at the top level and reuse.\n18. For image parameters displayed with P5, use `.p5` (not `.value`) with `p5.image()`:\n ```javascript\n const photo = viji.image(null, { label: 'Photo' });\n function render(viji, p5) {\n if (photo.value) p5.image(photo.p5, 0, 0, viji.width, viji.height);\n }\n ```\n19. For video frames: in **2D** (`// @renderer p5`) you may use `p5.image(viji.video.currentFrame, ...)` or `p5.drawingContext.drawImage(...)`. In **WEBGL** (`// @renderer p5 webgl`), use `p5.image(viji.video.currentFrame, ...)` only — `p5.drawingContext` is WebGL, not Canvas 2D.\n ```javascript\n if (viji.video.isConnected && viji.video.currentFrame) {\n p5.image(viji.video.currentFrame, 0, 0, viji.width, viji.height);\n }\n ```\n20. `p5.createGraphics()` works (creates OffscreenCanvas internally). Use for off-screen buffers.\n21. Fonts: `p5.textFont()` only with CSS generic names (`monospace`, `serif`, `sans-serif`). `loadFont()` is NOT available.\n22. `p5.tint()` and `p5.blendMode()` work normally.\n23. **Canvas mode:** Use `// @renderer p5` for a **2D** main canvas. For **WEBGL / 3D**, the first line MUST be `// @renderer p5 webgl`. NEVER call `createCanvas()` or `createCanvas(..., p5.WEBGL)` — Viji creates the canvas in the correct mode.\n24. In **WEBGL** scenes, `p5.drawingContext` is a WebGL context — never use Canvas 2D–only APIs on it. Use P5 3D drawing, `p5.image()` / textures for images and video.\n25. `p5.createGraphics(w, h)` is **2D only**. `createGraphics(w, h, p5.WEBGL)` is NOT supported.\n26. `p5.pixelDensity()` defaults to 1 in the worker. `p5.loadPixels()` and `p5.pixels[]` work (2D scenes; WEBGL pixel readback follows P5.js rules).\n27. ALWAYS check `viji.audio.isConnected` before using audio data.\n28. ALWAYS check `viji.video.isConnected && viji.video.currentFrame` before drawing video.\n29. NEVER enable CV features by default — use toggle parameters for user opt-in.\n30. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio-related, `category: 'video'` for video/camera/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host UI hide irrelevant controls when the input is inactive.\n ```javascript\n const audioReact = viji.toggle(true, { label: 'Audio Reactive', group: 'audio', category: 'audio' });\n const followMouse = viji.toggle(true, { label: 'Follow Mouse', group: 'interaction', category: 'interaction' });\n ```\n31. `viji.useContext()` is NOT available in P5 scenes — the canvas is managed by P5.\n\n## COMPLETE API REFERENCE\n\nAll `viji.*` members are identical to the native renderer (same object, same types).\n\n### Canvas & Timing\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.canvas` | `OffscreenCanvas` | The canvas element (managed by P5) |\n| `viji.width` | `number` | Current canvas width in pixels |\n| `viji.height` | `number` | Current canvas height in pixels |\n| `viji.time` | `number` | Seconds since scene start |\n| `viji.deltaTime` | `number` | Seconds since last frame |\n| `viji.frameCount` | `number` | Total frames rendered |\n| `viji.fps` | `number` | Target frame rate (based on host frame-rate mode) |\n\nNote: `viji.useContext()` is NOT available in P5. The canvas context is managed by P5 internally.\n\n### Parameters\n\nDeclare at top level. Read `.value` inside `render()`. All support `{ label, description?, group?, category? }`.\nCategory values: `'audio'`, `'video'`, `'interaction'`, `'general'`.\n\n```javascript\nviji.slider(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.color(default, { label, group?, category? }) // { value: '#rrggbb' }\nviji.toggle(default, { label, group?, category? }) // { value: boolean }\nviji.select(default, { options: [...], label, group?, category? }) // { value: string|number }\nviji.number(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.text(default, { label, group?, category?, maxLength? }) // { value: string }\nviji.image(null, { label, group?, category? }) // { value: ImageBitmap|null, p5: P5Image }\nviji.button({ label, description?, group?, category? }) // { value: boolean } (true one frame)\n```\n\n### Audio — `viji.audio`\n\nALWAYS check `viji.audio.isConnected` first.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether audio source is active |\n| `volume.current` | `number` | RMS volume 0–1 |\n| `volume.peak` | `number` | Peak amplitude 0–1 |\n| `volume.smoothed` | `number` | Smoothed volume (200ms decay) |\n| `bands.low` | `number` | 20–120 Hz energy 0–1 |\n| `bands.lowMid` | `number` | 120–400 Hz energy 0–1 |\n| `bands.mid` | `number` | 400–1600 Hz energy 0–1 |\n| `bands.highMid` | `number` | 1600–6000 Hz energy 0–1 |\n| `bands.high` | `number` | 6000–16000 Hz energy 0–1 |\n| `bands.lowSmoothed` … `bands.highSmoothed` | `number` | Smoothed variants of each band |\n| `beat.kick` | `number` | Kick energy 0–1 |\n| `beat.snare` | `number` | Snare energy 0–1 |\n| `beat.hat` | `number` | Hi-hat energy 0–1 |\n| `beat.any` | `number` | Any beat energy 0–1 |\n| `beat.kickSmoothed` … `beat.anySmoothed` | `number` | Smoothed beat values |\n| `beat.triggers.kick` | `boolean` | True on kick frame |\n| `beat.triggers.snare` | `boolean` | True on snare frame |\n| `beat.triggers.hat` | `boolean` | True on hat frame |\n| `beat.triggers.any` | `boolean` | True on any beat frame |\n| `beat.events` | `Array<{type,time,strength}>` | Recent beat events |\n| `beat.bpm` | `number` | Estimated BPM (60–240) |\n| `beat.confidence` | `number` | BPM tracking confidence 0–1 |\n| `beat.isLocked` | `boolean` | True when BPM is locked |\n| `spectral.brightness` | `number` | Spectral centroid 0–1 |\n| `spectral.flatness` | `number` | Spectral flatness 0–1 |\n| `getFrequencyData()` | `Uint8Array` | Raw FFT bins (0–255) |\n| `getWaveform()` | `Float32Array` | Time-domain waveform (−1 to 1) |\n\n**`viji.audioStreams` & `device.audio`:** Host and external devices may expose additional sources as **`AudioStreamAPI`** — same `isConnected`, `volume`, `bands` (+ smoothed), `spectral`, `getFrequencyData()`, and `getWaveform()` as above, but **no** `beat`, BPM, triggers, or events (lightweight subset).\n\n### Video — `viji.video`\n\nALWAYS check `viji.video.isConnected` first. Check `currentFrame` before drawing.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether video source is active |\n| `currentFrame` | `OffscreenCanvas\\|ImageBitmap\\|null` | Current video frame |\n| `frameWidth` | `number` | Frame width in pixels |\n| `frameHeight` | `number` | Frame height in pixels |\n| `frameRate` | `number` | Video frame rate |\n| `getFrameData()` | `ImageData\\|null` | Pixel data for CPU access |\n\nDraw video with P5: `p5.drawingContext.drawImage(viji.video.currentFrame, 0, 0, viji.width, viji.height)`\n\n### Computer Vision — `viji.video.cv` & `viji.video.faces/hands/pose/segmentation`\n\nEnable features via toggle parameters (NEVER enable by default):\n\n```javascript\nawait viji.video.cv.enableFaceDetection(true/false);\nawait viji.video.cv.enableFaceMesh(true/false);\nawait viji.video.cv.enableEmotionDetection(true/false);\nawait viji.video.cv.enableHandTracking(true/false);\nawait viji.video.cv.enablePoseDetection(true/false);\nawait viji.video.cv.enableBodySegmentation(true/false);\nviji.video.cv.getActiveFeatures(); // CVFeature[]\nviji.video.cv.isProcessing(); // boolean\n```\n\n**`viji.video.faces: FaceData[]`**\nEach face: `id` (number), `bounds` ({x,y,width,height}), `center` ({x,y}), `confidence` (0–1), `landmarks` ({x,y,z?}[]), `expressions` ({neutral,happy,sad,angry,surprised,disgusted,fearful} all 0–1), `headPose` ({pitch,yaw,roll}), `blendshapes` (52 ARKit coefficients: browDownLeft, browDownRight, browInnerUp, browOuterUpLeft, browOuterUpRight, cheekPuff, cheekSquintLeft, cheekSquintRight, eyeBlinkLeft, eyeBlinkRight, eyeLookDownLeft, eyeLookDownRight, eyeLookInLeft, eyeLookInRight, eyeLookOutLeft, eyeLookOutRight, eyeLookUpLeft, eyeLookUpRight, eyeSquintLeft, eyeSquintRight, eyeWideLeft, eyeWideRight, jawForward, jawLeft, jawOpen, jawRight, mouthClose, mouthDimpleLeft, mouthDimpleRight, mouthFrownLeft, mouthFrownRight, mouthFunnel, mouthLeft, mouthLowerDownLeft, mouthLowerDownRight, mouthPressLeft, mouthPressRight, mouthPucker, mouthRight, mouthRollLower, mouthRollUpper, mouthShrugLower, mouthShrugUpper, mouthSmileLeft, mouthSmileRight, mouthStretchLeft, mouthStretchRight, mouthUpperUpLeft, mouthUpperUpRight, noseSneerLeft, noseSneerRight, tongueOut — all 0–1).\n\n**`viji.video.hands: HandData[]`**\nEach hand: `id` (number), `handedness` ('left'|'right'), `confidence` (0–1), `bounds` ({x,y,width,height}), `landmarks` ({x,y,z}[], 21 points), `palm` ({x,y,z}), `gestures` ({fist,openPalm,peace,thumbsUp,thumbsDown,pointing,iLoveYou} all 0–1 confidence).\n\n**`viji.video.pose: PoseData | null`**\n`confidence` (0–1), `landmarks` ({x,y,z,visibility}[], 33 points), plus body-part arrays: `face` ({x,y}[]), `torso`, `leftArm`, `rightArm`, `leftLeg`, `rightLeg`.\n\n**`viji.video.segmentation: SegmentationData | null`**\n`mask` (Uint8Array, 0=background 255=person), `width`, `height`.\n\n### Input — Pointer (unified mouse/touch) — `viji.pointer`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `deltaX`, `deltaY` | `number` | Movement since last frame |\n| `isDown` | `boolean` | True if pressed/touching |\n| `wasPressed` | `boolean` | True on press frame |\n| `wasReleased` | `boolean` | True on release frame |\n| `isInCanvas` | `boolean` | True if inside canvas |\n| `type` | `string` | `'mouse'`, `'touch'`, or `'none'` |\n\n### Input — Mouse — `viji.mouse`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `isInCanvas` | `boolean` | Inside canvas bounds |\n| `isPressed` | `boolean` | Any button pressed |\n| `leftButton`, `rightButton`, `middleButton` | `boolean` | Specific buttons |\n| `deltaX`, `deltaY` | `number` | Movement delta |\n| `wheelDelta` | `number` | Scroll wheel delta |\n| `wheelX`, `wheelY` | `number` | Horizontal/vertical scroll |\n| `wasPressed`, `wasReleased`, `wasMoved` | `boolean` | Frame-edge events |\n\n### Input — Keyboard — `viji.keyboard`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isPressed(key)` | `boolean` | True while key is held |\n| `wasPressed(key)` | `boolean` | True on key-down frame |\n| `wasReleased(key)` | `boolean` | True on key-up frame |\n| `activeKeys` | `Set<string>` | Currently held keys |\n| `pressedThisFrame` | `Set<string>` | Keys pressed this frame |\n| `releasedThisFrame` | `Set<string>` | Keys released this frame |\n| `lastKeyPressed` | `string` | Most recent key-down |\n| `lastKeyReleased` | `string` | Most recent key-up |\n| `shift`, `ctrl`, `alt`, `meta` | `boolean` | Modifier states |\n\n### Input — Touch — `viji.touches`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `count` | `number` | Active touch count |\n| `points` | `TouchPoint[]` | All active touches |\n| `started` | `TouchPoint[]` | Touches started this frame |\n| `moved` | `TouchPoint[]` | Touches moved this frame |\n| `ended` | `TouchPoint[]` | Touches ended this frame |\n| `primary` | `TouchPoint\\|null` | First active touch |\n\n**TouchPoint:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force`, `isInCanvas`, `deltaX`, `deltaY`, `velocity` ({x,y}), `isNew`, `isActive`, `isEnding`.\n\n### Device Sensors — `viji.device`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `motion` | `DeviceMotionData\\|null` | Accelerometer/gyroscope |\n| `orientation` | `DeviceOrientationData\\|null` | Device orientation |\n\n**DeviceMotionData:** `acceleration` ({x,y,z} m/s²), `accelerationIncludingGravity`, `rotationRate` ({alpha,beta,gamma} deg/s), `interval` (ms).\n**DeviceOrientationData:** `alpha` (0–360° compass), `beta` (−180–180° tilt), `gamma` (−90–90° tilt), `absolute` (boolean).\n\n### External Devices — `viji.devices`\n\nArray of connected external devices. Each `DeviceState`:\n`id` (string), `name` (string), `motion` (DeviceMotionData|null), `orientation` (DeviceOrientationData|null), `video` (VideoAPI|null — same as viji.video but without CV), `audio` (AudioStreamAPI|null — lightweight analysis only; no beat/BPM/triggers).\n\n### Streams — `viji.videoStreams`\n\n`VideoAPI[]` — additional video sources provided by the host application (used by the compositor for scene mixing). May be empty. Each element has the same shape as `viji.video`.\n\n### Streams — `viji.audioStreams`\n\n`AudioStreamAPI[]` — additional audio sources from the host (e.g. multi-source mixing). May be empty. Lightweight interface: volume, bands, spectral features, `getFrequencyData()`, `getWaveform()` — **not** the full `AudioAPI` (no beat detection, BPM, triggers, or events).\n\n## P5 ↔ VIJI MAPPING\n\n| Standard P5.js | Viji-P5 |\n|---|---|\n| `width` / `height` | `viji.width` / `viji.height` |\n| `mouseX` / `mouseY` | `viji.pointer.x` / `viji.pointer.y` |\n| `mouseIsPressed` | `viji.pointer.isDown` |\n| `mouseButton === LEFT` | `viji.mouse.leftButton` |\n| `keyIsPressed` | `viji.keyboard.isPressed('keyName')` |\n| `key` | `viji.keyboard.lastKeyPressed` |\n| `frameCount` | Use `viji.time` or `viji.deltaTime` accumulator |\n| `frameRate(n)` | Remove — host controls frame rate |\n| `createCanvas(w, h)` | Remove — canvas is provided |\n| `preload()` | Remove — use `viji.image()` or `fetch()` in `setup()` |\n| `loadImage(url)` | `viji.image(null, { label: 'Image' })` |\n| `save()` | Remove — host handles capture |\n\n## BEST PRACTICES\n\n1. NEVER use `viji.time * speed.value` — use a `deltaTime` accumulator instead (see rule 16). Same for nested: never multiply an accumulator by another parameter; give each speed its own accumulator.\n2. Guard audio/video with `isConnected` checks.\n3. Pre-allocate all objects/arrays at top level — never inside `render()`.\n4. For CV, use toggle parameters — never enable by default.\n5. ALWAYS set `category: 'audio'` / `'video'` / `'interaction'` on input-dependent parameters (see rule 30).\n6. Use `p5.drawingContext.drawImage()` for video frames (faster than wrapping).\n7. Use `p5.createGraphics()` for off-screen buffers when needed.\n\n## TEMPLATE\n\n```javascript\n// @renderer p5\n\nconst bgColor = viji.color('#1a1a2e', { label: 'Background' });\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst count = viji.slider(8, { min: 3, max: 30, step: 1, label: 'Count' });\n\nlet angle = 0;\n\nfunction setup(viji, p5) {\n p5.colorMode(p5.HSB, 360, 100, 100);\n}\n\nfunction render(viji, p5) {\n angle += speed.value * viji.deltaTime;\n\n p5.background(bgColor.value);\n\n const cx = viji.width / 2;\n const cy = viji.height / 2;\n const radius = p5.min(viji.width, viji.height) * 0.3;\n const dotSize = p5.min(viji.width, viji.height) * 0.04;\n const n = p5.floor(count.value);\n\n p5.noStroke();\n for (let i = 0; i < n; i++) {\n const a = angle + (i / n) * p5.TWO_PI;\n const x = cx + p5.cos(a) * radius;\n const y = cy + p5.sin(a) * radius;\n p5.fill((i / n) * 360, 80, 90);\n p5.circle(x, y, dotSize);\n }\n}\n```\n\nNow generate a Viji P5 scene based on the artist's description below. Return ONLY the scene code.\nFollow all rules. Use `// @renderer p5` (2D) or `// @renderer p5 webgl` (WEBGL) as the first line. Prefix ALL P5 functions with `p5.`. Use `viji.deltaTime` for animation. Use parameters for anything adjustable. Check `isConnected` before using audio or video.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant (ChatGPT, Claude, etc.).\n3. After the prompt, describe the scene you want.\n4. The AI will return a complete Viji P5 scene.\n\n> [!TIP]\n> For better results, mention which data sources you want (audio, video, camera, mouse) and what kind of controls the user should have. If you have existing P5 sketches to convert, use the [Convert: P5 Sketches](/ai-prompts/convert-p5) prompt instead.\n\n## Related\n\n- [Create Your First Scene](/ai-prompts/create-first-scene) — guided prompt for beginners\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n- [Convert: P5 Sketches](/ai-prompts/convert-p5) — convert existing P5 sketches to Viji\n- [P5 Quick Start](/p5/quickstart) — your first Viji P5 scene\n- [P5 API Reference](/p5/api-reference) — full API reference\n- [Drawing with P5](/p5/drawing) — Viji-specific P5 drawing guide\n- [p5js.org Reference](https://p5js.org/reference/) — full P5.js documentation"
|
|
977
|
+
"markdown": "# Prompt: P5 Scenes\n\nCopy the prompt below and paste it into your AI assistant. Then describe the scene you want. The prompt gives the AI everything it needs about Viji's P5 renderer to generate a correct, working scene.\n\n## The Prompt\n\n````\nYou are generating a Viji P5.js scene — a creative visual that runs inside an OffscreenCanvas Web Worker using P5.js.\nArtists describe what they want; you produce complete, working scene code. Apply every rule below exactly.\n\n## REFERENCE (for AI assistants with web access)\n\nThis prompt is self-contained — all information needed is included below.\nFor the latest API documentation and type definitions:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## ARCHITECTURE\n\n- Scenes run in a **Web Worker** with an **OffscreenCanvas**. There is no DOM.\n- Viji automatically loads **P5.js v1.9.4** when you use `// @renderer p5` or `// @renderer p5 webgl`.\n- The global `viji` object provides canvas, timing, audio, video, CV, input, sensors, and parameters.\n- **Top-level code** runs once (initialization, parameter declarations, state).\n- **`function render(viji, p5) { ... }`** is called every frame. This is where you draw.\n- Optional **`function setup(viji, p5) { ... }`** runs once for configuration (e.g., `p5.colorMode()`).\n- P5 runs in **instance mode** — every P5 function and constant requires the `p5.` prefix.\n\n## RULES\n\n1. ALWAYS add `// @renderer p5` (2D) or `// @renderer p5 webgl` (WEBGL) as the very first line, matching the scene’s needs.\n2. ALWAYS use `render(viji, p5)` — not `draw()`. ALWAYS use `setup(viji, p5)` — not `setup()`.\n3. ALWAYS prefix every P5 function and constant with `p5.`:\n - `background(0)` → `p5.background(0)`\n - `fill(255)` → `p5.fill(255)`\n - `PI` → `p5.PI`, `TWO_PI` → `p5.TWO_PI`, `HSB` → `p5.HSB`\n - `createVector(1, 0)` → `p5.createVector(1, 0)`\n - `map(v, 0, 1, 0, 255)` → `p5.map(v, 0, 1, 0, 255)`\n - `noise(x)` → `p5.noise(x)`, `random()` → `p5.random()`\n This applies to ALL P5 functions and constants without exception.\n4. NEVER call `createCanvas()`. The canvas is created and managed by Viji.\n5. NEVER use `preload()`. Use `viji.image(null, { label: 'Name' })` for images, or `fetch()` in `setup()`.\n6. NEVER use P5 event callbacks: `mousePressed()`, `mouseDragged()`, `mouseReleased()`, `keyPressed()`, `keyReleased()`, `keyTyped()`, `touchStarted()`, `touchMoved()`, `touchEnded()`. Check state in `render()`:\n - `mouseIsPressed` → `viji.pointer.isDown` or `viji.mouse.isPressed`\n - `mouseX` / `mouseY` → `viji.pointer.x` / `viji.pointer.y` or `viji.mouse.x` / `viji.mouse.y`\n - `keyIsPressed` → `viji.keyboard.isPressed('keyName')`\n - For press-edge detection: `viji.pointer.wasPressed` / `viji.pointer.wasReleased`.\n7. NEVER use `loadImage()`, `loadFont()`, `loadJSON()`, `loadModel()`, `loadShader()`. Use `viji.image()` or `fetch()`.\n8. NEVER use `p5.frameRate()`, `p5.save()`, `p5.saveCanvas()`, `p5.saveFrames()`.\n9. NEVER use `createCapture()`, `createVideo()`. Use `viji.video.*` instead.\n10. NEVER use `p5.dom` or `p5.sound` libraries. Use Viji parameters for UI and `viji.audio.*` for audio.\n11. NEVER access `window`, `document`, `Image()`, or `localStorage`. `fetch()` IS available.\n12. ALWAYS declare parameters at the TOP LEVEL, never inside `render()` or `setup()`.\n13. ALWAYS read parameters via `.value`: `size.value`, `color.value`, `toggle.value`.\n14. ALWAYS use `viji.width` and `viji.height` for canvas dimensions. NEVER hardcode pixel sizes.\n15. ALWAYS use `viji.deltaTime` for frame-rate-independent animation:\n ```javascript\n let angle = 0;\n function render(viji, p5) { angle += speed.value * viji.deltaTime; }\n ```\n16. NEVER multiply `viji.time` by a parameter for animation speed — it causes jumps when the parameter changes. ALWAYS use a `deltaTime` accumulator (rule 15). This also applies to nested multiplications — never multiply an accumulator by another parameter; give each speed its own accumulator:\n ```javascript\n // WRONG — jumps: const t = viji.time * speed.value;\n // WRONG — nested: const rot = phase * rotSpeed.value;\n // RIGHT:\n let phase = 0, rotPhase = 0; // top level\n phase += speed.value * viji.deltaTime;\n rotPhase += speed.value * rotSpeed.value * viji.deltaTime;\n ```\n17. NEVER allocate objects, arrays, or strings inside `render()`. Pre-allocate at the top level and reuse.\n18. For image parameters displayed with P5, use `.p5` (not `.value`) with `p5.image()`:\n ```javascript\n const photo = viji.image(null, { label: 'Photo' });\n function render(viji, p5) {\n if (photo.value) p5.image(photo.p5, 0, 0, viji.width, viji.height);\n }\n ```\n19. For video frames: in **2D** (`// @renderer p5`) you may use `p5.image(viji.video.currentFrame, ...)` or `p5.drawingContext.drawImage(...)`. In **WEBGL** (`// @renderer p5 webgl`), use `p5.image(viji.video.currentFrame, ...)` only — `p5.drawingContext` is WebGL, not Canvas 2D.\n ```javascript\n if (viji.video.isConnected && viji.video.currentFrame) {\n p5.image(viji.video.currentFrame, 0, 0, viji.width, viji.height);\n }\n ```\n20. `p5.createGraphics()` works (creates OffscreenCanvas internally). Use for off-screen buffers.\n21. Fonts: `p5.textFont()` only with CSS generic names (`monospace`, `serif`, `sans-serif`). `loadFont()` is NOT available.\n22. `p5.tint()` and `p5.blendMode()` work normally.\n23. **Canvas mode:** Use `// @renderer p5` for a **2D** main canvas. For **WEBGL / 3D**, the first line MUST be `// @renderer p5 webgl`. NEVER call `createCanvas()` or `createCanvas(..., p5.WEBGL)` — Viji creates the canvas in the correct mode.\n24. In **WEBGL** scenes, `p5.drawingContext` is a WebGL context — never use Canvas 2D–only APIs on it. Use P5 3D drawing, `p5.image()` / textures for images and video.\n25. `p5.createGraphics(w, h)` is **2D only**. `createGraphics(w, h, p5.WEBGL)` is NOT supported.\n26. `p5.pixelDensity()` defaults to 1 in the worker. `p5.loadPixels()` and `p5.pixels[]` work (2D scenes; WEBGL pixel readback follows P5.js rules).\n27. ALWAYS check `viji.audio.isConnected` before using audio data.\n28. ALWAYS check `viji.video.isConnected && viji.video.currentFrame` before drawing video.\n29. NEVER enable CV features by default — use toggle parameters for user opt-in.\n30. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio-related, `category: 'video'` for video/camera/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host UI hide irrelevant controls when the input is inactive.\n ```javascript\n const audioReact = viji.toggle(true, { label: 'Audio Reactive', group: 'audio', category: 'audio' });\n const followMouse = viji.toggle(true, { label: 'Follow Mouse', group: 'interaction', category: 'interaction' });\n ```\n31. `viji.useContext()` is NOT available in P5 scenes — the canvas is managed by P5.\n\n## COMPLETE API REFERENCE\n\nAll `viji.*` members are identical to the native renderer (same object, same types).\n\n### Canvas & Timing\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.canvas` | `OffscreenCanvas` | The canvas element (managed by P5) |\n| `viji.width` | `number` | Current canvas width in pixels |\n| `viji.height` | `number` | Current canvas height in pixels |\n| `viji.time` | `number` | Seconds since scene start |\n| `viji.deltaTime` | `number` | Seconds since last frame |\n| `viji.frameCount` | `number` | Total frames rendered |\n| `viji.fps` | `number` | Target frame rate (based on host frame-rate mode) |\n\nNote: `viji.useContext()` is NOT available in P5. The canvas context is managed by P5 internally.\n\n### Parameters\n\nDeclare at top level. Read `.value` inside `render()`. All support `{ label, description?, group?, category? }`.\nCategory values: `'audio'`, `'video'`, `'interaction'`, `'general'`.\n\n```javascript\nviji.slider(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.color(default, { label, group?, category? }) // { value: '#rrggbb' }\nviji.toggle(default, { label, group?, category? }) // { value: boolean }\nviji.select(default, { options: [...], label, group?, category? }) // { value: string|number }\nviji.number(default, { min?, max?, step?, label, group?, category? }) // { value: number }\nviji.text(default, { label, group?, category?, maxLength? }) // { value: string }\nviji.image(null, { label, group?, category? }) // { value: ImageBitmap|null, p5: P5Image }\nviji.button({ label, description?, group?, category? }) // { value: boolean } (true one frame)\n```\n\n- `viji.coordinate(defaultValue, config)` — 2D coordinate, `{ x: number, y: number }`, both -1 to 1. Config: `{ step?, label, description?, group?, category? }`\n\n### Audio — `viji.audio`\n\nALWAYS check `viji.audio.isConnected` first.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether audio source is active |\n| `volume.current` | `number` | RMS volume 0–1 |\n| `volume.peak` | `number` | Peak amplitude 0–1 |\n| `volume.smoothed` | `number` | Smoothed volume (200ms decay) |\n| `bands.low` | `number` | 20–120 Hz energy 0–1 |\n| `bands.lowMid` | `number` | 120–400 Hz energy 0–1 |\n| `bands.mid` | `number` | 400–1600 Hz energy 0–1 |\n| `bands.highMid` | `number` | 1600–6000 Hz energy 0–1 |\n| `bands.high` | `number` | 6000–16000 Hz energy 0–1 |\n| `bands.lowSmoothed` … `bands.highSmoothed` | `number` | Smoothed variants of each band |\n| `beat.kick` | `number` | Kick energy 0–1 |\n| `beat.snare` | `number` | Snare energy 0–1 |\n| `beat.hat` | `number` | Hi-hat energy 0–1 |\n| `beat.any` | `number` | Any beat energy 0–1 |\n| `beat.kickSmoothed` … `beat.anySmoothed` | `number` | Smoothed beat values |\n| `beat.triggers.kick` | `boolean` | True on kick frame |\n| `beat.triggers.snare` | `boolean` | True on snare frame |\n| `beat.triggers.hat` | `boolean` | True on hat frame |\n| `beat.triggers.any` | `boolean` | True on any beat frame |\n| `beat.events` | `Array<{type,time,strength}>` | Recent beat events |\n| `beat.bpm` | `number` | Estimated BPM (60–240) |\n| `beat.confidence` | `number` | BPM tracking confidence 0–1 |\n| `beat.isLocked` | `boolean` | True when BPM is locked |\n| `spectral.brightness` | `number` | Spectral centroid 0–1 |\n| `spectral.flatness` | `number` | Spectral flatness 0–1 |\n| `getFrequencyData()` | `Uint8Array` | Raw FFT bins (0–255) |\n| `getWaveform()` | `Float32Array` | Time-domain waveform (−1 to 1) |\n\n**`viji.audioStreams` & `device.audio`:** Host and external devices may expose additional sources as **`AudioStreamAPI`** — same `isConnected`, `volume`, `bands` (+ smoothed), `spectral`, `getFrequencyData()`, and `getWaveform()` as above, but **no** `beat`, BPM, triggers, or events (lightweight subset).\n\n### Video — `viji.video`\n\nALWAYS check `viji.video.isConnected` first. Check `currentFrame` before drawing.\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isConnected` | `boolean` | Whether video source is active |\n| `currentFrame` | `OffscreenCanvas\\|ImageBitmap\\|null` | Current video frame |\n| `frameWidth` | `number` | Frame width in pixels |\n| `frameHeight` | `number` | Frame height in pixels |\n| `frameRate` | `number` | Video frame rate |\n| `getFrameData()` | `ImageData\\|null` | Pixel data for CPU access |\n\nDraw video with P5: `p5.drawingContext.drawImage(viji.video.currentFrame, 0, 0, viji.width, viji.height)`\n\n### Computer Vision — `viji.video.cv` & `viji.video.faces/hands/pose/segmentation`\n\nEnable features via toggle parameters (NEVER enable by default):\n\n```javascript\nawait viji.video.cv.enableFaceDetection(true/false);\nawait viji.video.cv.enableFaceMesh(true/false);\nawait viji.video.cv.enableEmotionDetection(true/false);\nawait viji.video.cv.enableHandTracking(true/false);\nawait viji.video.cv.enablePoseDetection(true/false);\nawait viji.video.cv.enableBodySegmentation(true/false);\nviji.video.cv.getActiveFeatures(); // CVFeature[]\nviji.video.cv.isProcessing(); // boolean\n```\n\n**`viji.video.faces: FaceData[]`**\nEach face: `id` (number), `bounds` ({x,y,width,height}), `center` ({x,y}), `confidence` (0–1), `landmarks` ({x,y,z?}[]), `expressions` ({neutral,happy,sad,angry,surprised,disgusted,fearful} all 0–1), `headPose` ({pitch,yaw,roll}), `blendshapes` (52 ARKit coefficients: browDownLeft, browDownRight, browInnerUp, browOuterUpLeft, browOuterUpRight, cheekPuff, cheekSquintLeft, cheekSquintRight, eyeBlinkLeft, eyeBlinkRight, eyeLookDownLeft, eyeLookDownRight, eyeLookInLeft, eyeLookInRight, eyeLookOutLeft, eyeLookOutRight, eyeLookUpLeft, eyeLookUpRight, eyeSquintLeft, eyeSquintRight, eyeWideLeft, eyeWideRight, jawForward, jawLeft, jawOpen, jawRight, mouthClose, mouthDimpleLeft, mouthDimpleRight, mouthFrownLeft, mouthFrownRight, mouthFunnel, mouthLeft, mouthLowerDownLeft, mouthLowerDownRight, mouthPressLeft, mouthPressRight, mouthPucker, mouthRight, mouthRollLower, mouthRollUpper, mouthShrugLower, mouthShrugUpper, mouthSmileLeft, mouthSmileRight, mouthStretchLeft, mouthStretchRight, mouthUpperUpLeft, mouthUpperUpRight, noseSneerLeft, noseSneerRight, tongueOut — all 0–1).\n\n**`viji.video.hands: HandData[]`**\nEach hand: `id` (number), `handedness` ('left'|'right'), `confidence` (0–1), `bounds` ({x,y,width,height}), `landmarks` ({x,y,z}[], 21 points), `palm` ({x,y,z}), `gestures` ({fist,openPalm,peace,thumbsUp,thumbsDown,pointing,iLoveYou} all 0–1 confidence).\n\n**`viji.video.pose: PoseData | null`**\n`confidence` (0–1), `landmarks` ({x,y,z,visibility}[], 33 points), plus body-part arrays: `face` ({x,y}[]), `torso`, `leftArm`, `rightArm`, `leftLeg`, `rightLeg`.\n\n**`viji.video.segmentation: SegmentationData | null`**\n`mask` (Uint8Array, 0=background 255=person), `width`, `height`.\n\n### Input — Pointer (unified mouse/touch) — `viji.pointer`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `deltaX`, `deltaY` | `number` | Movement since last frame |\n| `isDown` | `boolean` | True if pressed/touching |\n| `wasPressed` | `boolean` | True on press frame |\n| `wasReleased` | `boolean` | True on release frame |\n| `isInCanvas` | `boolean` | True if inside canvas |\n| `type` | `string` | `'mouse'`, `'touch'`, or `'none'` |\n\n### Input — Mouse — `viji.mouse`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `x`, `y` | `number` | Position in pixels |\n| `isInCanvas` | `boolean` | Inside canvas bounds |\n| `isPressed` | `boolean` | Any button pressed |\n| `leftButton`, `rightButton`, `middleButton` | `boolean` | Specific buttons |\n| `deltaX`, `deltaY` | `number` | Movement delta |\n| `wheelDelta` | `number` | Scroll wheel delta |\n| `wheelX`, `wheelY` | `number` | Horizontal/vertical scroll |\n| `wasPressed`, `wasReleased`, `wasMoved` | `boolean` | Frame-edge events |\n\n### Input — Keyboard — `viji.keyboard`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `isPressed(key)` | `boolean` | True while key is held |\n| `wasPressed(key)` | `boolean` | True on key-down frame |\n| `wasReleased(key)` | `boolean` | True on key-up frame |\n| `activeKeys` | `Set<string>` | Currently held keys |\n| `pressedThisFrame` | `Set<string>` | Keys pressed this frame |\n| `releasedThisFrame` | `Set<string>` | Keys released this frame |\n| `lastKeyPressed` | `string` | Most recent key-down |\n| `lastKeyReleased` | `string` | Most recent key-up |\n| `shift`, `ctrl`, `alt`, `meta` | `boolean` | Modifier states |\n\n### Input — Touch — `viji.touches`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `count` | `number` | Active touch count |\n| `points` | `TouchPoint[]` | All active touches |\n| `started` | `TouchPoint[]` | Touches started this frame |\n| `moved` | `TouchPoint[]` | Touches moved this frame |\n| `ended` | `TouchPoint[]` | Touches ended this frame |\n| `primary` | `TouchPoint\\|null` | First active touch |\n\n**TouchPoint:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force`, `isInCanvas`, `deltaX`, `deltaY`, `velocity` ({x,y}), `isNew`, `isActive`, `isEnding`.\n\n### Device Sensors — `viji.device`\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `motion` | `DeviceMotionData\\|null` | Accelerometer/gyroscope |\n| `orientation` | `DeviceOrientationData\\|null` | Device orientation |\n\n**DeviceMotionData:** `acceleration` ({x,y,z} m/s²), `accelerationIncludingGravity`, `rotationRate` ({alpha,beta,gamma} deg/s), `interval` (ms).\n**DeviceOrientationData:** `alpha` (0–360° compass), `beta` (−180–180° tilt), `gamma` (−90–90° tilt), `absolute` (boolean).\n\n### External Devices — `viji.devices`\n\nArray of connected external devices. Each `DeviceState`:\n`id` (string), `name` (string), `motion` (DeviceMotionData|null), `orientation` (DeviceOrientationData|null), `video` (VideoAPI|null — same as viji.video but without CV), `audio` (AudioStreamAPI|null — lightweight analysis only; no beat/BPM/triggers).\n\n### Streams — `viji.videoStreams`\n\n`VideoAPI[]` — additional video sources provided by the host application (used by the compositor for scene mixing). May be empty. Each element has the same shape as `viji.video`.\n\n### Streams — `viji.audioStreams`\n\n`AudioStreamAPI[]` — additional audio sources from the host (e.g. multi-source mixing). May be empty. Lightweight interface: volume, bands, spectral features, `getFrequencyData()`, `getWaveform()` — **not** the full `AudioAPI` (no beat detection, BPM, triggers, or events).\n\n## P5 ↔ VIJI MAPPING\n\n| Standard P5.js | Viji-P5 |\n|---|---|\n| `width` / `height` | `viji.width` / `viji.height` |\n| `mouseX` / `mouseY` | `viji.pointer.x` / `viji.pointer.y` |\n| `mouseIsPressed` | `viji.pointer.isDown` |\n| `mouseButton === LEFT` | `viji.mouse.leftButton` |\n| `keyIsPressed` | `viji.keyboard.isPressed('keyName')` |\n| `key` | `viji.keyboard.lastKeyPressed` |\n| `frameCount` | Use `viji.time` or `viji.deltaTime` accumulator |\n| `frameRate(n)` | Remove — host controls frame rate |\n| `createCanvas(w, h)` | Remove — canvas is provided |\n| `preload()` | Remove — use `viji.image()` or `fetch()` in `setup()` |\n| `loadImage(url)` | `viji.image(null, { label: 'Image' })` |\n| `save()` | Remove — host handles capture |\n\n## BEST PRACTICES\n\n1. NEVER use `viji.time * speed.value` — use a `deltaTime` accumulator instead (see rule 16). Same for nested: never multiply an accumulator by another parameter; give each speed its own accumulator.\n2. Guard audio/video with `isConnected` checks.\n3. Pre-allocate all objects/arrays at top level — never inside `render()`.\n4. For CV, use toggle parameters — never enable by default.\n5. ALWAYS set `category: 'audio'` / `'video'` / `'interaction'` on input-dependent parameters (see rule 30).\n6. Use `p5.drawingContext.drawImage()` for video frames (faster than wrapping).\n7. Use `p5.createGraphics()` for off-screen buffers when needed.\n\n## TEMPLATE\n\n```javascript\n// @renderer p5\n\nconst bgColor = viji.color('#1a1a2e', { label: 'Background' });\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst count = viji.slider(8, { min: 3, max: 30, step: 1, label: 'Count' });\n\nlet angle = 0;\n\nfunction setup(viji, p5) {\n p5.colorMode(p5.HSB, 360, 100, 100);\n}\n\nfunction render(viji, p5) {\n angle += speed.value * viji.deltaTime;\n\n p5.background(bgColor.value);\n\n const cx = viji.width / 2;\n const cy = viji.height / 2;\n const radius = p5.min(viji.width, viji.height) * 0.3;\n const dotSize = p5.min(viji.width, viji.height) * 0.04;\n const n = p5.floor(count.value);\n\n p5.noStroke();\n for (let i = 0; i < n; i++) {\n const a = angle + (i / n) * p5.TWO_PI;\n const x = cx + p5.cos(a) * radius;\n const y = cy + p5.sin(a) * radius;\n p5.fill((i / n) * 360, 80, 90);\n p5.circle(x, y, dotSize);\n }\n}\n```\n\nNow generate a Viji P5 scene based on the artist's description below. Return ONLY the scene code.\nFollow all rules. Use `// @renderer p5` (2D) or `// @renderer p5 webgl` (WEBGL) as the first line. Prefix ALL P5 functions with `p5.`. Use `viji.deltaTime` for animation. Use parameters for anything adjustable. Check `isConnected` before using audio or video.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant (ChatGPT, Claude, etc.).\n3. After the prompt, describe the scene you want.\n4. The AI will return a complete Viji P5 scene.\n\n> [!TIP]\n> For better results, mention which data sources you want (audio, video, camera, mouse) and what kind of controls the user should have. If you have existing P5 sketches to convert, use the [Convert: P5 Sketches](/ai-prompts/convert-p5) prompt instead.\n\n## Related\n\n- [Create Your First Scene](/ai-prompts/create-first-scene) — guided prompt for beginners\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n- [Convert: P5 Sketches](/ai-prompts/convert-p5) — convert existing P5 sketches to Viji\n- [P5 Quick Start](/p5/quickstart) — your first Viji P5 scene\n- [P5 API Reference](/p5/api-reference) — full API reference\n- [Drawing with P5](/p5/drawing) — Viji-specific P5 drawing guide\n- [p5js.org Reference](https://p5js.org/reference/) — full P5.js documentation"
|
|
963
978
|
}
|
|
964
979
|
]
|
|
965
980
|
},
|
|
@@ -970,7 +985,7 @@ export const docsApi = {
|
|
|
970
985
|
"content": [
|
|
971
986
|
{
|
|
972
987
|
"type": "text",
|
|
973
|
-
"markdown": "# Prompt: Shader Scenes\n\nCopy the prompt below and paste it into your AI assistant. Then describe the shader effect you want. The prompt gives the AI everything it needs about Viji's shader renderer to generate a correct, working scene.\n\n## The Prompt\n\n````\nYou are generating a Viji GLSL shader scene — a fragment shader that runs on a fullscreen quad inside a Web Worker.\nArtists describe what they want; you produce complete, working GLSL code. Apply every rule below exactly.\n\n## REFERENCE (for AI assistants with web access)\n\nThis prompt is self-contained — all information needed is included below.\nFor the latest API documentation and type definitions:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- Shader uniforms reference: https://unpkg.com/@viji-dev/core/dist/shader-uniforms.js\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## ARCHITECTURE\n\n- Viji renders a **fullscreen quad**. Your shader defines the color of every pixel.\n- Viji **auto-injects** `precision mediump float;` and ALL uniform declarations — both built-in uniforms and parameter uniforms from `@viji-*` directives.\n- You write only helper functions and `void main() { ... }`.\n- **GLSL ES 1.00** by default. Add `#version 300 es` as the very first line for ES 3.00.\n- ES 3.00 requires `out vec4 fragColor;` (before `main`) and `fragColor = ...` instead of `gl_FragColor`.\n- ES 3.00 uses `texture()` instead of `texture2D()`.\n- If the shader uses `fwidth`, Viji auto-injects `#extension GL_OES_standard_derivatives : enable`.\n\n## RULES\n\n1. ALWAYS add `// @renderer shader` as the first line (or after `#version 300 es` if using ES 3.00).\n2. NEVER declare `precision mediump float;` or `precision highp float;` — Viji auto-injects precision.\n3. NEVER redeclare built-in uniforms (`u_time`, `u_resolution`, `u_mouse`, etc.) — they are auto-injected.\n4. NEVER redeclare parameter uniforms — they are auto-generated from `@viji-*` directives.\n5. NEVER use the `u_` prefix for your own parameter names — it is reserved for built-in uniforms. Name parameters descriptively: `speed`, `colorMix`, `intensity`.\n6. `@viji-*` parameter directives ONLY work with `//` comments. NEVER use `/* */` for directives.\n7. ALWAYS use `@viji-accumulator` instead of `u_time * speed` for parameter-driven animation — this prevents jumps when sliders change:\n ```glsl\n // @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n // @viji-accumulator:phase rate:speed\n float wave = sin(phase); // smooth, no jumps\n ```\n The same applies to **nested** multiplications: never multiply an accumulator by another parameter inside the shader. If you need two independent speeds, declare two accumulators:\n ```glsl\n // @viji-accumulator:phase rate:speed\n // @viji-accumulator:rotPhase rate:rotSpeed\n ```\n8. For `backbuffer` (previous frame), just reference it in code — Viji auto-detects and enables it.\n9. Remove any `#ifdef GL_ES` / `precision` blocks — Viji handles this.\n10. ALWAYS set `category:` on input-dependent `@viji-*` directives: `category:audio` for audio controls, `category:video` for video controls, `category:interaction` for mouse/touch controls. This lets the host UI hide irrelevant controls when that input is inactive:\n ```glsl\n // @viji-toggle:audioReactive label:\"Audio Reactive\" default:true group:audio category:audio\n // @viji-toggle:showVideo label:\"Show Video\" default:true group:video category:video\n // @viji-slider:mouseInfluence label:\"Mouse Influence\" default:0.3 group:interaction category:interaction\n ```\n\n## COMPLETE UNIFORM REFERENCE\n\nAll uniforms below are always available — do NOT declare them.\n\n### Core\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_resolution` | `vec2` | Canvas width and height in pixels |\n| `u_time` | `float` | Elapsed seconds since scene start |\n| `u_deltaTime` | `float` | Seconds since last frame |\n| `u_frame` | `int` | Current frame number |\n| `u_fps` | `float` | Target frame rate (based on host frame-rate mode) |\n\n### Mouse\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_mouse` | `vec2` | Mouse position in pixels (WebGL coords: bottom-left origin) |\n| `u_mouseInCanvas` | `bool` | True if mouse is inside canvas |\n| `u_mousePressed` | `bool` | True if any mouse button is pressed |\n| `u_mouseLeft` | `bool` | True if left button is pressed |\n| `u_mouseRight` | `bool` | True if right button is pressed |\n| `u_mouseMiddle` | `bool` | True if middle button is pressed |\n| `u_mouseDelta` | `vec2` | Mouse movement delta per frame |\n| `u_mouseWheel` | `float` | Mouse wheel scroll delta |\n| `u_mouseWasPressed` | `bool` | True on the frame a button was pressed |\n| `u_mouseWasReleased` | `bool` | True on the frame a button was released |\n\n### Keyboard\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_keySpace` | `bool` | Spacebar |\n| `u_keyShift` | `bool` | Shift key |\n| `u_keyCtrl` | `bool` | Ctrl/Cmd key |\n| `u_keyAlt` | `bool` | Alt/Option key |\n| `u_keyW`, `u_keyA`, `u_keyS`, `u_keyD` | `bool` | WASD keys |\n| `u_keyUp`, `u_keyDown`, `u_keyLeft`, `u_keyRight` | `bool` | Arrow keys |\n| `u_keyboard` | `sampler2D` | Full keyboard state texture (256×3, LUMINANCE). Row 0: held, Row 1: pressed this frame, Row 2: toggle. Access: `texelFetch(u_keyboard, ivec2(keyCode, row), 0).r` |\n\n### Touch\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_touchCount` | `int` | Number of active touches (0–5) |\n| `u_touch0` – `u_touch4` | `vec2` | Touch point positions in pixels |\n\n### Pointer (unified mouse/touch)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_pointer` | `vec2` | Primary input position in pixels (WebGL coords) |\n| `u_pointerDelta` | `vec2` | Primary input movement delta |\n| `u_pointerDown` | `bool` | True if primary input is active |\n| `u_pointerWasPressed` | `bool` | True on frame input became active |\n| `u_pointerWasReleased` | `bool` | True on frame input was released |\n| `u_pointerInCanvas` | `bool` | True if inside canvas |\n\n### Audio — Scalars\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioVolume` | `float` | RMS volume 0–1 |\n| `u_audioPeak` | `float` | Peak amplitude 0–1 |\n| `u_audioVolumeSmoothed` | `float` | Smoothed volume (200ms decay) |\n| `u_audioLow` | `float` | Low band 20–120 Hz |\n| `u_audioLowMid` | `float` | Low-mid 120–400 Hz |\n| `u_audioMid` | `float` | Mid 400–1600 Hz |\n| `u_audioHighMid` | `float` | High-mid 1600–6000 Hz |\n| `u_audioHigh` | `float` | High 6000–16000 Hz |\n| `u_audioLowSmoothed` – `u_audioHighSmoothed` | `float` | Smoothed band variants |\n| `u_audioKick` | `float` | Kick energy 0–1 |\n| `u_audioSnare` | `float` | Snare energy 0–1 |\n| `u_audioHat` | `float` | Hi-hat energy 0–1 |\n| `u_audioAny` | `float` | Any beat energy 0–1 |\n| `u_audioKickSmoothed` – `u_audioAnySmoothed` | `float` | Smoothed beat values |\n| `u_audioKickTrigger` | `bool` | True on kick beat frame |\n| `u_audioSnareTrigger` | `bool` | True on snare beat frame |\n| `u_audioHatTrigger` | `bool` | True on hat beat frame |\n| `u_audioAnyTrigger` | `bool` | True on any beat frame |\n| `u_audioBPM` | `float` | Estimated BPM (60–240) |\n| `u_audioConfidence` | `float` | Beat tracking confidence 0–1 |\n| `u_audioIsLocked` | `bool` | True when BPM is locked |\n| `u_audioBrightness` | `float` | Spectral brightness 0–1 |\n| `u_audioFlatness` | `float` | Spectral flatness 0–1 |\n\n### Audio — Textures\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioFFT` | `sampler2D` | FFT frequency spectrum (1024 bins, 0–255) |\n| `u_audioWaveform` | `sampler2D` | Time-domain waveform (−1 to 1) |\n\n> [!NOTE]\n> **`u_audioFFT` / `u_audioWaveform` apply only to the main audio source.** Additional streams (host `audioStreams` and device audio) use **`u_audioStream{i}*`** float/bool uniforms only — see **Streams (Compositor)** → **Audio streams** in this reference.\n\n### Video\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_video` | `sampler2D` | Current video frame texture |\n| `u_videoResolution` | `vec2` | Video frame size in pixels |\n| `u_videoFrameRate` | `float` | Video frame rate |\n| `u_videoConnected` | `bool` | True if video source is active |\n\n### CV — Face Detection\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_faceCount` | `int` | Number of detected faces (0–1) |\n| `u_face0Bounds` | `vec4` | Bounding box (x, y, width, height) normalized 0–1 |\n| `u_face0Center` | `vec2` | Face center (x, y) normalized 0–1 |\n| `u_face0HeadPose` | `vec3` | Head rotation (pitch, yaw, roll) in degrees |\n| `u_face0Confidence` | `float` | Detection confidence 0–1 |\n| `u_face0Neutral` – `u_face0Fearful` | `float` | 7 expression scores (neutral, happy, sad, angry, surprised, disgusted, fearful) |\n\n**52 Blendshape uniforms** (all `float`, 0–1, ARKit names prefixed with `u_face0`):\n`u_face0BrowDownLeft`, `u_face0BrowDownRight`, `u_face0BrowInnerUp`, `u_face0BrowOuterUpLeft`, `u_face0BrowOuterUpRight`, `u_face0CheekPuff`, `u_face0CheekSquintLeft`, `u_face0CheekSquintRight`, `u_face0EyeBlinkLeft`, `u_face0EyeBlinkRight`, `u_face0EyeLookDownLeft`, `u_face0EyeLookDownRight`, `u_face0EyeLookInLeft`, `u_face0EyeLookInRight`, `u_face0EyeLookOutLeft`, `u_face0EyeLookOutRight`, `u_face0EyeLookUpLeft`, `u_face0EyeLookUpRight`, `u_face0EyeSquintLeft`, `u_face0EyeSquintRight`, `u_face0EyeWideLeft`, `u_face0EyeWideRight`, `u_face0JawForward`, `u_face0JawLeft`, `u_face0JawOpen`, `u_face0JawRight`, `u_face0MouthClose`, `u_face0MouthDimpleLeft`, `u_face0MouthDimpleRight`, `u_face0MouthFrownLeft`, `u_face0MouthFrownRight`, `u_face0MouthFunnel`, `u_face0MouthLeft`, `u_face0MouthLowerDownLeft`, `u_face0MouthLowerDownRight`, `u_face0MouthPressLeft`, `u_face0MouthPressRight`, `u_face0MouthPucker`, `u_face0MouthRight`, `u_face0MouthRollLower`, `u_face0MouthRollUpper`, `u_face0MouthShrugLower`, `u_face0MouthShrugUpper`, `u_face0MouthSmileLeft`, `u_face0MouthSmileRight`, `u_face0MouthStretchLeft`, `u_face0MouthStretchRight`, `u_face0MouthUpperUpLeft`, `u_face0MouthUpperUpRight`, `u_face0NoseSneerLeft`, `u_face0NoseSneerRight`, `u_face0TongueOut`.\n\n### CV — Hands\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_handCount` | `int` | Number of detected hands (0–2) |\n| `u_leftHandPalm`, `u_rightHandPalm` | `vec3` | Palm position (x, y, z) |\n| `u_leftHandConfidence`, `u_rightHandConfidence` | `float` | Detection confidence 0–1 |\n| `u_leftHandBounds`, `u_rightHandBounds` | `vec4` | Bounding box normalized 0–1 |\n| `u_leftHandFist` – `u_leftHandILoveYou` | `float` | 7 left-hand gesture scores (fist, open, peace, thumbsUp, thumbsDown, pointing, iLoveYou) |\n| `u_rightHandFist` – `u_rightHandILoveYou` | `float` | 7 right-hand gesture scores |\n\n### CV — Pose\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_poseDetected` | `bool` | True if a pose is detected |\n| `u_poseConfidence` | `float` | Detection confidence 0–1 |\n| `u_nosePosition` | `vec2` | Nose landmark (normalized 0–1) |\n| `u_leftShoulderPosition`, `u_rightShoulderPosition` | `vec2` | Shoulder positions |\n| `u_leftElbowPosition`, `u_rightElbowPosition` | `vec2` | Elbow positions |\n| `u_leftWristPosition`, `u_rightWristPosition` | `vec2` | Wrist positions |\n| `u_leftHipPosition`, `u_rightHipPosition` | `vec2` | Hip positions |\n| `u_leftKneePosition`, `u_rightKneePosition` | `vec2` | Knee positions |\n| `u_leftAnklePosition`, `u_rightAnklePosition` | `vec2` | Ankle positions |\n\n### CV — Body Segmentation\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_segmentationMask` | `sampler2D` | Segmentation mask (0=background, 1=person) |\n| `u_segmentationRes` | `vec2` | Mask resolution in pixels |\n\n### Device Sensors\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_deviceAcceleration` | `vec3` | Acceleration without gravity (m/s²) |\n| `u_deviceAccelerationGravity` | `vec3` | Acceleration with gravity (m/s²) |\n| `u_deviceRotationRate` | `vec3` | Rotation rate (deg/s) |\n| `u_deviceOrientation` | `vec3` | Orientation (alpha, beta, gamma) degrees |\n| `u_deviceOrientationAbsolute` | `bool` | True if using magnetometer |\n\n### External Devices\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_deviceCount` | `int` | Number of device video sources (0–8) |\n| `u_externalDeviceCount` | `int` | Number of external devices (0–8) |\n| `u_device0` – `u_device7` | `sampler2D` | Device camera textures |\n| `u_device0Resolution` – `u_device7Resolution` | `vec2` | Device camera resolutions |\n| `u_device0Connected` – `u_device7Connected` | `bool` | Device connection status |\n| `u_device0Acceleration` – `u_device7Acceleration` | `vec3` | Per-device acceleration |\n| `u_device0AccelerationGravity` – `u_device7AccelerationGravity` | `vec3` | Per-device acceleration w/ gravity |\n| `u_device0RotationRate` – `u_device7RotationRate` | `vec3` | Per-device rotation rate |\n| `u_device0Orientation` – `u_device7Orientation` | `vec3` | Per-device orientation |\n\n> [!NOTE]\n> **Device audio** (when an external device provides an audio source) is exposed as **`u_audioStream{i}*`** scalar uniforms — same per-slot names as compositor audio streams (`Connected`, `Volume`, band energies, `Brightness`, `Flatness` for `i` = 0–7). There are **no** per-device or per-stream FFT/waveform textures; only the **main** audio source gets `u_audioFFT` and `u_audioWaveform`.\n\n### Streams (Compositor)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_videoStreamCount` | `int` | Number of active streams (0–8) |\n| `u_videoStream0` – `u_videoStream7` | `sampler2D` | Stream textures |\n| `u_videoStream0Resolution` – `u_videoStream7Resolution` | `vec2` | Stream resolutions |\n| `u_videoStream0Connected` – `u_videoStream7Connected` | `bool` | Stream connection status |\n\nStreams are host-provided video sources used internally by the compositor.\n\n#### Audio streams (additional sources)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioStreamCount` | `int` | Number of active additional audio streams (0–8) |\n| `u_audioStream0Connected` – `u_audioStream7Connected` | `bool` | Whether that slot is actively providing audio |\n| `u_audioStream{i}Volume` | `float` | RMS-style volume 0–1 |\n| `u_audioStream{i}Low` – `u_audioStream{i}High` | `float` | Band energies 0–1 (`Low`, `LowMid`, `Mid`, `HighMid`, `High`) |\n| `u_audioStream{i}Brightness`, `u_audioStream{i}Flatness` | `float` | Spectral features 0–1 |\n\n(`i` = 0…7.) **Lightweight scalars only** — **no** `u_audioFFT` / `u_audioWaveform` per stream. Beat/BPM/trigger uniforms remain **main audio only** (`u_audioKick`, `u_audioBPM`, etc.).\n\n### Backbuffer\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `backbuffer` | `sampler2D` | Previous frame (auto-enabled when referenced) |\n\nNo `u_` prefix. RGBA 8-bit, LINEAR filtering, CLAMP_TO_EDGE wrapping. First frame samples as black. Content clears on canvas resize.\nSample: `texture2D(backbuffer, uv)` (ES 1.00) or `texture(backbuffer, uv)` (ES 3.00).\n\n## PARAMETER DIRECTIVES\n\nDeclare with `// @viji-TYPE:uniformName key:value ...` syntax. They become uniforms automatically.\n\n```glsl\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0 step:0.1\n// → uniform float speed;\n\n// @viji-color:tint label:\"Tint\" default:#ff6600\n// → uniform vec3 tint; (RGB 0–1)\n\n// @viji-toggle:invert label:\"Invert\" default:false\n// → uniform bool invert;\n\n// @viji-select:mode label:\"Mode\" default:0 options:[\"Solid\",\"Gradient\",\"Noise\"]\n// → uniform int mode; (0-based index)\n\n// @viji-number:count label:\"Count\" default:10.0 min:1.0 max:100.0 step:1.0\n// → uniform float count;\n\n// @viji-image:tex label:\"Texture\"\n// → uniform sampler2D tex;\n\n// @viji-button:reset label:\"Reset\"\n// → uniform bool reset; (true for one frame on press)\n\n// @viji-accumulator:phase rate:speed\n// → uniform float phase; (CPU-side: += speed × deltaTime each frame)\n```\n\nAll directives support `group:\"GroupName\"` and `category:\"audio|video|interaction|general\"`.\n\n## TEMPLATE\n\n```glsl\n// @renderer shader\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n// @viji-color:baseColor label:\"Color\" default:#ff6600\n// @viji-accumulator:phase rate:speed\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n\n float wave = sin(uv.x * 10.0 + phase) * 0.5 + 0.5;\n float pulse = 1.0 + u_audioLow * 0.5;\n vec3 color = baseColor * wave * pulse;\n\n gl_FragColor = vec4(color, 1.0);\n}\n```\n\nNow generate a Viji shader scene based on the artist's description below. Return ONLY the GLSL code.\nFollow all rules. Use `// @renderer shader` as the first line. Do NOT declare precision or uniforms. Use `@viji-accumulator` for parameter-driven animation. Use `@viji-slider/color/toggle` for artist controls.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant (ChatGPT, Claude, etc.).\n3. After the prompt, describe the shader effect you want.\n4. The AI will return a complete Viji shader scene.\n\n> [!TIP]\n> For better results, describe the visual effect you want (patterns, colors, motion), mention data sources (audio, video, mouse), and what controls the user should have. If you have existing Shadertoy shaders to convert, use the [Convert: Shadertoy](/ai-prompts/convert-shadertoy) prompt instead.\n\n## Related\n\n- [Create Your First Scene](/ai-prompts/create-first-scene) — guided prompt for beginners\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n- [Convert: Shadertoy](/ai-prompts/convert-shadertoy) — convert existing Shadertoy shaders to Viji\n- [Shader Quick Start](/shader/quickstart) — your first Viji shader\n- [Shader API Reference](/shader/api-reference) — full uniform reference\n- [Backbuffer & Feedback](/shader/backbuffer) — previous-frame feedback effects\n- [Shadertoy Compatibility](/shader/shadertoy) — compatibility layer for Shadertoy code"
|
|
988
|
+
"markdown": "# Prompt: Shader Scenes\n\nCopy the prompt below and paste it into your AI assistant. Then describe the shader effect you want. The prompt gives the AI everything it needs about Viji's shader renderer to generate a correct, working scene.\n\n## The Prompt\n\n````\nYou are generating a Viji GLSL shader scene — a fragment shader that runs on a fullscreen quad inside a Web Worker.\nArtists describe what they want; you produce complete, working GLSL code. Apply every rule below exactly.\n\n## REFERENCE (for AI assistants with web access)\n\nThis prompt is self-contained — all information needed is included below.\nFor the latest API documentation and type definitions:\n- Complete docs (all pages + examples): https://unpkg.com/@viji-dev/core/dist/docs-api.js\n- TypeScript API types: https://unpkg.com/@viji-dev/core/dist/artist-global.d.ts\n- Shader uniforms reference: https://unpkg.com/@viji-dev/core/dist/shader-uniforms.js\n- NPM package: https://www.npmjs.com/package/@viji-dev/core\n\n## ARCHITECTURE\n\n- Viji renders a **fullscreen quad**. Your shader defines the color of every pixel.\n- Viji **auto-injects** `precision mediump float;` and ALL uniform declarations — both built-in uniforms and parameter uniforms from `@viji-*` directives.\n- You write only helper functions and `void main() { ... }`.\n- **GLSL ES 1.00** by default. Add `#version 300 es` as the very first line for ES 3.00.\n- ES 3.00 requires `out vec4 fragColor;` (before `main`) and `fragColor = ...` instead of `gl_FragColor`.\n- ES 3.00 uses `texture()` instead of `texture2D()`.\n- If the shader uses `fwidth`, Viji auto-injects `#extension GL_OES_standard_derivatives : enable`.\n\n## RULES\n\n1. ALWAYS add `// @renderer shader` as the first line (or after `#version 300 es` if using ES 3.00).\n2. NEVER declare `precision mediump float;` or `precision highp float;` — Viji auto-injects precision.\n3. NEVER redeclare built-in uniforms (`u_time`, `u_resolution`, `u_mouse`, etc.) — they are auto-injected.\n4. NEVER redeclare parameter uniforms — they are auto-generated from `@viji-*` directives.\n5. NEVER use the `u_` prefix for your own parameter names — it is reserved for built-in uniforms. Name parameters descriptively: `speed`, `colorMix`, `intensity`.\n6. `@viji-*` parameter directives ONLY work with `//` comments. NEVER use `/* */` for directives.\n7. ALWAYS use `@viji-accumulator` instead of `u_time * speed` for parameter-driven animation — this prevents jumps when sliders change:\n ```glsl\n // @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n // @viji-accumulator:phase rate:speed\n float wave = sin(phase); // smooth, no jumps\n ```\n The same applies to **nested** multiplications: never multiply an accumulator by another parameter inside the shader. If you need two independent speeds, declare two accumulators:\n ```glsl\n // @viji-accumulator:phase rate:speed\n // @viji-accumulator:rotPhase rate:rotSpeed\n ```\n8. For `backbuffer` (previous frame), just reference it in code — Viji auto-detects and enables it.\n9. Remove any `#ifdef GL_ES` / `precision` blocks — Viji handles this.\n10. ALWAYS set `category:` on input-dependent `@viji-*` directives: `category:audio` for audio controls, `category:video` for video controls, `category:interaction` for mouse/touch controls. This lets the host UI hide irrelevant controls when that input is inactive:\n ```glsl\n // @viji-toggle:audioReactive label:\"Audio Reactive\" default:true group:audio category:audio\n // @viji-toggle:showVideo label:\"Show Video\" default:true group:video category:video\n // @viji-slider:mouseInfluence label:\"Mouse Influence\" default:0.3 group:interaction category:interaction\n ```\n\n## COMPLETE UNIFORM REFERENCE\n\nAll uniforms below are always available — do NOT declare them.\n\n### Core\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_resolution` | `vec2` | Canvas width and height in pixels |\n| `u_time` | `float` | Elapsed seconds since scene start |\n| `u_deltaTime` | `float` | Seconds since last frame |\n| `u_frame` | `int` | Current frame number |\n| `u_fps` | `float` | Target frame rate (based on host frame-rate mode) |\n\n### Mouse\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_mouse` | `vec2` | Mouse position in pixels (WebGL coords: bottom-left origin) |\n| `u_mouseInCanvas` | `bool` | True if mouse is inside canvas |\n| `u_mousePressed` | `bool` | True if any mouse button is pressed |\n| `u_mouseLeft` | `bool` | True if left button is pressed |\n| `u_mouseRight` | `bool` | True if right button is pressed |\n| `u_mouseMiddle` | `bool` | True if middle button is pressed |\n| `u_mouseDelta` | `vec2` | Mouse movement delta per frame |\n| `u_mouseWheel` | `float` | Mouse wheel scroll delta |\n| `u_mouseWasPressed` | `bool` | True on the frame a button was pressed |\n| `u_mouseWasReleased` | `bool` | True on the frame a button was released |\n\n### Keyboard\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_keySpace` | `bool` | Spacebar |\n| `u_keyShift` | `bool` | Shift key |\n| `u_keyCtrl` | `bool` | Ctrl/Cmd key |\n| `u_keyAlt` | `bool` | Alt/Option key |\n| `u_keyW`, `u_keyA`, `u_keyS`, `u_keyD` | `bool` | WASD keys |\n| `u_keyUp`, `u_keyDown`, `u_keyLeft`, `u_keyRight` | `bool` | Arrow keys |\n| `u_keyboard` | `sampler2D` | Full keyboard state texture (256×3, LUMINANCE). Row 0: held, Row 1: pressed this frame, Row 2: toggle. Access: `texelFetch(u_keyboard, ivec2(keyCode, row), 0).r` |\n\n### Touch\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_touchCount` | `int` | Number of active touches (0–5) |\n| `u_touch0` – `u_touch4` | `vec2` | Touch point positions in pixels |\n\n### Pointer (unified mouse/touch)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_pointer` | `vec2` | Primary input position in pixels (WebGL coords) |\n| `u_pointerDelta` | `vec2` | Primary input movement delta |\n| `u_pointerDown` | `bool` | True if primary input is active |\n| `u_pointerWasPressed` | `bool` | True on frame input became active |\n| `u_pointerWasReleased` | `bool` | True on frame input was released |\n| `u_pointerInCanvas` | `bool` | True if inside canvas |\n\n### Audio — Scalars\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioVolume` | `float` | RMS volume 0–1 |\n| `u_audioPeak` | `float` | Peak amplitude 0–1 |\n| `u_audioVolumeSmoothed` | `float` | Smoothed volume (200ms decay) |\n| `u_audioLow` | `float` | Low band 20–120 Hz |\n| `u_audioLowMid` | `float` | Low-mid 120–400 Hz |\n| `u_audioMid` | `float` | Mid 400–1600 Hz |\n| `u_audioHighMid` | `float` | High-mid 1600–6000 Hz |\n| `u_audioHigh` | `float` | High 6000–16000 Hz |\n| `u_audioLowSmoothed` – `u_audioHighSmoothed` | `float` | Smoothed band variants |\n| `u_audioKick` | `float` | Kick energy 0–1 |\n| `u_audioSnare` | `float` | Snare energy 0–1 |\n| `u_audioHat` | `float` | Hi-hat energy 0–1 |\n| `u_audioAny` | `float` | Any beat energy 0–1 |\n| `u_audioKickSmoothed` – `u_audioAnySmoothed` | `float` | Smoothed beat values |\n| `u_audioKickTrigger` | `bool` | True on kick beat frame |\n| `u_audioSnareTrigger` | `bool` | True on snare beat frame |\n| `u_audioHatTrigger` | `bool` | True on hat beat frame |\n| `u_audioAnyTrigger` | `bool` | True on any beat frame |\n| `u_audioBPM` | `float` | Estimated BPM (60–240) |\n| `u_audioConfidence` | `float` | Beat tracking confidence 0–1 |\n| `u_audioIsLocked` | `bool` | True when BPM is locked |\n| `u_audioBrightness` | `float` | Spectral brightness 0–1 |\n| `u_audioFlatness` | `float` | Spectral flatness 0–1 |\n\n### Audio — Textures\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioFFT` | `sampler2D` | FFT frequency spectrum (1024 bins, 0–255) |\n| `u_audioWaveform` | `sampler2D` | Time-domain waveform (−1 to 1) |\n\n> [!NOTE]\n> **`u_audioFFT` / `u_audioWaveform` apply only to the main audio source.** Additional streams (host `audioStreams` and device audio) use **`u_audioStream{i}*`** float/bool uniforms only — see **Streams (Compositor)** → **Audio streams** in this reference.\n\n### Video\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_video` | `sampler2D` | Current video frame texture |\n| `u_videoResolution` | `vec2` | Video frame size in pixels |\n| `u_videoFrameRate` | `float` | Video frame rate |\n| `u_videoConnected` | `bool` | True if video source is active |\n\n### CV — Face Detection\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_faceCount` | `int` | Number of detected faces (0–1) |\n| `u_face0Bounds` | `vec4` | Bounding box (x, y, width, height) normalized 0–1 |\n| `u_face0Center` | `vec2` | Face center (x, y) normalized 0–1 |\n| `u_face0HeadPose` | `vec3` | Head rotation (pitch, yaw, roll) in degrees |\n| `u_face0Confidence` | `float` | Detection confidence 0–1 |\n| `u_face0Neutral` – `u_face0Fearful` | `float` | 7 expression scores (neutral, happy, sad, angry, surprised, disgusted, fearful) |\n\n**52 Blendshape uniforms** (all `float`, 0–1, ARKit names prefixed with `u_face0`):\n`u_face0BrowDownLeft`, `u_face0BrowDownRight`, `u_face0BrowInnerUp`, `u_face0BrowOuterUpLeft`, `u_face0BrowOuterUpRight`, `u_face0CheekPuff`, `u_face0CheekSquintLeft`, `u_face0CheekSquintRight`, `u_face0EyeBlinkLeft`, `u_face0EyeBlinkRight`, `u_face0EyeLookDownLeft`, `u_face0EyeLookDownRight`, `u_face0EyeLookInLeft`, `u_face0EyeLookInRight`, `u_face0EyeLookOutLeft`, `u_face0EyeLookOutRight`, `u_face0EyeLookUpLeft`, `u_face0EyeLookUpRight`, `u_face0EyeSquintLeft`, `u_face0EyeSquintRight`, `u_face0EyeWideLeft`, `u_face0EyeWideRight`, `u_face0JawForward`, `u_face0JawLeft`, `u_face0JawOpen`, `u_face0JawRight`, `u_face0MouthClose`, `u_face0MouthDimpleLeft`, `u_face0MouthDimpleRight`, `u_face0MouthFrownLeft`, `u_face0MouthFrownRight`, `u_face0MouthFunnel`, `u_face0MouthLeft`, `u_face0MouthLowerDownLeft`, `u_face0MouthLowerDownRight`, `u_face0MouthPressLeft`, `u_face0MouthPressRight`, `u_face0MouthPucker`, `u_face0MouthRight`, `u_face0MouthRollLower`, `u_face0MouthRollUpper`, `u_face0MouthShrugLower`, `u_face0MouthShrugUpper`, `u_face0MouthSmileLeft`, `u_face0MouthSmileRight`, `u_face0MouthStretchLeft`, `u_face0MouthStretchRight`, `u_face0MouthUpperUpLeft`, `u_face0MouthUpperUpRight`, `u_face0NoseSneerLeft`, `u_face0NoseSneerRight`, `u_face0TongueOut`.\n\n### CV — Hands\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_handCount` | `int` | Number of detected hands (0–2) |\n| `u_leftHandPalm`, `u_rightHandPalm` | `vec3` | Palm position (x, y, z) |\n| `u_leftHandConfidence`, `u_rightHandConfidence` | `float` | Detection confidence 0–1 |\n| `u_leftHandBounds`, `u_rightHandBounds` | `vec4` | Bounding box normalized 0–1 |\n| `u_leftHandFist` – `u_leftHandILoveYou` | `float` | 7 left-hand gesture scores (fist, open, peace, thumbsUp, thumbsDown, pointing, iLoveYou) |\n| `u_rightHandFist` – `u_rightHandILoveYou` | `float` | 7 right-hand gesture scores |\n\n### CV — Pose\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_poseDetected` | `bool` | True if a pose is detected |\n| `u_poseConfidence` | `float` | Detection confidence 0–1 |\n| `u_nosePosition` | `vec2` | Nose landmark (normalized 0–1) |\n| `u_leftShoulderPosition`, `u_rightShoulderPosition` | `vec2` | Shoulder positions |\n| `u_leftElbowPosition`, `u_rightElbowPosition` | `vec2` | Elbow positions |\n| `u_leftWristPosition`, `u_rightWristPosition` | `vec2` | Wrist positions |\n| `u_leftHipPosition`, `u_rightHipPosition` | `vec2` | Hip positions |\n| `u_leftKneePosition`, `u_rightKneePosition` | `vec2` | Knee positions |\n| `u_leftAnklePosition`, `u_rightAnklePosition` | `vec2` | Ankle positions |\n\n### CV — Body Segmentation\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_segmentationMask` | `sampler2D` | Segmentation mask (0=background, 1=person) |\n| `u_segmentationRes` | `vec2` | Mask resolution in pixels |\n\n### Device Sensors\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_deviceAcceleration` | `vec3` | Acceleration without gravity (m/s²) |\n| `u_deviceAccelerationGravity` | `vec3` | Acceleration with gravity (m/s²) |\n| `u_deviceRotationRate` | `vec3` | Rotation rate (deg/s) |\n| `u_deviceOrientation` | `vec3` | Orientation (alpha, beta, gamma) degrees |\n| `u_deviceOrientationAbsolute` | `bool` | True if using magnetometer |\n\n### External Devices\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_deviceCount` | `int` | Number of device video sources (0–8) |\n| `u_externalDeviceCount` | `int` | Number of external devices (0–8) |\n| `u_device0` – `u_device7` | `sampler2D` | Device camera textures |\n| `u_device0Resolution` – `u_device7Resolution` | `vec2` | Device camera resolutions |\n| `u_device0Connected` – `u_device7Connected` | `bool` | Device connection status |\n| `u_device0Acceleration` – `u_device7Acceleration` | `vec3` | Per-device acceleration |\n| `u_device0AccelerationGravity` – `u_device7AccelerationGravity` | `vec3` | Per-device acceleration w/ gravity |\n| `u_device0RotationRate` – `u_device7RotationRate` | `vec3` | Per-device rotation rate |\n| `u_device0Orientation` – `u_device7Orientation` | `vec3` | Per-device orientation |\n\n> [!NOTE]\n> **Device audio** (when an external device provides an audio source) is exposed as **`u_audioStream{i}*`** scalar uniforms — same per-slot names as compositor audio streams (`Connected`, `Volume`, band energies, `Brightness`, `Flatness` for `i` = 0–7). There are **no** per-device or per-stream FFT/waveform textures; only the **main** audio source gets `u_audioFFT` and `u_audioWaveform`.\n\n### Streams (Compositor)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_videoStreamCount` | `int` | Number of active streams (0–8) |\n| `u_videoStream0` – `u_videoStream7` | `sampler2D` | Stream textures |\n| `u_videoStream0Resolution` – `u_videoStream7Resolution` | `vec2` | Stream resolutions |\n| `u_videoStream0Connected` – `u_videoStream7Connected` | `bool` | Stream connection status |\n\nStreams are host-provided video sources used internally by the compositor.\n\n#### Audio streams (additional sources)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioStreamCount` | `int` | Number of active additional audio streams (0–8) |\n| `u_audioStream0Connected` – `u_audioStream7Connected` | `bool` | Whether that slot is actively providing audio |\n| `u_audioStream{i}Volume` | `float` | RMS-style volume 0–1 |\n| `u_audioStream{i}Low` – `u_audioStream{i}High` | `float` | Band energies 0–1 (`Low`, `LowMid`, `Mid`, `HighMid`, `High`) |\n| `u_audioStream{i}Brightness`, `u_audioStream{i}Flatness` | `float` | Spectral features 0–1 |\n\n(`i` = 0…7.) **Lightweight scalars only** — **no** `u_audioFFT` / `u_audioWaveform` per stream. Beat/BPM/trigger uniforms remain **main audio only** (`u_audioKick`, `u_audioBPM`, etc.).\n\n### Backbuffer\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `backbuffer` | `sampler2D` | Previous frame (auto-enabled when referenced) |\n\nNo `u_` prefix. RGBA 8-bit, LINEAR filtering, CLAMP_TO_EDGE wrapping. First frame samples as black. Content clears on canvas resize.\nSample: `texture2D(backbuffer, uv)` (ES 1.00) or `texture(backbuffer, uv)` (ES 3.00).\n\n## PARAMETER DIRECTIVES\n\nDeclare with `// @viji-TYPE:uniformName key:value ...` syntax. They become uniforms automatically.\n\n```glsl\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0 step:0.1\n// → uniform float speed;\n\n// @viji-color:tint label:\"Tint\" default:#ff6600\n// → uniform vec3 tint; (RGB 0–1)\n\n// @viji-toggle:invert label:\"Invert\" default:false\n// → uniform bool invert;\n\n// @viji-select:mode label:\"Mode\" default:0 options:[\"Solid\",\"Gradient\",\"Noise\"]\n// → uniform int mode; (0-based index)\n\n// @viji-number:count label:\"Count\" default:10.0 min:1.0 max:100.0 step:1.0\n// → uniform float count;\n\n// @viji-image:tex label:\"Texture\"\n// → uniform sampler2D tex;\n\n// @viji-button:reset label:\"Reset\"\n// → uniform bool reset; (true for one frame on press)\n\n// @viji-coordinate:origin label:\"Origin\" default:[0.0,0.0]\n// → uniform vec2 origin; (both components -1 to 1)\n\n// @viji-accumulator:phase rate:speed\n// → uniform float phase; (CPU-side: += speed × deltaTime each frame)\n```\n\n- `@viji-coordinate:uniformName` — `vec2` uniform, both -1 to 1. Keys: `default:[x,y]` (required), `label` (required), `step`, `description`, `group`, `category`\n\nAll directives support `group:\"GroupName\"` and `category:\"audio|video|interaction|general\"`.\n\n## TEMPLATE\n\n```glsl\n// @renderer shader\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n// @viji-color:baseColor label:\"Color\" default:#ff6600\n// @viji-accumulator:phase rate:speed\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n\n float wave = sin(uv.x * 10.0 + phase) * 0.5 + 0.5;\n float pulse = 1.0 + u_audioLow * 0.5;\n vec3 color = baseColor * wave * pulse;\n\n gl_FragColor = vec4(color, 1.0);\n}\n```\n\nNow generate a Viji shader scene based on the artist's description below. Return ONLY the GLSL code.\nFollow all rules. Use `// @renderer shader` as the first line. Do NOT declare precision or uniforms. Use `@viji-accumulator` for parameter-driven animation. Use `@viji-slider/color/toggle` for artist controls.\n````\n\n## Usage\n\n1. Copy the entire prompt block above.\n2. Paste it into your AI assistant (ChatGPT, Claude, etc.).\n3. After the prompt, describe the shader effect you want.\n4. The AI will return a complete Viji shader scene.\n\n> [!TIP]\n> For better results, describe the visual effect you want (patterns, colors, motion), mention data sources (audio, video, mouse), and what controls the user should have. If you have existing Shadertoy shaders to convert, use the [Convert: Shadertoy](/ai-prompts/convert-shadertoy) prompt instead.\n\n## Related\n\n- [Create Your First Scene](/ai-prompts/create-first-scene) — guided prompt for beginners\n- [Prompting Tips](/ai-prompts/prompting-tips) — how to get better results from AI\n- [Convert: Shadertoy](/ai-prompts/convert-shadertoy) — convert existing Shadertoy shaders to Viji\n- [Shader Quick Start](/shader/quickstart) — your first Viji shader\n- [Shader API Reference](/shader/api-reference) — full uniform reference\n- [Backbuffer & Feedback](/shader/backbuffer) — previous-frame feedback effects\n- [Shadertoy Compatibility](/shader/shadertoy) — compatibility layer for Shadertoy code"
|
|
974
989
|
}
|
|
975
990
|
]
|
|
976
991
|
},
|
|
@@ -992,7 +1007,7 @@ export const docsApi = {
|
|
|
992
1007
|
"content": [
|
|
993
1008
|
{
|
|
994
1009
|
"type": "text",
|
|
995
|
-
"markdown": "# Convert: P5 Sketches to Viji\r\n\r\nCopy the prompt below and paste it into your AI assistant along with the P5.js sketch you want to convert. The prompt contains all the rules the AI needs to produce a correct Viji-P5 scene.\r\n\r\n## The Prompt\r\n\r\n````\r\nYou are converting a standard P5.js sketch into a Viji-P5 scene.\r\nViji scenes run inside an OffscreenCanvas Web Worker. Apply every rule below exactly.\r\n\r\n## RULES\r\n\r\n1. ALWAYS set the first line from the sketch's canvas mode: `// @renderer p5` for 2D (default), or `// @renderer p5 webgl` if the sketch used `createCanvas(w, h, WEBGL)` or 3D primitives on the main canvas. NEVER keep `createCanvas()` — Viji creates the canvas.\r\n2. ALWAYS rename `draw()` to `render(viji, p5)`.\r\n3. If `setup()` exists, change its signature to `setup(viji, p5)`. If it doesn't exist, do NOT add one.\r\n4. ALWAYS prefix every P5 function and constant with `p5.`:\r\n - `background(0)` → `p5.background(0)`\r\n - `fill(255)` → `p5.fill(255)`\r\n - `PI` → `p5.PI`, `TWO_PI` → `p5.TWO_PI`, `HSB` → `p5.HSB`\r\n - `createVector(1, 0)` → `p5.createVector(1, 0)`\r\n - `map(v, 0, 1, 0, 255)` → `p5.map(v, 0, 1, 0, 255)`\r\n - `noise(x)` → `p5.noise(x)`\r\n This applies to ALL P5 functions and constants without exception.\r\n5. NEVER call `createCanvas()`. The canvas is created and managed by Viji. WEBGL is selected only with `// @renderer p5 webgl`, not with `createCanvas(..., p5.WEBGL)`.\r\n6. NEVER use `preload()`. Use `viji.image(null, { label: 'Name' })` for images, or `fetch()` in an async `setup()` for data.\r\n7. NEVER use P5 event callbacks: `mousePressed()`, `mouseDragged()`, `mouseReleased()`, `keyPressed()`, `keyReleased()`, `keyTyped()`, `touchStarted()`, `touchMoved()`, `touchEnded()`. Instead, check state in `render()`:\r\n - `mouseIsPressed` → `viji.pointer.isDown` (works for both mouse and touch) or `viji.mouse.isPressed`\r\n - `mouseX` / `mouseY` → `viji.pointer.x` / `viji.pointer.y` (works for both mouse and touch) or `viji.mouse.x` / `viji.mouse.y`\r\n - `keyIsPressed` → `viji.keyboard.isPressed('keyName')`\r\n - For press-edge detection: use `viji.pointer.wasPressed` / `viji.pointer.wasReleased`.\r\n8. NEVER use `p5.frameRate()`, `p5.save()`, `p5.saveCanvas()`, `p5.saveFrames()`. These are host-level concerns.\r\n9. NEVER use `loadImage()`, `loadFont()`, `loadJSON()`, `loadModel()`, `loadShader()`. Use `viji.image()` or `fetch()`.\r\n10. NEVER use `createCapture()` or `createVideo()`. Use `viji.video.*` instead.\r\n11. NEVER use `p5.dom` or `p5.sound` libraries. Use Viji parameters for UI and `viji.audio.*` for audio.\r\n12. NEVER access `window`, `document`, `Image()`, or `localStorage`. `fetch()` IS available.\r\n13. ALWAYS declare parameters at the TOP LEVEL, never inside `render()` or `setup()`:\r\n ```javascript\r\n // CORRECT\r\n const size = viji.slider(50, { min: 10, max: 200, label: 'Size' });\r\n function render(viji, p5) { p5.circle(0, 0, size.value); }\r\n\r\n // WRONG — creates a new parameter every frame\r\n function render(viji, p5) { const size = viji.slider(50, { ... }); }\r\n ```\r\n14. ALWAYS read parameters via `.value`: `size.value`, `color.value`, `toggle.value`.\r\n15. ALWAYS use `viji.width` and `viji.height` for canvas dimensions. NEVER hardcode pixel sizes.\r\n16. ALWAYS use `viji.deltaTime` for frame-rate-independent animation. Replace `frameCount * 0.01` patterns with a deltaTime accumulator:\r\n ```javascript\r\n let angle = 0;\r\n function render(viji, p5) {\r\n angle += speed.value * viji.deltaTime;\r\n }\r\n ```\r\n NEVER multiply `viji.time` by a parameter (`viji.time * speed.value`) — it causes jumps when the parameter changes. Same for nested: never multiply an accumulator by another parameter; give each speed its own accumulator.\r\n17. NEVER allocate objects, arrays, or strings inside `render()`. Pre-allocate at the top level and reuse.\r\n18. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio, `category: 'video'` for video/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host hide irrelevant controls when the input is inactive.\r\n19. For image parameters displayed with P5, use `photo.p5` (not `photo.value`) with `p5.image()`:\r\n ```javascript\r\n const photo = viji.image(null, { label: 'Photo' });\r\n function render(viji, p5) {\r\n if (photo.value) p5.image(photo.p5, 0, 0, viji.width, viji.height);\r\n }\r\n ```\r\n\r\n## API MAPPING\r\n\r\n| Standard P5.js | Viji-P5 |\r\n|---|---|\r\n| `width` / `height` | `viji.width` / `viji.height` |\r\n| `mouseX` / `mouseY` | `viji.pointer.x` / `viji.pointer.y` (or `viji.mouse.x` / `viji.mouse.y`) |\r\n| `mouseIsPressed` | `viji.pointer.isDown` (or `viji.mouse.isPressed`) |\r\n| `mouseButton === LEFT` | `viji.mouse.leftButton` |\r\n| `keyIsPressed` | `viji.keyboard.isPressed('keyName')` |\r\n| `key` | `viji.keyboard.lastKeyPressed` |\r\n| `frameCount` | Use `viji.time` or `viji.deltaTime` accumulator |\r\n| `frameRate(n)` | Remove — host controls frame rate |\r\n| `createCanvas(w, h)` / `createCanvas(w, h, WEBGL)` | Remove — use `// @renderer p5` or `// @renderer p5 webgl` |\r\n| `preload()` | Remove — use `viji.image()` or `fetch()` in `setup()` |\r\n| `loadImage(url)` | `viji.image(null, { label: 'Image' })` |\r\n| `save()` | Remove — host uses `captureFrame()` |\r\n\r\n## PARAMETER TYPES\r\n\r\n```javascript\r\nviji.slider(default, { min, max, step, label, group, category }) // returns { value: number }\r\nviji.color(default, { label, group, category }) // returns { value: '#rrggbb' }\r\nviji.toggle(default, { label, group, category }) // returns { value: boolean }\r\nviji.select(default, { options: [...], label, group, category }) // returns { value: string }\r\nviji.number(default, { min, max, step, label, group, category }) // returns { value: number }\r\nviji.text(default, { label, group, category }) // returns { value: string }\r\nviji.image(default, { label, group, category }) // returns { value: ImageBitmap|null, p5: P5Image }\r\nviji.button({ label, description, group, category }) // returns { value: boolean }\r\n```\r\n\r\n## TEMPLATE\r\n\r\n```javascript\r\n// @renderer p5\r\n\r\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\r\n\r\nlet angle = 0;\r\n\r\nfunction setup(viji, p5) {\r\n p5.colorMode(p5.HSB, 360, 100, 100);\r\n}\r\n\r\nfunction render(viji, p5) {\r\n angle += speed.value * viji.deltaTime;\r\n p5.background(0, 0, 10);\r\n const x = viji.width / 2 + p5.cos(angle) * viji.width * 0.3;\r\n const y = viji.height / 2 + p5.sin(angle) * viji.height * 0.3;\r\n p5.noStroke();\r\n p5.fill(angle * 30 % 360, 80, 100);\r\n p5.circle(x, y, viji.width * 0.05);\r\n}\r\n```\r\n\r\nNow convert the P5.js sketch I provide. Return ONLY the converted Viji-P5 scene code.\r\n````\r\n\r\n## Usage\r\n\r\n1. Copy the entire prompt block above.\r\n2. Paste it into your AI assistant.\r\n3. After the prompt, paste the P5.js sketch you want to convert.\r\n4. The AI will return a Viji-compatible scene.\r\n\r\nFor a detailed human-readable guide, see [Converting P5 Sketches](/p5/converting-sketches).\r\n\r\n## Related\r\n\r\n- [Converting P5 Sketches](/p5/converting-sketches) — step-by-step manual conversion guide\r\n- [Prompt: P5 Scenes](/ai-prompts/p5-prompt) — AI prompt for creating new P5 scenes from scratch\r\n- [P5 Quick Start](/p5/quickstart) — your first Viji-P5 scene"
|
|
1010
|
+
"markdown": "# Convert: P5 Sketches to Viji\r\n\r\nCopy the prompt below and paste it into your AI assistant along with the P5.js sketch you want to convert. The prompt contains all the rules the AI needs to produce a correct Viji-P5 scene.\r\n\r\n## The Prompt\r\n\r\n````\r\nYou are converting a standard P5.js sketch into a Viji-P5 scene.\r\nViji scenes run inside an OffscreenCanvas Web Worker. Apply every rule below exactly.\r\n\r\n## RULES\r\n\r\n1. ALWAYS set the first line from the sketch's canvas mode: `// @renderer p5` for 2D (default), or `// @renderer p5 webgl` if the sketch used `createCanvas(w, h, WEBGL)` or 3D primitives on the main canvas. NEVER keep `createCanvas()` — Viji creates the canvas.\r\n2. ALWAYS rename `draw()` to `render(viji, p5)`.\r\n3. If `setup()` exists, change its signature to `setup(viji, p5)`. If it doesn't exist, do NOT add one.\r\n4. ALWAYS prefix every P5 function and constant with `p5.`:\r\n - `background(0)` → `p5.background(0)`\r\n - `fill(255)` → `p5.fill(255)`\r\n - `PI` → `p5.PI`, `TWO_PI` → `p5.TWO_PI`, `HSB` → `p5.HSB`\r\n - `createVector(1, 0)` → `p5.createVector(1, 0)`\r\n - `map(v, 0, 1, 0, 255)` → `p5.map(v, 0, 1, 0, 255)`\r\n - `noise(x)` → `p5.noise(x)`\r\n This applies to ALL P5 functions and constants without exception.\r\n5. NEVER call `createCanvas()`. The canvas is created and managed by Viji. WEBGL is selected only with `// @renderer p5 webgl`, not with `createCanvas(..., p5.WEBGL)`.\r\n6. NEVER use `preload()`. Use `viji.image(null, { label: 'Name' })` for images, or `fetch()` in an async `setup()` for data.\r\n7. NEVER use P5 event callbacks: `mousePressed()`, `mouseDragged()`, `mouseReleased()`, `keyPressed()`, `keyReleased()`, `keyTyped()`, `touchStarted()`, `touchMoved()`, `touchEnded()`. Instead, check state in `render()`:\r\n - `mouseIsPressed` → `viji.pointer.isDown` (works for both mouse and touch) or `viji.mouse.isPressed`\r\n - `mouseX` / `mouseY` → `viji.pointer.x` / `viji.pointer.y` (works for both mouse and touch) or `viji.mouse.x` / `viji.mouse.y`\r\n - `keyIsPressed` → `viji.keyboard.isPressed('keyName')`\r\n - For press-edge detection: use `viji.pointer.wasPressed` / `viji.pointer.wasReleased`.\r\n8. NEVER use `p5.frameRate()`, `p5.save()`, `p5.saveCanvas()`, `p5.saveFrames()`. These are host-level concerns.\r\n9. NEVER use `loadImage()`, `loadFont()`, `loadJSON()`, `loadModel()`, `loadShader()`. Use `viji.image()` or `fetch()`.\r\n10. NEVER use `createCapture()` or `createVideo()`. Use `viji.video.*` instead.\r\n11. NEVER use `p5.dom` or `p5.sound` libraries. Use Viji parameters for UI and `viji.audio.*` for audio.\r\n12. NEVER access `window`, `document`, `Image()`, or `localStorage`. `fetch()` IS available.\r\n13. ALWAYS declare parameters at the TOP LEVEL, never inside `render()` or `setup()`:\r\n ```javascript\r\n // CORRECT\r\n const size = viji.slider(50, { min: 10, max: 200, label: 'Size' });\r\n function render(viji, p5) { p5.circle(0, 0, size.value); }\r\n\r\n // WRONG — creates a new parameter every frame\r\n function render(viji, p5) { const size = viji.slider(50, { ... }); }\r\n ```\r\n14. ALWAYS read parameters via `.value`: `size.value`, `color.value`, `toggle.value`.\r\n15. ALWAYS use `viji.width` and `viji.height` for canvas dimensions. NEVER hardcode pixel sizes.\r\n16. ALWAYS use `viji.deltaTime` for frame-rate-independent animation. Replace `frameCount * 0.01` patterns with a deltaTime accumulator:\r\n ```javascript\r\n let angle = 0;\r\n function render(viji, p5) {\r\n angle += speed.value * viji.deltaTime;\r\n }\r\n ```\r\n NEVER multiply `viji.time` by a parameter (`viji.time * speed.value`) — it causes jumps when the parameter changes. Same for nested: never multiply an accumulator by another parameter; give each speed its own accumulator.\r\n17. NEVER allocate objects, arrays, or strings inside `render()`. Pre-allocate at the top level and reuse.\r\n18. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio, `category: 'video'` for video/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host hide irrelevant controls when the input is inactive.\r\n19. For image parameters displayed with P5, use `photo.p5` (not `photo.value`) with `p5.image()`:\r\n ```javascript\r\n const photo = viji.image(null, { label: 'Photo' });\r\n function render(viji, p5) {\r\n if (photo.value) p5.image(photo.p5, 0, 0, viji.width, viji.height);\r\n }\r\n ```\r\n\r\n## API MAPPING\r\n\r\n| Standard P5.js | Viji-P5 |\r\n|---|---|\r\n| `width` / `height` | `viji.width` / `viji.height` |\r\n| `mouseX` / `mouseY` | `viji.pointer.x` / `viji.pointer.y` (or `viji.mouse.x` / `viji.mouse.y`) |\r\n| `mouseIsPressed` | `viji.pointer.isDown` (or `viji.mouse.isPressed`) |\r\n| `mouseButton === LEFT` | `viji.mouse.leftButton` |\r\n| `keyIsPressed` | `viji.keyboard.isPressed('keyName')` |\r\n| `key` | `viji.keyboard.lastKeyPressed` |\r\n| `frameCount` | Use `viji.time` or `viji.deltaTime` accumulator |\r\n| `frameRate(n)` | Remove — host controls frame rate |\r\n| `createCanvas(w, h)` / `createCanvas(w, h, WEBGL)` | Remove — use `// @renderer p5` or `// @renderer p5 webgl` |\r\n| `preload()` | Remove — use `viji.image()` or `fetch()` in `setup()` |\r\n| `loadImage(url)` | `viji.image(null, { label: 'Image' })` |\r\n| `save()` | Remove — host uses `captureFrame()` |\r\n\r\n## PARAMETER TYPES\r\n\r\n```javascript\r\nviji.slider(default, { min, max, step, label, group, category }) // returns { value: number }\r\nviji.color(default, { label, group, category }) // returns { value: '#rrggbb' }\r\nviji.toggle(default, { label, group, category }) // returns { value: boolean }\r\nviji.select(default, { options: [...], label, group, category }) // returns { value: string }\r\nviji.number(default, { min, max, step, label, group, category }) // returns { value: number }\r\nviji.text(default, { label, group, category }) // returns { value: string }\r\nviji.image(default, { label, group, category }) // returns { value: ImageBitmap|null, p5: P5Image }\r\nviji.button({ label, description, group, category }) // returns { value: boolean }\r\nviji.coordinate(defaultValue, config) // returns { value: { x: number, y: number } } // 2D coordinate pad, both -1 to 1\r\n```\r\n\r\n## TEMPLATE\r\n\r\n```javascript\r\n// @renderer p5\r\n\r\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\r\n\r\nlet angle = 0;\r\n\r\nfunction setup(viji, p5) {\r\n p5.colorMode(p5.HSB, 360, 100, 100);\r\n}\r\n\r\nfunction render(viji, p5) {\r\n angle += speed.value * viji.deltaTime;\r\n p5.background(0, 0, 10);\r\n const x = viji.width / 2 + p5.cos(angle) * viji.width * 0.3;\r\n const y = viji.height / 2 + p5.sin(angle) * viji.height * 0.3;\r\n p5.noStroke();\r\n p5.fill(angle * 30 % 360, 80, 100);\r\n p5.circle(x, y, viji.width * 0.05);\r\n}\r\n```\r\n\r\nNow convert the P5.js sketch I provide. Return ONLY the converted Viji-P5 scene code.\r\n````\r\n\r\n## Usage\r\n\r\n1. Copy the entire prompt block above.\r\n2. Paste it into your AI assistant.\r\n3. After the prompt, paste the P5.js sketch you want to convert.\r\n4. The AI will return a Viji-compatible scene.\r\n\r\nFor a detailed human-readable guide, see [Converting P5 Sketches](/p5/converting-sketches).\r\n\r\n## Related\r\n\r\n- [Converting P5 Sketches](/p5/converting-sketches) — step-by-step manual conversion guide\r\n- [Prompt: P5 Scenes](/ai-prompts/p5-prompt) — AI prompt for creating new P5 scenes from scratch\r\n- [P5 Quick Start](/p5/quickstart) — your first Viji-P5 scene"
|
|
996
1011
|
}
|
|
997
1012
|
]
|
|
998
1013
|
},
|
|
@@ -1003,7 +1018,7 @@ export const docsApi = {
|
|
|
1003
1018
|
"content": [
|
|
1004
1019
|
{
|
|
1005
1020
|
"type": "text",
|
|
1006
|
-
"markdown": "# Convert: Shadertoy to Viji\r\n\r\nCopy the prompt below and paste it into your AI assistant along with the Shadertoy shader you want to convert. The prompt contains all the rules the AI needs to produce a correct Viji shader scene.\r\n\r\n## The Prompt\r\n\r\n````\r\nYou are converting a Shadertoy shader into a Viji shader scene.\r\nViji runs GLSL fragment shaders with automatic uniform injection. Apply every rule below exactly.\r\n\r\n## RULES\r\n\r\n1. ALWAYS add `// @renderer shader` as the very first line (or after `#version 300 es` if using GLSL ES 3.00).\r\n2. NEVER declare `precision mediump float;` or `precision highp float;` — Viji auto-injects precision.\r\n3. NEVER redeclare built-in uniforms (`u_time`, `u_resolution`, `u_mouse`, etc.) — they are auto-injected.\r\n4. NEVER redeclare parameter uniforms — they are auto-generated from `@viji-*` directives.\r\n5. Convert the `mainImage` signature to a standard `void main()`:\r\n - Replace `fragCoord` with `gl_FragCoord.xy`\r\n - Replace `fragColor` with `gl_FragColor`\r\n - Remove the `mainImage` wrapper entirely.\r\n6. ALWAYS replace Shadertoy uniforms with Viji equivalents using this mapping:\r\n\r\n | Shadertoy | Viji | Notes |\r\n |---|---|---|\r\n | `iResolution.xy` | `u_resolution` | Viji's `u_resolution` is `vec2`. For `.z` (aspect ratio), use `u_resolution.x / u_resolution.y`. |\r\n | `iResolution.x`, `.y` | `u_resolution.x`, `.y` | Direct match. |\r\n | `iTime` | `u_time` | Elapsed seconds. |\r\n | `iTimeDelta` | `u_deltaTime` | Seconds since last frame. |\r\n | `iFrame` | `u_frame` | Frame counter (`int`). |\r\n | `iMouse.xy` | `u_mouse` | Current mouse position in pixels. |\r\n | `iMouse.z` | Approximate with `u_mouseLeft ? u_mouse.x : 0.0` | Viji does not track click-origin. |\r\n | `iMouse.w` | Approximate with `u_mouseLeft ? u_mouse.y : 0.0` | Viji does not track click-origin. |\r\n | `iChannel0`–`3` | Declare `@viji-image` parameters | See texture rules below. |\r\n | `iChannelResolution` | Not available | Track dimensions manually if needed. |\r\n | `iDate` | Not available | Use `u_time` for elapsed time. |\r\n | `iSampleRate` | Not available | Not applicable. |\r\n\r\n7. For `iChannel` textures, declare `@viji-image` parameters:\r\n ```glsl\r\n // @viji-image:channel0 label:\"Texture 1\"\r\n // @viji-image:channel1 label:\"Texture 2\"\r\n ```\r\n Then replace `texture(iChannel0, uv)` with `texture2D(channel0, uv)` (or `texture(channel0, uv)` in ES 3.00).\r\n\r\n8. If an `iChannel` is set to **Keyboard** input in Shadertoy, replace it with `u_keyboard`:\r\n ```glsl\r\n // Shadertoy: texelFetch(iChannel0, ivec2(KEY, 0), 0).x\r\n // Viji: texelFetch(u_keyboard, ivec2(KEY, 0), 0).x\r\n ```\r\n `u_keyboard` is a built-in `sampler2D` (256x3). Row 0 = held, Row 1 = pressed this frame, Row 2 = toggle. Do NOT declare it — it is auto-injected.\r\n\r\n9. For `iResolution` used as `vec3`, replace with:\r\n ```glsl\r\n vec3(u_resolution, u_resolution.x / u_resolution.y)\r\n ```\r\n Or refactor to use `u_resolution` as `vec2` directly — most code only needs `.xy`.\r\n\r\n10. If the shader uses `iTime` multiplied by a speed factor, ALWAYS use an accumulator instead of `u_time * speed` to prevent animation jumps when the slider changes:\r\n ```glsl\r\n // @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\r\n // @viji-accumulator:phase rate:speed\r\n ```\r\n Then replace `iTime` with `phase`.\r\n The same applies to nested multiplications: never multiply an accumulator by another parameter inside the shader. If you need two independent speeds, declare two accumulators.\r\n\r\n11. If adding artist-controllable parameters, ALWAYS use `// @viji-*` directives:\r\n ```glsl\r\n // @viji-slider:name label:\"Label\" default:1.0 min:0.0 max:5.0\r\n // @viji-color:name label:\"Label\" default:#ff6600\r\n // @viji-toggle:name label:\"Label\" default:true\r\n // @viji-select:name label:\"Label\" default:0 options:[\"A\",\"B\",\"C\"]\r\n // @viji-image:name label:\"Label\"\r\n // @viji-button:name label:\"Label\"\r\n // @viji-accumulator:name rate:source\r\n ```\r\n NEVER use the `u_` prefix for parameter names — it is reserved for built-in uniforms.\r\n\r\n12. Parameter directives ONLY work with `//` comments. NEVER use `/* */` for `@viji-*` directives.\r\n\r\n13. If the shader uses `#version 300 es`:\r\n - Keep it as the very first line (before `// @renderer shader`).\r\n - Replace `gl_FragColor = ...` with `out vec4 fragColor;` (declared before `main`) and `fragColor = ...`.\r\n - Replace `texture2D()` with `texture()`.\r\n - Default (no `#version`) uses GLSL ES 1.00 for maximum compatibility.\r\n\r\n14. Remove any `#ifdef GL_ES` / `precision` blocks — Viji handles this.\r\n15. ALWAYS set `category:` on input-dependent `@viji-*` directives: `category:audio` for audio controls, `category:video` for video controls, `category:interaction` for mouse/touch controls.\r\n\r\n16. For feedback effects that used Shadertoy's Buffer tabs, use Viji's backbuffer:\r\n ```glsl\r\n vec4 prev = texture2D(backbuffer, uv);\r\n ```\r\n `backbuffer` is auto-detected and enabled. This replaces simple Buffer A patterns.\r\n Viji does NOT support multi-buffer pipelines (Buffer A feeding Buffer B). Only single-pass feedback is available.\r\n\r\n16. UNSUPPORTED Shadertoy features — if the source shader uses any of these, warn the user:\r\n - **Multi-buffer pipelines** (Buffer A→B→C→D): only single `backbuffer` available.\r\n - **CubeMap buffer** (`samplerCube`): not supported.\r\n - **3D textures** (`sampler3D`): not supported.\r\n - **`iChannelTime`**: not available.\r\n - **`iChannelResolution`**: not available.\r\n - **Sound output buffer**: not supported.\r\n - **`mainVR()`**: not supported.\r\n - **Texture wrap/filter modes**: Viji uses fixed `CLAMP_TO_EDGE` + `LINEAR`. Use `fract(uv)` for repeat.\r\n\r\n## UNIFORM QUICK REFERENCE\r\n\r\nThese are always available — do NOT declare them:\r\n- `u_resolution` (vec2), `u_time` (float), `u_deltaTime` (float), `u_frame` (int)\r\n- `u_mouse` (vec2), `u_mousePressed` (bool), `u_mouseLeft` (bool)\r\n- `u_keyboard` (sampler2D, 256x3 keyboard state texture)\r\n- `u_audioVolume` (float), `u_audioLow/Mid/High` (float), `u_audioKick/Snare/Hat` (float)\r\n- `u_video` (sampler2D), `backbuffer` (sampler2D, auto-enabled if used)\r\n\r\n## PARAMETER TYPE → UNIFORM MAPPING\r\n\r\n| Directive | GLSL Type | Example |\r\n|---|---|---|\r\n| `@viji-slider` | `uniform float` | `// @viji-slider:speed label:\"Speed\" default:1.0 min:0.0 max:5.0` |\r\n| `@viji-number` | `uniform float` | `// @viji-number:count label:\"Count\" default:10.0 min:1.0 max:100.0` |\r\n| `@viji-color` | `uniform vec3` | `// @viji-color:tint label:\"Tint\" default:#00ffcc` |\r\n| `@viji-toggle` | `uniform bool` | `// @viji-toggle:invert label:\"Invert\" default:false` |\r\n| `@viji-select` | `uniform int` | `// @viji-select:mode label:\"Mode\" default:0 options:[\"A\",\"B\"]` |\r\n| `@viji-image` | `uniform sampler2D` | `// @viji-image:tex label:\"Texture\"` |\r\n| `@viji-button` | `uniform bool` | `// @viji-button:trigger label:\"Trigger\"` |\r\n| `@viji-accumulator` | `uniform float` | `// @viji-accumulator:phase rate:speed` |\r\n\r\n## CONVERSION TEMPLATE\r\n\r\n```glsl\r\n// @renderer shader\r\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\r\n// @viji-accumulator:phase rate:speed\r\n\r\nvoid main() {\r\n vec2 uv = gl_FragCoord.xy / u_resolution;\r\n\r\n // ... converted shader logic ...\r\n // Use `phase` instead of `iTime`\r\n // Use `u_resolution` instead of `iResolution.xy`\r\n // Use `gl_FragCoord.xy` instead of `fragCoord`\r\n\r\n gl_FragColor = vec4(color, 1.0);\r\n}\r\n```\r\n\r\nNow convert the Shadertoy shader I provide. Return ONLY the converted Viji shader code.\r\nApply all rules. Do NOT use a compatibility layer — convert directly to native Viji uniforms.\r\n````\r\n\r\n## Usage\r\n\r\n1. Copy the entire prompt block above.\r\n2. Paste it into your AI assistant.\r\n3. After the prompt, paste the Shadertoy shader code (the `mainImage` function).\r\n4. The AI will return a native Viji shader scene.\r\n\r\n> [!TIP]\r\n> This prompt converts to **native Viji uniforms** (no `#define` compatibility layer). For a quick-and-dirty conversion using `#define` macros, see the compatibility header in [Shadertoy Compatibility](/shader/shadertoy).\r\n\r\n## Related\r\n\r\n- [Shadertoy Compatibility](/shader/shadertoy) — manual conversion guide with compatibility layer\r\n- [Accumulator](/shader/parameters/accumulator) — how accumulators prevent animation jumps\r\n- [Prompt: Shader Scenes](/ai-prompts/shader-prompt) — AI prompt for creating new shaders from scratch\r\n- [Shader Quick Start](/shader/quickstart) — your first Viji shader"
|
|
1021
|
+
"markdown": "# Convert: Shadertoy to Viji\r\n\r\nCopy the prompt below and paste it into your AI assistant along with the Shadertoy shader you want to convert. The prompt contains all the rules the AI needs to produce a correct Viji shader scene.\r\n\r\n## The Prompt\r\n\r\n````\r\nYou are converting a Shadertoy shader into a Viji shader scene.\r\nViji runs GLSL fragment shaders with automatic uniform injection. Apply every rule below exactly.\r\n\r\n## RULES\r\n\r\n1. ALWAYS add `// @renderer shader` as the very first line (or after `#version 300 es` if using GLSL ES 3.00).\r\n2. NEVER declare `precision mediump float;` or `precision highp float;` — Viji auto-injects precision.\r\n3. NEVER redeclare built-in uniforms (`u_time`, `u_resolution`, `u_mouse`, etc.) — they are auto-injected.\r\n4. NEVER redeclare parameter uniforms — they are auto-generated from `@viji-*` directives.\r\n5. Convert the `mainImage` signature to a standard `void main()`:\r\n - Replace `fragCoord` with `gl_FragCoord.xy`\r\n - Replace `fragColor` with `gl_FragColor`\r\n - Remove the `mainImage` wrapper entirely.\r\n6. ALWAYS replace Shadertoy uniforms with Viji equivalents using this mapping:\r\n\r\n | Shadertoy | Viji | Notes |\r\n |---|---|---|\r\n | `iResolution.xy` | `u_resolution` | Viji's `u_resolution` is `vec2`. For `.z` (aspect ratio), use `u_resolution.x / u_resolution.y`. |\r\n | `iResolution.x`, `.y` | `u_resolution.x`, `.y` | Direct match. |\r\n | `iTime` | `u_time` | Elapsed seconds. |\r\n | `iTimeDelta` | `u_deltaTime` | Seconds since last frame. |\r\n | `iFrame` | `u_frame` | Frame counter (`int`). |\r\n | `iMouse.xy` | `u_mouse` | Current mouse position in pixels. |\r\n | `iMouse.z` | Approximate with `u_mouseLeft ? u_mouse.x : 0.0` | Viji does not track click-origin. |\r\n | `iMouse.w` | Approximate with `u_mouseLeft ? u_mouse.y : 0.0` | Viji does not track click-origin. |\r\n | `iChannel0`–`3` | Declare `@viji-image` parameters | See texture rules below. |\r\n | `iChannelResolution` | Not available | Track dimensions manually if needed. |\r\n | `iDate` | Not available | Use `u_time` for elapsed time. |\r\n | `iSampleRate` | Not available | Not applicable. |\r\n\r\n7. For `iChannel` textures, declare `@viji-image` parameters:\r\n ```glsl\r\n // @viji-image:channel0 label:\"Texture 1\"\r\n // @viji-image:channel1 label:\"Texture 2\"\r\n ```\r\n Then replace `texture(iChannel0, uv)` with `texture2D(channel0, uv)` (or `texture(channel0, uv)` in ES 3.00).\r\n\r\n8. If an `iChannel` is set to **Keyboard** input in Shadertoy, replace it with `u_keyboard`:\r\n ```glsl\r\n // Shadertoy: texelFetch(iChannel0, ivec2(KEY, 0), 0).x\r\n // Viji: texelFetch(u_keyboard, ivec2(KEY, 0), 0).x\r\n ```\r\n `u_keyboard` is a built-in `sampler2D` (256x3). Row 0 = held, Row 1 = pressed this frame, Row 2 = toggle. Do NOT declare it — it is auto-injected.\r\n\r\n9. For `iResolution` used as `vec3`, replace with:\r\n ```glsl\r\n vec3(u_resolution, u_resolution.x / u_resolution.y)\r\n ```\r\n Or refactor to use `u_resolution` as `vec2` directly — most code only needs `.xy`.\r\n\r\n10. If the shader uses `iTime` multiplied by a speed factor, ALWAYS use an accumulator instead of `u_time * speed` to prevent animation jumps when the slider changes:\r\n ```glsl\r\n // @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\r\n // @viji-accumulator:phase rate:speed\r\n ```\r\n Then replace `iTime` with `phase`.\r\n The same applies to nested multiplications: never multiply an accumulator by another parameter inside the shader. If you need two independent speeds, declare two accumulators.\r\n\r\n11. If adding artist-controllable parameters, ALWAYS use `// @viji-*` directives:\r\n ```glsl\r\n // @viji-slider:name label:\"Label\" default:1.0 min:0.0 max:5.0\r\n // @viji-color:name label:\"Label\" default:#ff6600\r\n // @viji-toggle:name label:\"Label\" default:true\r\n // @viji-select:name label:\"Label\" default:0 options:[\"A\",\"B\",\"C\"]\r\n // @viji-image:name label:\"Label\"\r\n // @viji-button:name label:\"Label\"\r\n // @viji-coordinate:uniformName label:\"Label\" default:[x,y] // vec2 uniform, both -1 to 1; keys: default (required), label (required), step, description, group, category\r\n // @viji-accumulator:name rate:source\r\n ```\r\n NEVER use the `u_` prefix for parameter names — it is reserved for built-in uniforms.\r\n\r\n12. Parameter directives ONLY work with `//` comments. NEVER use `/* */` for `@viji-*` directives.\r\n\r\n13. If the shader uses `#version 300 es`:\r\n - Keep it as the very first line (before `// @renderer shader`).\r\n - Replace `gl_FragColor = ...` with `out vec4 fragColor;` (declared before `main`) and `fragColor = ...`.\r\n - Replace `texture2D()` with `texture()`.\r\n - Default (no `#version`) uses GLSL ES 1.00 for maximum compatibility.\r\n\r\n14. Remove any `#ifdef GL_ES` / `precision` blocks — Viji handles this.\r\n15. ALWAYS set `category:` on input-dependent `@viji-*` directives: `category:audio` for audio controls, `category:video` for video controls, `category:interaction` for mouse/touch controls.\r\n\r\n16. For feedback effects that used Shadertoy's Buffer tabs, use Viji's backbuffer:\r\n ```glsl\r\n vec4 prev = texture2D(backbuffer, uv);\r\n ```\r\n `backbuffer` is auto-detected and enabled. This replaces simple Buffer A patterns.\r\n Viji does NOT support multi-buffer pipelines (Buffer A feeding Buffer B). Only single-pass feedback is available.\r\n\r\n16. UNSUPPORTED Shadertoy features — if the source shader uses any of these, warn the user:\r\n - **Multi-buffer pipelines** (Buffer A→B→C→D): only single `backbuffer` available.\r\n - **CubeMap buffer** (`samplerCube`): not supported.\r\n - **3D textures** (`sampler3D`): not supported.\r\n - **`iChannelTime`**: not available.\r\n - **`iChannelResolution`**: not available.\r\n - **Sound output buffer**: not supported.\r\n - **`mainVR()`**: not supported.\r\n - **Texture wrap/filter modes**: Viji uses fixed `CLAMP_TO_EDGE` + `LINEAR`. Use `fract(uv)` for repeat.\r\n\r\n## UNIFORM QUICK REFERENCE\r\n\r\nThese are always available — do NOT declare them:\r\n- `u_resolution` (vec2), `u_time` (float), `u_deltaTime` (float), `u_frame` (int)\r\n- `u_mouse` (vec2), `u_mousePressed` (bool), `u_mouseLeft` (bool)\r\n- `u_keyboard` (sampler2D, 256x3 keyboard state texture)\r\n- `u_audioVolume` (float), `u_audioLow/Mid/High` (float), `u_audioKick/Snare/Hat` (float)\r\n- `u_video` (sampler2D), `backbuffer` (sampler2D, auto-enabled if used)\r\n\r\n## PARAMETER TYPE → UNIFORM MAPPING\r\n\r\n| Directive | GLSL Type | Example |\r\n|---|---|---|\r\n| `@viji-slider` | `uniform float` | `// @viji-slider:speed label:\"Speed\" default:1.0 min:0.0 max:5.0` |\r\n| `@viji-number` | `uniform float` | `// @viji-number:count label:\"Count\" default:10.0 min:1.0 max:100.0` |\r\n| `@viji-color` | `uniform vec3` | `// @viji-color:tint label:\"Tint\" default:#00ffcc` |\r\n| `@viji-toggle` | `uniform bool` | `// @viji-toggle:invert label:\"Invert\" default:false` |\r\n| `@viji-select` | `uniform int` | `// @viji-select:mode label:\"Mode\" default:0 options:[\"A\",\"B\"]` |\r\n| `@viji-image` | `uniform sampler2D` | `// @viji-image:tex label:\"Texture\"` |\r\n| `@viji-button` | `uniform bool` | `// @viji-button:trigger label:\"Trigger\"` |\r\n| `@viji-coordinate` | `uniform vec2` | `// @viji-coordinate:origin label:\"Origin\" default:[0.0,0.0]` (both -1 to 1; `label` and `default:[x,y]` required; optional: `step`, `description`, `group`, `category`) |\r\n| `@viji-accumulator` | `uniform float` | `// @viji-accumulator:phase rate:speed` |\r\n\r\n## CONVERSION TEMPLATE\r\n\r\n```glsl\r\n// @renderer shader\r\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\r\n// @viji-accumulator:phase rate:speed\r\n\r\nvoid main() {\r\n vec2 uv = gl_FragCoord.xy / u_resolution;\r\n\r\n // ... converted shader logic ...\r\n // Use `phase` instead of `iTime`\r\n // Use `u_resolution` instead of `iResolution.xy`\r\n // Use `gl_FragCoord.xy` instead of `fragCoord`\r\n\r\n gl_FragColor = vec4(color, 1.0);\r\n}\r\n```\r\n\r\nNow convert the Shadertoy shader I provide. Return ONLY the converted Viji shader code.\r\nApply all rules. Do NOT use a compatibility layer — convert directly to native Viji uniforms.\r\n````\r\n\r\n## Usage\r\n\r\n1. Copy the entire prompt block above.\r\n2. Paste it into your AI assistant.\r\n3. After the prompt, paste the Shadertoy shader code (the `mainImage` function).\r\n4. The AI will return a native Viji shader scene.\r\n\r\n> [!TIP]\r\n> This prompt converts to **native Viji uniforms** (no `#define` compatibility layer). For a quick-and-dirty conversion using `#define` macros, see the compatibility header in [Shadertoy Compatibility](/shader/shadertoy).\r\n\r\n## Related\r\n\r\n- [Shadertoy Compatibility](/shader/shadertoy) — manual conversion guide with compatibility layer\r\n- [Accumulator](/shader/parameters/accumulator) — how accumulators prevent animation jumps\r\n- [Prompt: Shader Scenes](/ai-prompts/shader-prompt) — AI prompt for creating new shaders from scratch\r\n- [Shader Quick Start](/shader/quickstart) — your first Viji shader"
|
|
1007
1022
|
}
|
|
1008
1023
|
]
|
|
1009
1024
|
},
|
|
@@ -1014,7 +1029,7 @@ export const docsApi = {
|
|
|
1014
1029
|
"content": [
|
|
1015
1030
|
{
|
|
1016
1031
|
"type": "text",
|
|
1017
|
-
"markdown": "# Convert: Three.js to Viji\r\n\r\nCopy the prompt below and paste it into your AI assistant along with the Three.js code you want to convert. The prompt contains all the rules the AI needs to produce a correct Viji native scene with Three.js.\r\n\r\n## The Prompt\r\n\r\n````\r\nYou are converting a standalone Three.js application into a Viji native scene.\r\nViji scenes run inside an OffscreenCanvas Web Worker. Apply every rule below exactly.\r\n\r\n## RULES\r\n\r\n1. ALWAYS import Three.js dynamically at the top level using `await import()`:\r\n ```javascript\r\n const THREE = await import('https://esm.sh/three@0.160.0');\r\n ```\r\n NEVER use `<script>` tags, `require()`, or static `import` statements.\r\n ALWAYS pin the version number in the URL.\r\n\r\n2. ALWAYS use `viji.canvas` as the renderer's canvas:\r\n ```javascript\r\n const renderer = new THREE.WebGLRenderer({ canvas: viji.canvas, antialias: true });\r\n renderer.setSize(viji.width, viji.height, false);\r\n ```\r\n ALWAYS pass `false` as the third argument to `setSize()` — this prevents Three.js from setting CSS styles, which would fail in the worker.\r\n\r\n3. NEVER use `requestAnimationFrame()`. Viji controls the render loop. Write all per-frame logic inside `function render(viji) { ... }` and call `renderer.render(scene, camera)` at the end.\r\n\r\n4. ALWAYS handle resize by checking `viji.width` / `viji.height` in `render()`:\r\n ```javascript\r\n let prevWidth = viji.width;\r\n let prevHeight = viji.height;\r\n\r\n function render(viji) {\r\n if (viji.width !== prevWidth || viji.height !== prevHeight) {\r\n renderer.setSize(viji.width, viji.height, false);\r\n camera.aspect = viji.width / viji.height;\r\n camera.updateProjectionMatrix();\r\n prevWidth = viji.width;\r\n prevHeight = viji.height;\r\n }\r\n renderer.render(scene, camera);\r\n }\r\n ```\r\n\r\n5. NEVER access `window`, `document`, `Image()`, or `localStorage`. `fetch()` IS available.\r\n\r\n6. NEVER use `window.innerWidth` / `window.innerHeight`. Use `viji.width` / `viji.height`.\r\n\r\n7. Replace hardcoded values with Viji parameters declared at the top level:\r\n ```javascript\r\n const speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\r\n const color = viji.color('#049ef4', { label: 'Color' });\r\n ```\r\n NEVER declare parameters inside `render()`.\r\n ALWAYS read via `.value`: `speed.value`, `color.value`.\r\n\r\n8. ALWAYS use `viji.deltaTime` for animation timing:\r\n ```javascript\r\n cube.rotation.y += speed.value * viji.deltaTime;\r\n ```\r\n NEVER use `clock.getDelta()` or `Date.now()`. Remove any `THREE.Clock` usage.\r\n NEVER multiply `viji.time` by a parameter (`viji.time * speed.value`) — it causes animation jumps when the parameter changes. Same for nested multiplications: never multiply an accumulator by another parameter; give each speed its own accumulator.\r\n\r\n9. Replace mouse/keyboard event listeners with Viji APIs:\r\n - `event.clientX` → `viji.pointer.x` (works for both mouse and touch) or `viji.mouse.x`\r\n - `event.clientY` → `viji.pointer.y` or `viji.mouse.y`\r\n - Mouse buttons → `viji.mouse.leftButton`, `viji.mouse.rightButton`\r\n - Key presses → `viji.keyboard.isPressed('keyName')`\r\n\r\n10. `OrbitControls` and other controls that depend on DOM events will NOT work in the worker.\r\n For camera interaction, read `viji.pointer` (handles both mouse and touch) and update the camera manually.\r\n\r\n11. For Three.js addons, import from the examples directory:\r\n ```javascript\r\n const { GLTFLoader } = await import('https://esm.sh/three@0.160.0/examples/jsm/loaders/GLTFLoader.js');\r\n const { EffectComposer } = await import('https://esm.sh/three@0.160.0/examples/jsm/postprocessing/EffectComposer.js');\r\n ```\r\n ALWAYS use the same Three.js version for addons as for the main library.\r\n\r\n12. For textures from file inputs, use Viji's image parameters:\r\n ```javascript\r\n const photo = viji.image(null, { label: 'Texture' });\r\n // In render():\r\n if (photo.value && !texture) {\r\n texture = new THREE.CanvasTexture(photo.value);\r\n material.map = texture;\r\n material.needsUpdate = true;\r\n }\r\n ```\r\n\r\n13. For video textures, use `viji.video`:\r\n ```javascript\r\n if (viji.video.isConnected && viji.video.currentFrame) {\r\n if (!videoTexture) {\r\n videoTexture = new THREE.CanvasTexture(viji.video.currentFrame);\r\n material.map = videoTexture;\r\n }\r\n videoTexture.needsUpdate = true;\r\n }\r\n ```\r\n\r\n14. NEVER allocate new objects inside `render()`. Pre-create vectors, colors, and materials at the top level.\r\n\r\n15. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio, `category: 'video'` for video/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host hide irrelevant controls when the input is inactive.\r\n\r\n16. Remove any `window.addEventListener('resize', ...)` — resize is handled in `render()` (see rule 4).\r\n\r\n16. Remove any CSS, HTML, or DOM manipulation code. Viji scenes produce only canvas output.\r\n\r\n## PARAMETER TYPES\r\n\r\n```javascript\r\nviji.slider(default, { min, max, step, label, group, category }) // { value: number }\r\nviji.color(default, { label, group, category }) // { value: '#rrggbb' }\r\nviji.toggle(default, { label, group, category }) // { value: boolean }\r\nviji.select(default, { options: [...], label, group, category }) // { value: string }\r\nviji.number(default, { min, max, step, label, group, category }) // { value: number }\r\nviji.image(default, { label, group, category }) // { value: ImageBitmap|null }\r\nviji.button({ label, description, group, category }) // { value: boolean }\r\n```\r\n\r\n## VIJI API QUICK REFERENCE\r\n\r\n- `viji.canvas` — the OffscreenCanvas (pass to Three.js renderer)\r\n- `viji.width`, `viji.height` — current canvas dimensions\r\n- `viji.time` — elapsed seconds since scene start\r\n- `viji.deltaTime` — seconds since last frame\r\n- `viji.pointer.x`, `.y`, `.isDown`, `.deltaX`, `.deltaY` — unified mouse/touch input\r\n- `viji.mouse.x`, `.y`, `.isPressed`, `.leftButton`, `.rightButton`, `.wheelDelta`\r\n- `viji.keyboard.isPressed('key')`, `.lastKeyPressed`\r\n- `viji.audio.isConnected`, `.volume.current`, `.bands.low/mid/high`, `.beat.kick/snare/hat`\r\n- `viji.video.isConnected`, `.currentFrame`\r\n\r\n## TEMPLATE\r\n\r\n```javascript\r\nconst THREE = await import('https://esm.sh/three@0.160.0');\r\n\r\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\r\nconst color = viji.color('#049ef4', { label: 'Color' });\r\n\r\nconst scene = new THREE.Scene();\r\nconst camera = new THREE.PerspectiveCamera(60, viji.width / viji.height, 0.1, 100);\r\ncamera.position.set(0, 1, 3);\r\ncamera.lookAt(0, 0, 0);\r\n\r\nconst renderer = new THREE.WebGLRenderer({ canvas: viji.canvas, antialias: true });\r\nrenderer.setSize(viji.width, viji.height, false);\r\n\r\nconst geometry = new THREE.BoxGeometry();\r\nconst material = new THREE.MeshStandardMaterial({ color: color.value });\r\nconst mesh = new THREE.Mesh(geometry, material);\r\nscene.add(mesh);\r\n\r\nscene.add(new THREE.DirectionalLight(0xffffff, 1.5));\r\nscene.add(new THREE.AmbientLight(0x404040));\r\n\r\nlet prevWidth = viji.width;\r\nlet prevHeight = viji.height;\r\n\r\nfunction render(viji) {\r\n mesh.rotation.y += speed.value * viji.deltaTime;\r\n material.color.set(color.value);\r\n\r\n if (viji.width !== prevWidth || viji.height !== prevHeight) {\r\n renderer.setSize(viji.width, viji.height, false);\r\n camera.aspect = viji.width / viji.height;\r\n camera.updateProjectionMatrix();\r\n prevWidth = viji.width;\r\n prevHeight = viji.height;\r\n }\r\n\r\n renderer.render(scene, camera);\r\n}\r\n```\r\n\r\nNow convert the Three.js code I provide. Return ONLY the converted Viji scene code.\r\n````\r\n\r\n## Usage\r\n\r\n1. Copy the entire prompt block above.\r\n2. Paste it into your AI assistant.\r\n3. After the prompt, paste the Three.js code you want to convert.\r\n4. The AI will return a Viji-compatible native scene.\r\n\r\n> [!NOTE]\r\n> This prompt handles standard Three.js scenes. If the original code uses a framework (React Three Fiber, Drei, etc.), you may need to manually extract the Three.js scene setup first.\r\n\r\n## Related\r\n\r\n- [External Libraries](/native/external-libraries) — detailed guide for using Three.js and other libraries in Viji\r\n- [Prompt: Native Scenes](/ai-prompts/native-prompt) — AI prompt for creating new native scenes from scratch\r\n- [Native Quick Start](/native/quickstart) — your first Viji native scene"
|
|
1032
|
+
"markdown": "# Convert: Three.js to Viji\r\n\r\nCopy the prompt below and paste it into your AI assistant along with the Three.js code you want to convert. The prompt contains all the rules the AI needs to produce a correct Viji native scene with Three.js.\r\n\r\n## The Prompt\r\n\r\n````\r\nYou are converting a standalone Three.js application into a Viji native scene.\r\nViji scenes run inside an OffscreenCanvas Web Worker. Apply every rule below exactly.\r\n\r\n## RULES\r\n\r\n1. ALWAYS import Three.js dynamically at the top level using `await import()`:\r\n ```javascript\r\n const THREE = await import('https://esm.sh/three@0.160.0');\r\n ```\r\n NEVER use `<script>` tags, `require()`, or static `import` statements.\r\n ALWAYS pin the version number in the URL.\r\n\r\n2. ALWAYS use `viji.canvas` as the renderer's canvas:\r\n ```javascript\r\n const renderer = new THREE.WebGLRenderer({ canvas: viji.canvas, antialias: true });\r\n renderer.setSize(viji.width, viji.height, false);\r\n ```\r\n ALWAYS pass `false` as the third argument to `setSize()` — this prevents Three.js from setting CSS styles, which would fail in the worker.\r\n\r\n3. NEVER use `requestAnimationFrame()`. Viji controls the render loop. Write all per-frame logic inside `function render(viji) { ... }` and call `renderer.render(scene, camera)` at the end.\r\n\r\n4. ALWAYS handle resize by checking `viji.width` / `viji.height` in `render()`:\r\n ```javascript\r\n let prevWidth = viji.width;\r\n let prevHeight = viji.height;\r\n\r\n function render(viji) {\r\n if (viji.width !== prevWidth || viji.height !== prevHeight) {\r\n renderer.setSize(viji.width, viji.height, false);\r\n camera.aspect = viji.width / viji.height;\r\n camera.updateProjectionMatrix();\r\n prevWidth = viji.width;\r\n prevHeight = viji.height;\r\n }\r\n renderer.render(scene, camera);\r\n }\r\n ```\r\n\r\n5. NEVER access `window`, `document`, `Image()`, or `localStorage`. `fetch()` IS available.\r\n\r\n6. NEVER use `window.innerWidth` / `window.innerHeight`. Use `viji.width` / `viji.height`.\r\n\r\n7. Replace hardcoded values with Viji parameters declared at the top level:\r\n ```javascript\r\n const speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\r\n const color = viji.color('#049ef4', { label: 'Color' });\r\n ```\r\n NEVER declare parameters inside `render()`.\r\n ALWAYS read via `.value`: `speed.value`, `color.value`.\r\n\r\n8. ALWAYS use `viji.deltaTime` for animation timing:\r\n ```javascript\r\n cube.rotation.y += speed.value * viji.deltaTime;\r\n ```\r\n NEVER use `clock.getDelta()` or `Date.now()`. Remove any `THREE.Clock` usage.\r\n NEVER multiply `viji.time` by a parameter (`viji.time * speed.value`) — it causes animation jumps when the parameter changes. Same for nested multiplications: never multiply an accumulator by another parameter; give each speed its own accumulator.\r\n\r\n9. Replace mouse/keyboard event listeners with Viji APIs:\r\n - `event.clientX` → `viji.pointer.x` (works for both mouse and touch) or `viji.mouse.x`\r\n - `event.clientY` → `viji.pointer.y` or `viji.mouse.y`\r\n - Mouse buttons → `viji.mouse.leftButton`, `viji.mouse.rightButton`\r\n - Key presses → `viji.keyboard.isPressed('keyName')`\r\n\r\n10. `OrbitControls` and other controls that depend on DOM events will NOT work in the worker.\r\n For camera interaction, read `viji.pointer` (handles both mouse and touch) and update the camera manually.\r\n\r\n11. For Three.js addons, import from the examples directory:\r\n ```javascript\r\n const { GLTFLoader } = await import('https://esm.sh/three@0.160.0/examples/jsm/loaders/GLTFLoader.js');\r\n const { EffectComposer } = await import('https://esm.sh/three@0.160.0/examples/jsm/postprocessing/EffectComposer.js');\r\n ```\r\n ALWAYS use the same Three.js version for addons as for the main library.\r\n\r\n12. For textures from file inputs, use Viji's image parameters:\r\n ```javascript\r\n const photo = viji.image(null, { label: 'Texture' });\r\n // In render():\r\n if (photo.value && !texture) {\r\n texture = new THREE.CanvasTexture(photo.value);\r\n material.map = texture;\r\n material.needsUpdate = true;\r\n }\r\n ```\r\n\r\n13. For video textures, use `viji.video`:\r\n ```javascript\r\n if (viji.video.isConnected && viji.video.currentFrame) {\r\n if (!videoTexture) {\r\n videoTexture = new THREE.CanvasTexture(viji.video.currentFrame);\r\n material.map = videoTexture;\r\n }\r\n videoTexture.needsUpdate = true;\r\n }\r\n ```\r\n\r\n14. NEVER allocate new objects inside `render()`. Pre-create vectors, colors, and materials at the top level.\r\n\r\n15. ALWAYS set `category` on parameters that depend on an external input: `category: 'audio'` for audio, `category: 'video'` for video/CV, `category: 'interaction'` for mouse/keyboard/touch. This lets the host hide irrelevant controls when the input is inactive.\r\n\r\n16. Remove any `window.addEventListener('resize', ...)` — resize is handled in `render()` (see rule 4).\r\n\r\n16. Remove any CSS, HTML, or DOM manipulation code. Viji scenes produce only canvas output.\r\n\r\n## PARAMETER TYPES\r\n\r\n```javascript\r\nviji.slider(default, { min, max, step, label, group, category }) // { value: number }\r\nviji.color(default, { label, group, category }) // { value: '#rrggbb' }\r\nviji.toggle(default, { label, group, category }) // { value: boolean }\r\nviji.select(default, { options: [...], label, group, category }) // { value: string }\r\nviji.number(default, { min, max, step, label, group, category }) // { value: number }\r\nviji.image(default, { label, group, category }) // { value: ImageBitmap|null }\r\nviji.button({ label, description, group, category }) // { value: boolean }\r\nviji.coordinate(defaultValue, config) // { value: { x: number, y: number } } // 2D coordinate pad, both -1 to 1\r\n```\r\n\r\n## VIJI API QUICK REFERENCE\r\n\r\n- `viji.canvas` — the OffscreenCanvas (pass to Three.js renderer)\r\n- `viji.width`, `viji.height` — current canvas dimensions\r\n- `viji.time` — elapsed seconds since scene start\r\n- `viji.deltaTime` — seconds since last frame\r\n- `viji.pointer.x`, `.y`, `.isDown`, `.deltaX`, `.deltaY` — unified mouse/touch input\r\n- `viji.mouse.x`, `.y`, `.isPressed`, `.leftButton`, `.rightButton`, `.wheelDelta`\r\n- `viji.keyboard.isPressed('key')`, `.lastKeyPressed`\r\n- `viji.audio.isConnected`, `.volume.current`, `.bands.low/mid/high`, `.beat.kick/snare/hat`\r\n- `viji.video.isConnected`, `.currentFrame`\r\n\r\n## TEMPLATE\r\n\r\n```javascript\r\nconst THREE = await import('https://esm.sh/three@0.160.0');\r\n\r\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\r\nconst color = viji.color('#049ef4', { label: 'Color' });\r\n\r\nconst scene = new THREE.Scene();\r\nconst camera = new THREE.PerspectiveCamera(60, viji.width / viji.height, 0.1, 100);\r\ncamera.position.set(0, 1, 3);\r\ncamera.lookAt(0, 0, 0);\r\n\r\nconst renderer = new THREE.WebGLRenderer({ canvas: viji.canvas, antialias: true });\r\nrenderer.setSize(viji.width, viji.height, false);\r\n\r\nconst geometry = new THREE.BoxGeometry();\r\nconst material = new THREE.MeshStandardMaterial({ color: color.value });\r\nconst mesh = new THREE.Mesh(geometry, material);\r\nscene.add(mesh);\r\n\r\nscene.add(new THREE.DirectionalLight(0xffffff, 1.5));\r\nscene.add(new THREE.AmbientLight(0x404040));\r\n\r\nlet prevWidth = viji.width;\r\nlet prevHeight = viji.height;\r\n\r\nfunction render(viji) {\r\n mesh.rotation.y += speed.value * viji.deltaTime;\r\n material.color.set(color.value);\r\n\r\n if (viji.width !== prevWidth || viji.height !== prevHeight) {\r\n renderer.setSize(viji.width, viji.height, false);\r\n camera.aspect = viji.width / viji.height;\r\n camera.updateProjectionMatrix();\r\n prevWidth = viji.width;\r\n prevHeight = viji.height;\r\n }\r\n\r\n renderer.render(scene, camera);\r\n}\r\n```\r\n\r\nNow convert the Three.js code I provide. Return ONLY the converted Viji scene code.\r\n````\r\n\r\n## Usage\r\n\r\n1. Copy the entire prompt block above.\r\n2. Paste it into your AI assistant.\r\n3. After the prompt, paste the Three.js code you want to convert.\r\n4. The AI will return a Viji-compatible native scene.\r\n\r\n> [!NOTE]\r\n> This prompt handles standard Three.js scenes. If the original code uses a framework (React Three Fiber, Drei, etc.), you may need to manually extract the Three.js scene setup first.\r\n\r\n## Related\r\n\r\n- [External Libraries](/native/external-libraries) — detailed guide for using Three.js and other libraries in Viji\r\n- [Prompt: Native Scenes](/ai-prompts/native-prompt) — AI prompt for creating new native scenes from scratch\r\n- [Native Quick Start](/native/quickstart) — your first Viji native scene"
|
|
1018
1033
|
}
|
|
1019
1034
|
]
|
|
1020
1035
|
},
|
|
@@ -1056,7 +1071,7 @@ export const docsApi = {
|
|
|
1056
1071
|
"content": [
|
|
1057
1072
|
{
|
|
1058
1073
|
"type": "text",
|
|
1059
|
-
"markdown": "# API Reference\n\nThis page lists every property and method available on the `viji` object passed to your scene functions. Use it as a quick lookup — each entry links to its dedicated documentation page for full details, examples, and patterns.\n\nNew to Viji? Start with the [Quick Start](/native/quickstart) instead.\n\n## Entry Points\n\n```javascript\n// Top-level code runs once (initialization, parameters, state, imports)\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nlet angle = 0;\n\nfunction render(viji) {\n // Called every frame — this is where you draw\n}\n```\n\nThere is no `setup()` function in native scenes. All initialization goes at the top level. Top-level `await` is supported for dynamic imports.\n\n## Canvas & Context\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.canvas`](/native/canvas-context) | `OffscreenCanvas` | The rendering canvas | [Canvas & Context](/native/canvas-context) |\n| [`viji.ctx`](/native/canvas-context) | `OffscreenCanvasRenderingContext2D` | 2D context (after `useContext('2d')`) | [Canvas & Context](/native/canvas-context) |\n| [`viji.gl`](/native/canvas-context) | `WebGLRenderingContext \\| WebGL2RenderingContext` | WebGL context (after `useContext('webgl'\\|'webgl2')`) | [Canvas & Context](/native/canvas-context) |\n| [`viji.width`](/native/canvas-context) | `number` | Canvas width in pixels | [Canvas & Context](/native/canvas-context) |\n| [`viji.height`](/native/canvas-context) | `number` | Canvas height in pixels | [Canvas & Context](/native/canvas-context) |\n| [`viji.useContext(type)`](/native/canvas-context) | `Method` | Request a rendering context: `'2d'`, `'webgl'`, `'webgl2'` | [Canvas & Context](/native/canvas-context) |\n\n## Timing\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.time`](/native/timing) | `number` | Seconds elapsed since the scene started | [Timing](/native/timing) |\n| [`viji.deltaTime`](/native/timing) | `number` | Seconds since the previous frame | [Timing](/native/timing) |\n| [`viji.frameCount`](/native/timing) | `number` | Monotonically increasing frame counter | [Timing](/native/timing) |\n| [`viji.fps`](/native/timing) | `number` | Target FPS based on the host's frame rate mode | [Timing](/native/timing) |\n\n## Parameters\n\nAll parameter methods are called at the top level of your scene file. Read `.value` inside `render()` to get the current value.\n\n| Method | Returns | `.value` Type | Details |\n|--------|---------|---------------|---------|\n| [`viji.slider(default, config)`](/native/parameters/slider) | `SliderParameter` | `number` | [Slider](/native/parameters/slider) |\n| [`viji.color(default, config)`](/native/parameters/color) | `ColorParameter` | `string` (hex) | [Color](/native/parameters/color) |\n| [`viji.toggle(default, config)`](/native/parameters/toggle) | `ToggleParameter` | `boolean` | [Toggle](/native/parameters/toggle) |\n| [`viji.select(default, config)`](/native/parameters/select) | `SelectParameter` | `string \\| number` | [Select](/native/parameters/select) |\n| [`viji.number(default, config)`](/native/parameters/number) | `NumberParameter` | `number` | [Number](/native/parameters/number) |\n| [`viji.text(default, config)`](/native/parameters/text) | `TextParameter` | `string` | [Text](/native/parameters/text) |\n| [`viji.image(null, config)`](/native/parameters/image) | `ImageParameter` | `ImageBitmap \\| null` | [Image](/native/parameters/image) |\n| [`viji.button(config)`](/native/parameters/button) | `ButtonParameter` | `boolean` (true for one frame) | [Button](/native/parameters/button) |\n\nSee [Parameters Overview](/native/parameters) for the declaration pattern, [Grouping](/native/parameters/grouping) and [Categories](/native/parameters/categories) for organization.\n\n## Audio\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.audio.isConnected`](/native/audio) | `boolean` | Whether an audio source is active | [Overview](/native/audio) |\n| [`viji.audio.volume.current`](/native/audio/volume) | `number` | Current RMS volume 0–1 | [Volume](/native/audio/volume) |\n| [`viji.audio.volume.peak`](/native/audio/volume) | `number` | Peak volume 0–1 | [Volume](/native/audio/volume) |\n| [`viji.audio.volume.smoothed`](/native/audio/volume) | `number` | Smoothed volume 0–1 | [Volume](/native/audio/volume) |\n| [`viji.audio.bands.low`](/native/audio/bands) | `number` | Low frequency band energy (20–120 Hz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.lowMid`](/native/audio/bands) | `number` | Low-mid band energy (120–500 Hz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.mid`](/native/audio/bands) | `number` | Mid band energy (500–2 kHz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.highMid`](/native/audio/bands) | `number` | High-mid band energy (2–6 kHz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.high`](/native/audio/bands) | `number` | High band energy (6–16 kHz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.lowSmoothed`](/native/audio/bands) | `number` | Smoothed low band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.lowMidSmoothed`](/native/audio/bands) | `number` | Smoothed low-mid band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.midSmoothed`](/native/audio/bands) | `number` | Smoothed mid band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.highMidSmoothed`](/native/audio/bands) | `number` | Smoothed high-mid band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.highSmoothed`](/native/audio/bands) | `number` | Smoothed high band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.beat.kick`](/native/audio/beat) | `number` | Kick beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.snare`](/native/audio/beat) | `number` | Snare beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.hat`](/native/audio/beat) | `number` | Hi-hat beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.any`](/native/audio/beat) | `number` | Combined beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.kickSmoothed`](/native/audio/beat) | `number` | Smoothed kick | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.snareSmoothed`](/native/audio/beat) | `number` | Smoothed snare | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.hatSmoothed`](/native/audio/beat) | `number` | Smoothed hi-hat | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.anySmoothed`](/native/audio/beat) | `number` | Smoothed combined | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.kick`](/native/audio/beat) | `boolean` | Kick trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.snare`](/native/audio/beat) | `boolean` | Snare trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.hat`](/native/audio/beat) | `boolean` | Hi-hat trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.any`](/native/audio/beat) | `boolean` | Any beat trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.events`](/native/audio/beat) | `Array<{ type, time, strength }>` | Beat events this frame | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.bpm`](/native/audio/beat) | `number` | Tracked BPM | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.confidence`](/native/audio/beat) | `number` | Beat-tracker confidence 0–1 | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.isLocked`](/native/audio/beat) | `boolean` | Whether beat tracking is locked | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.spectral.brightness`](/native/audio/spectral) | `number` | Spectral brightness 0–1 | [Spectral Analysis](/native/audio/spectral) |\n| [`viji.audio.spectral.flatness`](/native/audio/spectral) | `number` | Spectral flatness 0–1 | [Spectral Analysis](/native/audio/spectral) |\n| [`viji.audio.getFrequencyData()`](/native/audio/frequency-data) | `() => Uint8Array` | Raw FFT frequency bins (0–255) | [Frequency Data](/native/audio/frequency-data) |\n| [`viji.audio.getWaveform()`](/native/audio/waveform) | `() => Float32Array` | Time-domain waveform (-1 to 1) | [Waveform](/native/audio/waveform) |\n\n## Video & CV\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.video.isConnected`](/native/video) | `boolean` | Whether a video source is active | [Overview](/native/video) |\n| [`viji.video.currentFrame`](/native/video/basics) | `OffscreenCanvas \\| ImageBitmap \\| null` | Current video frame | [Video Basics](/native/video/basics) |\n| [`viji.video.frameWidth`](/native/video/basics) | `number` | Frame width in pixels | [Video Basics](/native/video/basics) |\n| [`viji.video.frameHeight`](/native/video/basics) | `number` | Frame height in pixels | [Video Basics](/native/video/basics) |\n| [`viji.video.frameRate`](/native/video/basics) | `number` | Video frame rate | [Video Basics](/native/video/basics) |\n| [`viji.video.getFrameData()`](/native/video/basics) | `() => ImageData \\| null` | Pixel data for the current frame | [Video Basics](/native/video/basics) |\n| [`viji.video.faces`](/native/video/face-detection) | `FaceData[]` | Detected faces | [Face Detection](/native/video/face-detection) |\n| [`viji.video.hands`](/native/video/hand-tracking) | `HandData[]` | Detected hands | [Hand Tracking](/native/video/hand-tracking) |\n| [`viji.video.pose`](/native/video/pose-detection) | `PoseData \\| null` | Detected body pose | [Pose Detection](/native/video/pose-detection) |\n| [`viji.video.segmentation`](/native/video/body-segmentation) | `SegmentationData \\| null` | Body segmentation mask | [Body Segmentation](/native/video/body-segmentation) |\n| [`viji.video.cv.enableFaceDetection(enabled)`](/native/video/face-detection) | `(boolean) => Promise<void>` | Enable/disable face detection | [Face Detection](/native/video/face-detection) |\n| [`viji.video.cv.enableFaceMesh(enabled)`](/native/video/face-mesh) | `(boolean) => Promise<void>` | Enable/disable face mesh | [Face Mesh](/native/video/face-mesh) |\n| [`viji.video.cv.enableEmotionDetection(enabled)`](/native/video/emotion-detection) | `(boolean) => Promise<void>` | Enable/disable emotion detection | [Emotion Detection](/native/video/emotion-detection) |\n| [`viji.video.cv.enableHandTracking(enabled)`](/native/video/hand-tracking) | `(boolean) => Promise<void>` | Enable/disable hand tracking | [Hand Tracking](/native/video/hand-tracking) |\n| [`viji.video.cv.enablePoseDetection(enabled)`](/native/video/pose-detection) | `(boolean) => Promise<void>` | Enable/disable pose detection | [Pose Detection](/native/video/pose-detection) |\n| [`viji.video.cv.enableBodySegmentation(enabled)`](/native/video/body-segmentation) | `(boolean) => Promise<void>` | Enable/disable body segmentation | [Body Segmentation](/native/video/body-segmentation) |\n| [`viji.video.cv.getActiveFeatures()`](/native/video) | `() => CVFeature[]` | List of active CV features | [Overview](/native/video) |\n| [`viji.video.cv.isProcessing()`](/native/video) | `() => boolean` | Whether CV is currently processing | [Overview](/native/video) |\n\n## Mouse\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.mouse.x`](/native/mouse) | `number` | Cursor X position in pixels | [Mouse](/native/mouse) |\n| [`viji.mouse.y`](/native/mouse) | `number` | Cursor Y position in pixels | [Mouse](/native/mouse) |\n| [`viji.mouse.isInCanvas`](/native/mouse) | `boolean` | Whether cursor is inside the canvas | [Mouse](/native/mouse) |\n| [`viji.mouse.isPressed`](/native/mouse) | `boolean` | Whether any button is pressed | [Mouse](/native/mouse) |\n| [`viji.mouse.leftButton`](/native/mouse) | `boolean` | Left button state | [Mouse](/native/mouse) |\n| [`viji.mouse.rightButton`](/native/mouse) | `boolean` | Right button state | [Mouse](/native/mouse) |\n| [`viji.mouse.middleButton`](/native/mouse) | `boolean` | Middle button state | [Mouse](/native/mouse) |\n| [`viji.mouse.deltaX`](/native/mouse) | `number` | Horizontal movement since last frame | [Mouse](/native/mouse) |\n| [`viji.mouse.deltaY`](/native/mouse) | `number` | Vertical movement since last frame | [Mouse](/native/mouse) |\n| [`viji.mouse.wheelDelta`](/native/mouse) | `number` | Scroll wheel delta | [Mouse](/native/mouse) |\n| [`viji.mouse.wheelX`](/native/mouse) | `number` | Horizontal scroll delta | [Mouse](/native/mouse) |\n| [`viji.mouse.wheelY`](/native/mouse) | `number` | Vertical scroll delta | [Mouse](/native/mouse) |\n| [`viji.mouse.wasPressed`](/native/mouse) | `boolean` | True for one frame when pressed | [Mouse](/native/mouse) |\n| [`viji.mouse.wasReleased`](/native/mouse) | `boolean` | True for one frame when released | [Mouse](/native/mouse) |\n| [`viji.mouse.wasMoved`](/native/mouse) | `boolean` | True for one frame when moved | [Mouse](/native/mouse) |\n\n## Keyboard\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.keyboard.isPressed(key)`](/native/keyboard) | `(string) => boolean` | Whether a key is currently held | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.wasPressed(key)`](/native/keyboard) | `(string) => boolean` | True for one frame when pressed | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.wasReleased(key)`](/native/keyboard) | `(string) => boolean` | True for one frame when released | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.activeKeys`](/native/keyboard) | `Set<string>` | All currently held keys | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.pressedThisFrame`](/native/keyboard) | `Set<string>` | Keys pressed this frame | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.releasedThisFrame`](/native/keyboard) | `Set<string>` | Keys released this frame | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.lastKeyPressed`](/native/keyboard) | `string` | Most recently pressed key | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.lastKeyReleased`](/native/keyboard) | `string` | Most recently released key | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.shift`](/native/keyboard) | `boolean` | Shift key state | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.ctrl`](/native/keyboard) | `boolean` | Ctrl/Cmd key state | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.alt`](/native/keyboard) | `boolean` | Alt/Option key state | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.meta`](/native/keyboard) | `boolean` | Meta/Win key state | [Keyboard](/native/keyboard) |\n\n## Touch\n\n> **Note:** The property is `viji.touches` (plural), not `viji.touch`.\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.touches.points`](/native/touch) | `TouchPoint[]` | All active touch points | [Touch](/native/touch) |\n| [`viji.touches.count`](/native/touch) | `number` | Number of active touches | [Touch](/native/touch) |\n| [`viji.touches.started`](/native/touch) | `TouchPoint[]` | Touch points that started this frame | [Touch](/native/touch) |\n| [`viji.touches.moved`](/native/touch) | `TouchPoint[]` | Touch points that moved this frame | [Touch](/native/touch) |\n| [`viji.touches.ended`](/native/touch) | `TouchPoint[]` | Touch points that ended this frame | [Touch](/native/touch) |\n| [`viji.touches.primary`](/native/touch) | `TouchPoint \\| null` | The first active touch point | [Touch](/native/touch) |\n\n**`TouchPoint` fields:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force` (numbers); `isInCanvas`, `isNew`, `isActive`, `isEnding` (booleans); `deltaX`, `deltaY` (numbers); `velocity` `{ x, y }`.\n\n## Pointer (Unified)\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.pointer.x`](/native/pointer) | `number` | Primary pointer X position | [Pointer](/native/pointer) |\n| [`viji.pointer.y`](/native/pointer) | `number` | Primary pointer Y position | [Pointer](/native/pointer) |\n| [`viji.pointer.deltaX`](/native/pointer) | `number` | Horizontal movement since last frame | [Pointer](/native/pointer) |\n| [`viji.pointer.deltaY`](/native/pointer) | `number` | Vertical movement since last frame | [Pointer](/native/pointer) |\n| [`viji.pointer.isDown`](/native/pointer) | `boolean` | Whether the pointer is active (click or touch) | [Pointer](/native/pointer) |\n| [`viji.pointer.wasPressed`](/native/pointer) | `boolean` | True for one frame when pressed | [Pointer](/native/pointer) |\n| [`viji.pointer.wasReleased`](/native/pointer) | `boolean` | True for one frame when released | [Pointer](/native/pointer) |\n| [`viji.pointer.isInCanvas`](/native/pointer) | `boolean` | Whether pointer is inside the canvas | [Pointer](/native/pointer) |\n| [`viji.pointer.type`](/native/pointer) | `'mouse' \\| 'touch' \\| 'none'` | Current input source | [Pointer](/native/pointer) |\n\n## Device Sensors\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.device.motion`](/native/sensors) | `DeviceMotionData \\| null` | Accelerometer and gyroscope data | [Device Sensors](/native/sensors) |\n| [`viji.device.orientation`](/native/sensors) | `DeviceOrientationData \\| null` | Device orientation (alpha, beta, gamma) | [Device Sensors](/native/sensors) |\n\n**`DeviceMotionData`:** `acceleration` `{ x, y, z }`, `accelerationIncludingGravity` `{ x, y, z }`, `rotationRate` `{ alpha, beta, gamma }`, `interval`.\n\n**`DeviceOrientationData`:** `alpha`, `beta`, `gamma` (numbers or null), `absolute` (boolean).\n\n## External Devices\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.devices`](/native/external-devices) | `DeviceState[]` | Connected external devices | [Overview](/native/external-devices) |\n| [`viji.devices[i].id`](/native/external-devices) | `string` | Unique device identifier | [Overview](/native/external-devices) |\n| [`viji.devices[i].name`](/native/external-devices) | `string` | User-friendly device name | [Overview](/native/external-devices) |\n| [`viji.devices[i].motion`](/native/external-devices/sensors) | `DeviceMotionData \\| null` | Device accelerometer/gyroscope | [Device Sensors](/native/external-devices/sensors) |\n| [`viji.devices[i].orientation`](/native/external-devices/sensors) | `DeviceOrientationData \\| null` | Device orientation | [Device Sensors](/native/external-devices/sensors) |\n| [`viji.devices[i].video`](/native/external-devices/video) | `VideoAPI \\| null` | Device camera video | [Device Video](/native/external-devices/video) |\n| [`viji.devices[i].audio`](/native/external-devices/audio) | `AudioStreamAPI \\| null` | Device audio stream | [Device Audio](/native/external-devices/audio) |\n\n## Streams\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.videoStreams` | `VideoAPI[]` | Additional video streams provided by the host |\n| `viji.audioStreams` | `AudioStreamAPI[]` | Additional audio streams provided by the host |\n\nEach `videoStreams` element has the same shape as [`viji.video`](/native/video). Each `audioStreams` element provides lightweight audio analysis (volume, frequency bands, spectral features) but does **not** include beat detection or BPM tracking — see [`viji.audio`](/native/audio) for full analysis on the main stream.\n\nBoth arrays may be empty if the host does not provide additional streams. Audio streams from external devices appear on `device.audio`, not in `viji.audioStreams`.\n\n## Related\n\n- [Quick Start](/native/quickstart) — getting started with the Native renderer\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers\n- [Common Mistakes](/getting-started/common-mistakes) — pitfalls to avoid\n- [P5 API Reference](/p5/api-reference) — the same API in the P5 renderer\n- [Shader API Reference](/shader/api-reference) — built-in uniforms for shaders"
|
|
1074
|
+
"markdown": "# API Reference\n\nThis page lists every property and method available on the `viji` object passed to your scene functions. Use it as a quick lookup — each entry links to its dedicated documentation page for full details, examples, and patterns.\n\nNew to Viji? Start with the [Quick Start](/native/quickstart) instead.\n\n## Entry Points\n\n```javascript\n// Top-level code runs once (initialization, parameters, state, imports)\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nlet angle = 0;\n\nfunction render(viji) {\n // Called every frame — this is where you draw\n}\n```\n\nThere is no `setup()` function in native scenes. All initialization goes at the top level. Top-level `await` is supported for dynamic imports.\n\n## Canvas & Context\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.canvas`](/native/canvas-context) | `OffscreenCanvas` | The rendering canvas | [Canvas & Context](/native/canvas-context) |\n| [`viji.ctx`](/native/canvas-context) | `OffscreenCanvasRenderingContext2D` | 2D context (after `useContext('2d')`) | [Canvas & Context](/native/canvas-context) |\n| [`viji.gl`](/native/canvas-context) | `WebGLRenderingContext \\| WebGL2RenderingContext` | WebGL context (after `useContext('webgl'\\|'webgl2')`) | [Canvas & Context](/native/canvas-context) |\n| [`viji.width`](/native/canvas-context) | `number` | Canvas width in pixels | [Canvas & Context](/native/canvas-context) |\n| [`viji.height`](/native/canvas-context) | `number` | Canvas height in pixels | [Canvas & Context](/native/canvas-context) |\n| [`viji.useContext(type)`](/native/canvas-context) | `Method` | Request a rendering context: `'2d'`, `'webgl'`, `'webgl2'` | [Canvas & Context](/native/canvas-context) |\n\n## Timing\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.time`](/native/timing) | `number` | Seconds elapsed since the scene started | [Timing](/native/timing) |\n| [`viji.deltaTime`](/native/timing) | `number` | Seconds since the previous frame | [Timing](/native/timing) |\n| [`viji.frameCount`](/native/timing) | `number` | Monotonically increasing frame counter | [Timing](/native/timing) |\n| [`viji.fps`](/native/timing) | `number` | Target FPS based on the host's frame rate mode | [Timing](/native/timing) |\n\n## Parameters\n\nAll parameter methods are called at the top level of your scene file. Read `.value` inside `render()` to get the current value.\n\n| Method | Returns | `.value` Type | Details |\n|--------|---------|---------------|---------|\n| [`viji.slider(default, config)`](/native/parameters/slider) | `SliderParameter` | `number` | [Slider](/native/parameters/slider) |\n| [`viji.color(default, config)`](/native/parameters/color) | `ColorParameter` | `string` (hex) | [Color](/native/parameters/color) |\n| [`viji.toggle(default, config)`](/native/parameters/toggle) | `ToggleParameter` | `boolean` | [Toggle](/native/parameters/toggle) |\n| [`viji.select(default, config)`](/native/parameters/select) | `SelectParameter` | `string \\| number` | [Select](/native/parameters/select) |\n| [`viji.number(default, config)`](/native/parameters/number) | `NumberParameter` | `number` | [Number](/native/parameters/number) |\n| [`viji.text(default, config)`](/native/parameters/text) | `TextParameter` | `string` | [Text](/native/parameters/text) |\n| [`viji.image(null, config)`](/native/parameters/image) | `ImageParameter` | `ImageBitmap \\| null` | [Image](/native/parameters/image) |\n| [`viji.button(config)`](/native/parameters/button) | `ButtonParameter` | `boolean` (true for one frame) | [Button](/native/parameters/button) |\n| [`viji.coordinate(default, config)`](/native/parameters/coordinate) | `CoordinateParameter` | 2D coordinate pad — `{ x: number, y: number }`, both -1 to 1 | [Coordinate](/native/parameters/coordinate) |\n\nSee [Parameters Overview](/native/parameters) for the declaration pattern, [Grouping](/native/parameters/grouping) and [Categories](/native/parameters/categories) for organization.\n\n## Audio\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.audio.isConnected`](/native/audio) | `boolean` | Whether an audio source is active | [Overview](/native/audio) |\n| [`viji.audio.volume.current`](/native/audio/volume) | `number` | Current RMS volume 0–1 | [Volume](/native/audio/volume) |\n| [`viji.audio.volume.peak`](/native/audio/volume) | `number` | Peak volume 0–1 | [Volume](/native/audio/volume) |\n| [`viji.audio.volume.smoothed`](/native/audio/volume) | `number` | Smoothed volume 0–1 | [Volume](/native/audio/volume) |\n| [`viji.audio.bands.low`](/native/audio/bands) | `number` | Low frequency band energy (20–120 Hz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.lowMid`](/native/audio/bands) | `number` | Low-mid band energy (120–500 Hz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.mid`](/native/audio/bands) | `number` | Mid band energy (500–2 kHz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.highMid`](/native/audio/bands) | `number` | High-mid band energy (2–6 kHz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.high`](/native/audio/bands) | `number` | High band energy (6–16 kHz) | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.lowSmoothed`](/native/audio/bands) | `number` | Smoothed low band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.lowMidSmoothed`](/native/audio/bands) | `number` | Smoothed low-mid band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.midSmoothed`](/native/audio/bands) | `number` | Smoothed mid band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.highMidSmoothed`](/native/audio/bands) | `number` | Smoothed high-mid band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.bands.highSmoothed`](/native/audio/bands) | `number` | Smoothed high band | [Frequency Bands](/native/audio/bands) |\n| [`viji.audio.beat.kick`](/native/audio/beat) | `number` | Kick beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.snare`](/native/audio/beat) | `number` | Snare beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.hat`](/native/audio/beat) | `number` | Hi-hat beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.any`](/native/audio/beat) | `number` | Combined beat energy | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.kickSmoothed`](/native/audio/beat) | `number` | Smoothed kick | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.snareSmoothed`](/native/audio/beat) | `number` | Smoothed snare | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.hatSmoothed`](/native/audio/beat) | `number` | Smoothed hi-hat | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.anySmoothed`](/native/audio/beat) | `number` | Smoothed combined | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.kick`](/native/audio/beat) | `boolean` | Kick trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.snare`](/native/audio/beat) | `boolean` | Snare trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.hat`](/native/audio/beat) | `boolean` | Hi-hat trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.triggers.any`](/native/audio/beat) | `boolean` | Any beat trigger (true for one frame) | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.events`](/native/audio/beat) | `Array<{ type, time, strength }>` | Beat events this frame | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.bpm`](/native/audio/beat) | `number` | Tracked BPM | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.confidence`](/native/audio/beat) | `number` | Beat-tracker confidence 0–1 | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.beat.isLocked`](/native/audio/beat) | `boolean` | Whether beat tracking is locked | [Beat Detection](/native/audio/beat) |\n| [`viji.audio.spectral.brightness`](/native/audio/spectral) | `number` | Spectral brightness 0–1 | [Spectral Analysis](/native/audio/spectral) |\n| [`viji.audio.spectral.flatness`](/native/audio/spectral) | `number` | Spectral flatness 0–1 | [Spectral Analysis](/native/audio/spectral) |\n| [`viji.audio.getFrequencyData()`](/native/audio/frequency-data) | `() => Uint8Array` | Raw FFT frequency bins (0–255) | [Frequency Data](/native/audio/frequency-data) |\n| [`viji.audio.getWaveform()`](/native/audio/waveform) | `() => Float32Array` | Time-domain waveform (-1 to 1) | [Waveform](/native/audio/waveform) |\n\n## Video & CV\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.video.isConnected`](/native/video) | `boolean` | Whether a video source is active | [Overview](/native/video) |\n| [`viji.video.currentFrame`](/native/video/basics) | `OffscreenCanvas \\| ImageBitmap \\| null` | Current video frame | [Video Basics](/native/video/basics) |\n| [`viji.video.frameWidth`](/native/video/basics) | `number` | Frame width in pixels | [Video Basics](/native/video/basics) |\n| [`viji.video.frameHeight`](/native/video/basics) | `number` | Frame height in pixels | [Video Basics](/native/video/basics) |\n| [`viji.video.frameRate`](/native/video/basics) | `number` | Video frame rate | [Video Basics](/native/video/basics) |\n| [`viji.video.getFrameData()`](/native/video/basics) | `() => ImageData \\| null` | Pixel data for the current frame | [Video Basics](/native/video/basics) |\n| [`viji.video.faces`](/native/video/face-detection) | `FaceData[]` | Detected faces | [Face Detection](/native/video/face-detection) |\n| [`viji.video.hands`](/native/video/hand-tracking) | `HandData[]` | Detected hands | [Hand Tracking](/native/video/hand-tracking) |\n| [`viji.video.pose`](/native/video/pose-detection) | `PoseData \\| null` | Detected body pose | [Pose Detection](/native/video/pose-detection) |\n| [`viji.video.segmentation`](/native/video/body-segmentation) | `SegmentationData \\| null` | Body segmentation mask | [Body Segmentation](/native/video/body-segmentation) |\n| [`viji.video.cv.enableFaceDetection(enabled)`](/native/video/face-detection) | `(boolean) => Promise<void>` | Enable/disable face detection | [Face Detection](/native/video/face-detection) |\n| [`viji.video.cv.enableFaceMesh(enabled)`](/native/video/face-mesh) | `(boolean) => Promise<void>` | Enable/disable face mesh | [Face Mesh](/native/video/face-mesh) |\n| [`viji.video.cv.enableEmotionDetection(enabled)`](/native/video/emotion-detection) | `(boolean) => Promise<void>` | Enable/disable emotion detection | [Emotion Detection](/native/video/emotion-detection) |\n| [`viji.video.cv.enableHandTracking(enabled)`](/native/video/hand-tracking) | `(boolean) => Promise<void>` | Enable/disable hand tracking | [Hand Tracking](/native/video/hand-tracking) |\n| [`viji.video.cv.enablePoseDetection(enabled)`](/native/video/pose-detection) | `(boolean) => Promise<void>` | Enable/disable pose detection | [Pose Detection](/native/video/pose-detection) |\n| [`viji.video.cv.enableBodySegmentation(enabled)`](/native/video/body-segmentation) | `(boolean) => Promise<void>` | Enable/disable body segmentation | [Body Segmentation](/native/video/body-segmentation) |\n| [`viji.video.cv.getActiveFeatures()`](/native/video) | `() => CVFeature[]` | List of active CV features | [Overview](/native/video) |\n| [`viji.video.cv.isProcessing()`](/native/video) | `() => boolean` | Whether CV is currently processing | [Overview](/native/video) |\n\n## Mouse\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.mouse.x`](/native/mouse) | `number` | Cursor X position in pixels | [Mouse](/native/mouse) |\n| [`viji.mouse.y`](/native/mouse) | `number` | Cursor Y position in pixels | [Mouse](/native/mouse) |\n| [`viji.mouse.isInCanvas`](/native/mouse) | `boolean` | Whether cursor is inside the canvas | [Mouse](/native/mouse) |\n| [`viji.mouse.isPressed`](/native/mouse) | `boolean` | Whether any button is pressed | [Mouse](/native/mouse) |\n| [`viji.mouse.leftButton`](/native/mouse) | `boolean` | Left button state | [Mouse](/native/mouse) |\n| [`viji.mouse.rightButton`](/native/mouse) | `boolean` | Right button state | [Mouse](/native/mouse) |\n| [`viji.mouse.middleButton`](/native/mouse) | `boolean` | Middle button state | [Mouse](/native/mouse) |\n| [`viji.mouse.deltaX`](/native/mouse) | `number` | Horizontal movement since last frame | [Mouse](/native/mouse) |\n| [`viji.mouse.deltaY`](/native/mouse) | `number` | Vertical movement since last frame | [Mouse](/native/mouse) |\n| [`viji.mouse.wheelDelta`](/native/mouse) | `number` | Scroll wheel delta | [Mouse](/native/mouse) |\n| [`viji.mouse.wheelX`](/native/mouse) | `number` | Horizontal scroll delta | [Mouse](/native/mouse) |\n| [`viji.mouse.wheelY`](/native/mouse) | `number` | Vertical scroll delta | [Mouse](/native/mouse) |\n| [`viji.mouse.wasPressed`](/native/mouse) | `boolean` | True for one frame when pressed | [Mouse](/native/mouse) |\n| [`viji.mouse.wasReleased`](/native/mouse) | `boolean` | True for one frame when released | [Mouse](/native/mouse) |\n| [`viji.mouse.wasMoved`](/native/mouse) | `boolean` | True for one frame when moved | [Mouse](/native/mouse) |\n\n## Keyboard\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.keyboard.isPressed(key)`](/native/keyboard) | `(string) => boolean` | Whether a key is currently held | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.wasPressed(key)`](/native/keyboard) | `(string) => boolean` | True for one frame when pressed | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.wasReleased(key)`](/native/keyboard) | `(string) => boolean` | True for one frame when released | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.activeKeys`](/native/keyboard) | `Set<string>` | All currently held keys | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.pressedThisFrame`](/native/keyboard) | `Set<string>` | Keys pressed this frame | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.releasedThisFrame`](/native/keyboard) | `Set<string>` | Keys released this frame | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.lastKeyPressed`](/native/keyboard) | `string` | Most recently pressed key | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.lastKeyReleased`](/native/keyboard) | `string` | Most recently released key | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.shift`](/native/keyboard) | `boolean` | Shift key state | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.ctrl`](/native/keyboard) | `boolean` | Ctrl/Cmd key state | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.alt`](/native/keyboard) | `boolean` | Alt/Option key state | [Keyboard](/native/keyboard) |\n| [`viji.keyboard.meta`](/native/keyboard) | `boolean` | Meta/Win key state | [Keyboard](/native/keyboard) |\n\n## Touch\n\n> **Note:** The property is `viji.touches` (plural), not `viji.touch`.\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.touches.points`](/native/touch) | `TouchPoint[]` | All active touch points | [Touch](/native/touch) |\n| [`viji.touches.count`](/native/touch) | `number` | Number of active touches | [Touch](/native/touch) |\n| [`viji.touches.started`](/native/touch) | `TouchPoint[]` | Touch points that started this frame | [Touch](/native/touch) |\n| [`viji.touches.moved`](/native/touch) | `TouchPoint[]` | Touch points that moved this frame | [Touch](/native/touch) |\n| [`viji.touches.ended`](/native/touch) | `TouchPoint[]` | Touch points that ended this frame | [Touch](/native/touch) |\n| [`viji.touches.primary`](/native/touch) | `TouchPoint \\| null` | The first active touch point | [Touch](/native/touch) |\n\n**`TouchPoint` fields:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force` (numbers); `isInCanvas`, `isNew`, `isActive`, `isEnding` (booleans); `deltaX`, `deltaY` (numbers); `velocity` `{ x, y }`.\n\n## Pointer (Unified)\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.pointer.x`](/native/pointer) | `number` | Primary pointer X position | [Pointer](/native/pointer) |\n| [`viji.pointer.y`](/native/pointer) | `number` | Primary pointer Y position | [Pointer](/native/pointer) |\n| [`viji.pointer.deltaX`](/native/pointer) | `number` | Horizontal movement since last frame | [Pointer](/native/pointer) |\n| [`viji.pointer.deltaY`](/native/pointer) | `number` | Vertical movement since last frame | [Pointer](/native/pointer) |\n| [`viji.pointer.isDown`](/native/pointer) | `boolean` | Whether the pointer is active (click or touch) | [Pointer](/native/pointer) |\n| [`viji.pointer.wasPressed`](/native/pointer) | `boolean` | True for one frame when pressed | [Pointer](/native/pointer) |\n| [`viji.pointer.wasReleased`](/native/pointer) | `boolean` | True for one frame when released | [Pointer](/native/pointer) |\n| [`viji.pointer.isInCanvas`](/native/pointer) | `boolean` | Whether pointer is inside the canvas | [Pointer](/native/pointer) |\n| [`viji.pointer.type`](/native/pointer) | `'mouse' \\| 'touch' \\| 'none'` | Current input source | [Pointer](/native/pointer) |\n\n## Device Sensors\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.device.motion`](/native/sensors) | `DeviceMotionData \\| null` | Accelerometer and gyroscope data | [Device Sensors](/native/sensors) |\n| [`viji.device.orientation`](/native/sensors) | `DeviceOrientationData \\| null` | Device orientation (alpha, beta, gamma) | [Device Sensors](/native/sensors) |\n\n**`DeviceMotionData`:** `acceleration` `{ x, y, z }`, `accelerationIncludingGravity` `{ x, y, z }`, `rotationRate` `{ alpha, beta, gamma }`, `interval`.\n\n**`DeviceOrientationData`:** `alpha`, `beta`, `gamma` (numbers or null), `absolute` (boolean).\n\n## External Devices\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.devices`](/native/external-devices) | `DeviceState[]` | Connected external devices | [Overview](/native/external-devices) |\n| [`viji.devices[i].id`](/native/external-devices) | `string` | Unique device identifier | [Overview](/native/external-devices) |\n| [`viji.devices[i].name`](/native/external-devices) | `string` | User-friendly device name | [Overview](/native/external-devices) |\n| [`viji.devices[i].motion`](/native/external-devices/sensors) | `DeviceMotionData \\| null` | Device accelerometer/gyroscope | [Device Sensors](/native/external-devices/sensors) |\n| [`viji.devices[i].orientation`](/native/external-devices/sensors) | `DeviceOrientationData \\| null` | Device orientation | [Device Sensors](/native/external-devices/sensors) |\n| [`viji.devices[i].video`](/native/external-devices/video) | `VideoAPI \\| null` | Device camera video | [Device Video](/native/external-devices/video) |\n| [`viji.devices[i].audio`](/native/external-devices/audio) | `AudioStreamAPI \\| null` | Device audio stream | [Device Audio](/native/external-devices/audio) |\n\n## Streams\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.videoStreams` | `VideoAPI[]` | Additional video streams provided by the host |\n| `viji.audioStreams` | `AudioStreamAPI[]` | Additional audio streams provided by the host |\n\nEach `videoStreams` element has the same shape as [`viji.video`](/native/video). Each `audioStreams` element provides lightweight audio analysis (volume, frequency bands, spectral features) but does **not** include beat detection or BPM tracking — see [`viji.audio`](/native/audio) for full analysis on the main stream.\n\nBoth arrays may be empty if the host does not provide additional streams. Audio streams from external devices appear on `device.audio`, not in `viji.audioStreams`.\n\n## Related\n\n- [Quick Start](/native/quickstart) — getting started with the Native renderer\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers\n- [Common Mistakes](/getting-started/common-mistakes) — pitfalls to avoid\n- [P5 API Reference](/p5/api-reference) — the same API in the P5 renderer\n- [Shader API Reference](/shader/api-reference) — built-in uniforms for shaders"
|
|
1060
1075
|
}
|
|
1061
1076
|
]
|
|
1062
1077
|
},
|
|
@@ -1150,7 +1165,7 @@ export const docsApi = {
|
|
|
1150
1165
|
"content": [
|
|
1151
1166
|
{
|
|
1152
1167
|
"type": "text",
|
|
1153
|
-
"markdown": "# Parameters\n\nParameters are the primary way to give users control over your scene. You define them at the top level of your code, and Viji renders corresponding UI controls (sliders, color pickers, toggles, etc.) in the host application. Read `.value` inside `render()` to get the current state — values update in real-time as users interact with the controls.\n\n## Parameter Types\n\n| Type | Function | Value | Use For |\n|---|---|---|---|\n| [Slider](slider/) | [`viji.slider(default, config)`](slider/) | `number` | Continuous numeric ranges (speed, size, opacity) |\n| [Number](number/) | [`viji.number(default, config)`](number/) | `number` | Precise numeric input (counts, thresholds) |\n| [Color](color/) | [`viji.color(default, config)`](color/) | `string` | Hex color values (`'#rrggbb'`) |\n| [Toggle](toggle/) | [`viji.toggle(default, config)`](toggle/) | `boolean` | On/off switches (enable audio, show trail) |\n| [Select](select/) | [`viji.select(default, config)`](select/) | `string \\| number` | Dropdown from predefined options (blend mode, shape type) |\n| [Text](text/) | [`viji.text(default, config)`](text/) | `string` | Free-form text input (titles, labels) |\n| [Image](image/) | [`viji.image(default, config)`](image/) | `ImageBitmap \\| null` | User-uploaded images and textures |\n| [Button](button/) | [`viji.button(config)`](button/) | `boolean` | Momentary trigger — true for 1 frame (resets, spawns) |\n\n## Basic Pattern\n\n```javascript\n// 1. Define at top level — runs once\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst color = viji.color('#ff6600', { label: 'Color' });\nconst mirror = viji.toggle(false, { label: 'Mirror' });\n\n// 2. Read .value in render() — updates in real-time\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n ctx.fillStyle = color.value;\n // speed.value, mirror.value, etc.\n}\n```\n\n> [!WARNING]\n> Parameters must be declared at the **top level** of your scene, never inside `render()`. They are registered once during initialization. Declaring them inside `render()` would re-register the parameter every frame, resetting its value to the default and making user changes ineffective.\n\n## Common Config Keys\n\nAll parameter types share these optional configuration keys:\n\n| Key | Type | Default | Description |\n|---|---|---|---|\n| `label` | `string` | **(required)** | Display name shown in the parameter UI |\n| `description` | `string` | — | Tooltip or help text |\n| `group` | `string` | `'general'` | Group name for organizing parameters — see [Grouping](grouping/) |\n| `category` | `ParameterCategory` | `'general'` | Controls visibility based on active capabilities — see [Categories](categories/) |\n\n## Organization\n\nAs scenes grow, you'll want to organize parameters into logical sections and control when they're visible:\n\n- **[Grouping](grouping/)** — Collect related parameters under named groups (e.g., \"animation\", \"shape\", \"audio\"). Parameters with the same `group` string appear together in the UI.\n- **[Categories](categories/)** — Tag parameters as `'general'`, `'audio'`, `'video'`, or `'interaction'` to automatically show/hide them based on what inputs are currently active.\n\n## Related\n\n- [Slider](slider/) — the most common parameter type\n- [Grouping](grouping/) — organizing parameters into named groups\n- [Categories](categories/) — visibility based on capabilities\n- [P5 Parameters](/p5/parameters) — same system in the P5 renderer\n- [Shader Parameters](/shader/parameters) — comment-directive syntax for shaders\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
1168
|
+
"markdown": "# Parameters\n\nParameters are the primary way to give users control over your scene. You define them at the top level of your code, and Viji renders corresponding UI controls (sliders, color pickers, toggles, etc.) in the host application. Read `.value` inside `render()` to get the current state — values update in real-time as users interact with the controls.\n\n## Parameter Types\n\n| Type | Function | Value | Use For |\n|---|---|---|---|\n| [Slider](slider/) | [`viji.slider(default, config)`](slider/) | `number` | Continuous numeric ranges (speed, size, opacity) |\n| [Number](number/) | [`viji.number(default, config)`](number/) | `number` | Precise numeric input (counts, thresholds) |\n| [Color](color/) | [`viji.color(default, config)`](color/) | `string` | Hex color values (`'#rrggbb'`) |\n| [Toggle](toggle/) | [`viji.toggle(default, config)`](toggle/) | `boolean` | On/off switches (enable audio, show trail) |\n| [Select](select/) | [`viji.select(default, config)`](select/) | `string \\| number` | Dropdown from predefined options (blend mode, shape type) |\n| [Text](text/) | [`viji.text(default, config)`](text/) | `string` | Free-form text input (titles, labels) |\n| [Image](image/) | [`viji.image(default, config)`](image/) | `ImageBitmap \\| null` | User-uploaded images and textures |\n| [Button](button/) | [`viji.button(config)`](button/) | `boolean` | Momentary trigger — true for 1 frame (resets, spawns) |\n| Coordinate | [`viji.coordinate(default, config)`](coordinate/) | `{ x: number, y: number }` | 2D coordinate pad control. Both axes range from -1 to 1. |\n\n## Basic Pattern\n\n```javascript\n// 1. Define at top level — runs once\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst color = viji.color('#ff6600', { label: 'Color' });\nconst mirror = viji.toggle(false, { label: 'Mirror' });\n\n// 2. Read .value in render() — updates in real-time\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n ctx.fillStyle = color.value;\n // speed.value, mirror.value, etc.\n}\n```\n\n> [!WARNING]\n> Parameters must be declared at the **top level** of your scene, never inside `render()`. They are registered once during initialization. Declaring them inside `render()` would re-register the parameter every frame, resetting its value to the default and making user changes ineffective.\n\n## Common Config Keys\n\nAll parameter types share these optional configuration keys:\n\n| Key | Type | Default | Description |\n|---|---|---|---|\n| `label` | `string` | **(required)** | Display name shown in the parameter UI |\n| `description` | `string` | — | Tooltip or help text |\n| `group` | `string` | `'general'` | Group name for organizing parameters — see [Grouping](grouping/) |\n| `category` | `ParameterCategory` | `'general'` | Controls visibility based on active capabilities — see [Categories](categories/) |\n\n## Organization\n\nAs scenes grow, you'll want to organize parameters into logical sections and control when they're visible:\n\n- **[Grouping](grouping/)** — Collect related parameters under named groups (e.g., \"animation\", \"shape\", \"audio\"). Parameters with the same `group` string appear together in the UI.\n- **[Categories](categories/)** — Tag parameters as `'general'`, `'audio'`, `'video'`, or `'interaction'` to automatically show/hide them based on what inputs are currently active.\n\n## Related\n\n- [Slider](slider/) — the most common parameter type\n- [Coordinate](coordinate/) — 2D position control\n- [Grouping](grouping/) — organizing parameters into named groups\n- [Categories](categories/) — visibility based on capabilities\n- [P5 Parameters](/p5/parameters) — same system in the P5 renderer\n- [Shader Parameters](/shader/parameters) — comment-directive syntax for shaders\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
1154
1169
|
}
|
|
1155
1170
|
]
|
|
1156
1171
|
},
|
|
@@ -1312,6 +1327,27 @@ export const docsApi = {
|
|
|
1312
1327
|
}
|
|
1313
1328
|
]
|
|
1314
1329
|
},
|
|
1330
|
+
"native-param-coordinate": {
|
|
1331
|
+
"id": "native-param-coordinate",
|
|
1332
|
+
"title": "Coordinate Parameter",
|
|
1333
|
+
"description": "Create a 2D coordinate control for x/y position values from -1 to 1.",
|
|
1334
|
+
"content": [
|
|
1335
|
+
{
|
|
1336
|
+
"type": "text",
|
|
1337
|
+
"markdown": "# viji.coordinate()\n\n```\ncoordinate(defaultValue: CoordinateValue, config: CoordinateConfig): CoordinateParameter\n```\n\nCreates a 2D coordinate parameter that the host application renders as a draggable pad control. The value is an `{ x, y }` object where both components range from **-1 to 1**. The artist defines the coordinate at the top level of the scene, and reads its current value inside `render()`.\n\n## Parameters\n\n| Name | Type | Required | Default | Description |\n|------|------|----------|---------|-------------|\n| `defaultValue` | `{ x: number, y: number }` | Yes | — | Initial coordinate value (both -1 to 1) |\n| `config.step` | `number` | No | `0.01` | Snap increment for the coordinate values |\n| `config.label` | `string` | Yes | — | Display name shown in the parameter UI |\n| `config.description` | `string` | No | — | Tooltip or help text |\n| `config.group` | `string` | No | `'general'` | Group name for organizing parameters — see [Grouping](../grouping/) |\n| `config.category` | `ParameterCategory` | No | `'general'` | Controls visibility based on capabilities — see [Categories](../categories/) |\n\n## Return Value\n\nReturns a `CoordinateParameter` object:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `value` | `{ x: number, y: number }` | Current coordinate. Updates in real-time when the user drags the control. Both components are -1 to 1. |\n| `step` | `number` | Step increment |\n| `label` | `string` | Display label |\n| `description` | `string \\| undefined` | Description text |\n| `group` | `string` | Group name |\n| `category` | `ParameterCategory` | Parameter category |\n\n## Usage\n\nDefine coordinates at the **top level** of your scene code, before the `render()` function. Read `.value.x` and `.value.y` inside `render()` to get the current position.\n\n```javascript\nconst origin = viji.coordinate({ x: 0, y: 0 }, {\n label: 'Effect Origin',\n group: 'position'\n});\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n ctx.clearRect(0, 0, viji.width, viji.height);\n\n const cx = viji.width / 2 + origin.value.x * viji.width * 0.4;\n const cy = viji.height / 2 - origin.value.y * viji.height * 0.4;\n\n ctx.beginPath();\n ctx.arc(cx, cy, 40, 0, Math.PI * 2);\n ctx.fillStyle = '#ff6b6b';\n ctx.fill();\n}\n```\n\n> [!NOTE]\n> Parameters must be defined at the top level, not inside `render()`. They are registered once during scene initialization. Defining them inside `render()` would re-register the parameter every frame, resetting its value to the default and making user changes ineffective."
|
|
1338
|
+
},
|
|
1339
|
+
{
|
|
1340
|
+
"type": "live-example",
|
|
1341
|
+
"title": "Basic Coordinate",
|
|
1342
|
+
"sceneCode": "const origin = viji.coordinate({ x: 0, y: 0 }, {\n label: 'Effect Origin',\n description: 'Drag to move the circle',\n group: 'position'\n});\n\nconst radius = viji.slider(0.08, {\n min: 0.02,\n max: 0.25,\n step: 0.01,\n label: 'Radius',\n group: 'position'\n});\n\nconst color = viji.color('#ff6b6b', {\n label: 'Color',\n group: 'appearance'\n});\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n const s = Math.min(w, h);\n\n ctx.fillStyle = '#1a1a2e';\n ctx.fillRect(0, 0, w, h);\n\n // Draw grid lines\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.06)';\n ctx.lineWidth = 1;\n for (let i = -1; i <= 1; i += 0.25) {\n const px = w / 2 + i * w * 0.4;\n const py = h / 2 - i * h * 0.4;\n ctx.beginPath(); ctx.moveTo(px, 0); ctx.lineTo(px, h); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(0, py); ctx.lineTo(w, py); ctx.stroke();\n }\n\n // Draw crosshair at center\n ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)';\n ctx.beginPath(); ctx.moveTo(w / 2, 0); ctx.lineTo(w / 2, h); ctx.stroke();\n ctx.beginPath(); ctx.moveTo(0, h / 2); ctx.lineTo(w, h / 2); ctx.stroke();\n\n // Map coordinate to canvas\n const cx = w / 2 + origin.value.x * w * 0.4;\n const cy = h / 2 - origin.value.y * h * 0.4;\n const r = radius.value * s;\n\n // Draw glow\n const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, r * 2);\n grad.addColorStop(0, color.value + '40');\n grad.addColorStop(1, 'transparent');\n ctx.fillStyle = grad;\n ctx.fillRect(cx - r * 2, cy - r * 2, r * 4, r * 4);\n\n // Draw circle\n ctx.beginPath();\n ctx.arc(cx, cy, r, 0, Math.PI * 2);\n ctx.fillStyle = color.value;\n ctx.fill();\n\n // Draw coordinate readout\n ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';\n ctx.font = Math.round(s * 0.025) + 'px monospace';\n ctx.textAlign = 'center';\n ctx.fillText(\n 'x: ' + origin.value.x.toFixed(2) + ' y: ' + origin.value.y.toFixed(2),\n w / 2, h - s * 0.03\n );\n}\n",
|
|
1343
|
+
"sceneFile": "coordinate-basic.scene.js"
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
"type": "text",
|
|
1347
|
+
"markdown": "## Coordinate Space\n\nThe coordinate value uses a **normalized -1 to 1 range** on both axes:\n\n| Value | Position |\n|-------|----------|\n| `{ x: -1, y: -1 }` | Bottom-left |\n| `{ x: 0, y: 0 }` | Center |\n| `{ x: 1, y: 1 }` | Top-right |\n| `{ x: -1, y: 1 }` | Top-left |\n| `{ x: 1, y: -1 }` | Bottom-right |\n\nThe y-axis follows mathematical convention: positive y points **up**. When mapping to canvas pixels, invert y since canvas y increases downward.\n\n## Related\n\n- [Slider](../slider/) — single-axis numeric range\n- [Number](../number/) — precise numeric input\n- [Grouping](../grouping/) — organizing parameters into named groups\n- [Categories](../categories/) — controlling parameter visibility based on capabilities\n- [Shader Coordinate](/shader/parameters/coordinate) — equivalent for the Shader renderer"
|
|
1348
|
+
}
|
|
1349
|
+
]
|
|
1350
|
+
},
|
|
1315
1351
|
"native-param-grouping": {
|
|
1316
1352
|
"id": "native-param-grouping",
|
|
1317
1353
|
"title": "Grouping Parameters",
|
|
@@ -1973,7 +2009,7 @@ export const docsApi = {
|
|
|
1973
2009
|
"content": [
|
|
1974
2010
|
{
|
|
1975
2011
|
"type": "text",
|
|
1976
|
-
"markdown": "# API Reference\n\nThis page lists every property and method available on the `viji` object passed to your P5 scene functions. The `viji` API is identical to the [Native renderer](/native/api-reference) — the difference is that P5 scenes also receive a `p5` instance as the second argument.\n\nNew to Viji P5? Start with the [Quick Start](/p5/quickstart) instead.\n\n## Entry Points\n\n```javascript\n// @renderer p5\n\nfunction setup(viji, p5) {\n // Called once when the scene starts (optional)\n}\n\nfunction render(viji, p5) {\n // Called every frame\n}\n```\n\nThe `p5` parameter is a full [P5.js](https://p5js.org/reference/) instance (v1.9.4) in instance mode. All P5 drawing methods (`p5.rect()`, `p5.fill()`, `p5.ellipse()`, etc.) are accessed through it. See [Drawing with P5](/p5/drawing) for Viji-specific drawing patterns.\n\n## Canvas & Context\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.canvas`](/p5/canvas-resolution) | `OffscreenCanvas` | The rendering canvas | [Canvas & Resolution](/p5/canvas-resolution) |\n| [`viji.width`](/p5/canvas-resolution) | `number` | Canvas width in pixels | [Canvas & Resolution](/p5/canvas-resolution) |\n| [`viji.height`](/p5/canvas-resolution) | `number` | Canvas height in pixels | [Canvas & Resolution](/p5/canvas-resolution) |\n\n> [!WARNING]\n> `viji.useContext()` is **not available** in P5 scenes. The canvas and its rendering context (2D or WEBGL, depending on the directive) are managed by P5 internally. Calling `useContext()` would conflict with P5's rendering pipeline.\n\n## Timing\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.time`](/p5/timing) | `number` | Seconds elapsed since the scene started | [Timing](/p5/timing) |\n| [`viji.deltaTime`](/p5/timing) | `number` | Seconds since the previous frame | [Timing](/p5/timing) |\n| [`viji.frameCount`](/p5/timing) | `number` | Monotonically increasing frame counter | [Timing](/p5/timing) |\n| [`viji.fps`](/p5/timing) | `number` | Target FPS based on the host's frame rate mode | [Timing](/p5/timing) |\n\n## Parameters\n\nAll parameter methods are called at the top level of your scene file. Read `.value` inside `render()` to get the current value.\n\n| Method | Returns | `.value` Type | Details |\n|--------|---------|---------------|---------|\n| [`viji.slider(default, config)`](/p5/parameters/slider) | `SliderParameter` | `number` | [Slider](/p5/parameters/slider) |\n| [`viji.color(default, config)`](/p5/parameters/color) | `ColorParameter` | `string` (hex) | [Color](/p5/parameters/color) |\n| [`viji.toggle(default, config)`](/p5/parameters/toggle) | `ToggleParameter` | `boolean` | [Toggle](/p5/parameters/toggle) |\n| [`viji.select(default, config)`](/p5/parameters/select) | `SelectParameter` | `string \\| number` | [Select](/p5/parameters/select) |\n| [`viji.number(default, config)`](/p5/parameters/number) | `NumberParameter` | `number` | [Number](/p5/parameters/number) |\n| [`viji.text(default, config)`](/p5/parameters/text) | `TextParameter` | `string` | [Text](/p5/parameters/text) |\n| [`viji.image(null, config)`](/p5/parameters/image) | `ImageParameter` | `ImageBitmap \\| null` | [Image](/p5/parameters/image) |\n| [`viji.button(config)`](/p5/parameters/button) | `ButtonParameter` | `boolean` (true for one frame) | [Button](/p5/parameters/button) |\n\n> [!NOTE]\n> Image parameters have a `.p5` property for use with `p5.image()`. See [Drawing with P5 — Image Parameters](/p5/drawing) for the pattern.\n\nSee [Parameters Overview](/p5/parameters) for the declaration pattern, [Grouping](/p5/parameters/grouping) and [Categories](/p5/parameters/categories) for organization.\n\n## Audio\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.audio.isConnected`](/p5/audio) | `boolean` | Whether an audio source is active | [Overview](/p5/audio) |\n| [`viji.audio.volume.current`](/p5/audio/volume) | `number` | Current RMS volume 0–1 | [Volume](/p5/audio/volume) |\n| [`viji.audio.volume.peak`](/p5/audio/volume) | `number` | Peak volume 0–1 | [Volume](/p5/audio/volume) |\n| [`viji.audio.volume.smoothed`](/p5/audio/volume) | `number` | Smoothed volume 0–1 | [Volume](/p5/audio/volume) |\n| [`viji.audio.bands.low`](/p5/audio/bands) | `number` | Low frequency band energy (20–120 Hz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.lowMid`](/p5/audio/bands) | `number` | Low-mid band energy (120–500 Hz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.mid`](/p5/audio/bands) | `number` | Mid band energy (500–2 kHz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.highMid`](/p5/audio/bands) | `number` | High-mid band energy (2–6 kHz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.high`](/p5/audio/bands) | `number` | High band energy (6–16 kHz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.lowSmoothed`](/p5/audio/bands) | `number` | Smoothed low band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.lowMidSmoothed`](/p5/audio/bands) | `number` | Smoothed low-mid band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.midSmoothed`](/p5/audio/bands) | `number` | Smoothed mid band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.highMidSmoothed`](/p5/audio/bands) | `number` | Smoothed high-mid band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.highSmoothed`](/p5/audio/bands) | `number` | Smoothed high band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.beat.kick`](/p5/audio/beat) | `number` | Kick beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.snare`](/p5/audio/beat) | `number` | Snare beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.hat`](/p5/audio/beat) | `number` | Hi-hat beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.any`](/p5/audio/beat) | `number` | Combined beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.kickSmoothed`](/p5/audio/beat) | `number` | Smoothed kick | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.snareSmoothed`](/p5/audio/beat) | `number` | Smoothed snare | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.hatSmoothed`](/p5/audio/beat) | `number` | Smoothed hi-hat | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.anySmoothed`](/p5/audio/beat) | `number` | Smoothed combined | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.kick`](/p5/audio/beat) | `boolean` | Kick trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.snare`](/p5/audio/beat) | `boolean` | Snare trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.hat`](/p5/audio/beat) | `boolean` | Hi-hat trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.any`](/p5/audio/beat) | `boolean` | Any beat trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.events`](/p5/audio/beat) | `Array<{ type, time, strength }>` | Beat events this frame | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.bpm`](/p5/audio/beat) | `number` | Tracked BPM | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.confidence`](/p5/audio/beat) | `number` | Beat-tracker confidence 0–1 | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.isLocked`](/p5/audio/beat) | `boolean` | Whether beat tracking is locked | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.spectral.brightness`](/p5/audio/spectral) | `number` | Spectral brightness 0–1 | [Spectral Analysis](/p5/audio/spectral) |\n| [`viji.audio.spectral.flatness`](/p5/audio/spectral) | `number` | Spectral flatness 0–1 | [Spectral Analysis](/p5/audio/spectral) |\n| [`viji.audio.getFrequencyData()`](/p5/audio/frequency-data) | `() => Uint8Array` | Raw FFT frequency bins (0–255) | [Frequency Data](/p5/audio/frequency-data) |\n| [`viji.audio.getWaveform()`](/p5/audio/waveform) | `() => Float32Array` | Time-domain waveform (-1 to 1) | [Waveform](/p5/audio/waveform) |\n\n## Video & CV\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.video.isConnected`](/p5/video) | `boolean` | Whether a video source is active | [Overview](/p5/video) |\n| [`viji.video.currentFrame`](/p5/video/basics) | `OffscreenCanvas \\| ImageBitmap \\| null` | Current video frame | [Video Basics](/p5/video/basics) |\n| [`viji.video.frameWidth`](/p5/video/basics) | `number` | Frame width in pixels | [Video Basics](/p5/video/basics) |\n| [`viji.video.frameHeight`](/p5/video/basics) | `number` | Frame height in pixels | [Video Basics](/p5/video/basics) |\n| [`viji.video.frameRate`](/p5/video/basics) | `number` | Video frame rate | [Video Basics](/p5/video/basics) |\n| [`viji.video.getFrameData()`](/p5/video/basics) | `() => ImageData \\| null` | Pixel data for the current frame | [Video Basics](/p5/video/basics) |\n| [`viji.video.faces`](/p5/video/face-detection) | `FaceData[]` | Detected faces | [Face Detection](/p5/video/face-detection) |\n| [`viji.video.hands`](/p5/video/hand-tracking) | `HandData[]` | Detected hands | [Hand Tracking](/p5/video/hand-tracking) |\n| [`viji.video.pose`](/p5/video/pose-detection) | `PoseData \\| null` | Detected body pose | [Pose Detection](/p5/video/pose-detection) |\n| [`viji.video.segmentation`](/p5/video/body-segmentation) | `SegmentationData \\| null` | Body segmentation mask | [Body Segmentation](/p5/video/body-segmentation) |\n| [`viji.video.cv.enableFaceDetection(enabled)`](/p5/video/face-detection) | `(boolean) => Promise<void>` | Enable/disable face detection | [Face Detection](/p5/video/face-detection) |\n| [`viji.video.cv.enableFaceMesh(enabled)`](/p5/video/face-mesh) | `(boolean) => Promise<void>` | Enable/disable face mesh | [Face Mesh](/p5/video/face-mesh) |\n| [`viji.video.cv.enableEmotionDetection(enabled)`](/p5/video/emotion-detection) | `(boolean) => Promise<void>` | Enable/disable emotion detection | [Emotion Detection](/p5/video/emotion-detection) |\n| [`viji.video.cv.enableHandTracking(enabled)`](/p5/video/hand-tracking) | `(boolean) => Promise<void>` | Enable/disable hand tracking | [Hand Tracking](/p5/video/hand-tracking) |\n| [`viji.video.cv.enablePoseDetection(enabled)`](/p5/video/pose-detection) | `(boolean) => Promise<void>` | Enable/disable pose detection | [Pose Detection](/p5/video/pose-detection) |\n| [`viji.video.cv.enableBodySegmentation(enabled)`](/p5/video/body-segmentation) | `(boolean) => Promise<void>` | Enable/disable body segmentation | [Body Segmentation](/p5/video/body-segmentation) |\n| [`viji.video.cv.getActiveFeatures()`](/p5/video) | `() => CVFeature[]` | List of active CV features | [Overview](/p5/video) |\n| [`viji.video.cv.isProcessing()`](/p5/video) | `() => boolean` | Whether CV is currently processing | [Overview](/p5/video) |\n\n## Mouse\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.mouse.x`](/p5/mouse) | `number` | Cursor X position in pixels | [Mouse](/p5/mouse) |\n| [`viji.mouse.y`](/p5/mouse) | `number` | Cursor Y position in pixels | [Mouse](/p5/mouse) |\n| [`viji.mouse.isInCanvas`](/p5/mouse) | `boolean` | Whether cursor is inside the canvas | [Mouse](/p5/mouse) |\n| [`viji.mouse.isPressed`](/p5/mouse) | `boolean` | Whether any button is pressed | [Mouse](/p5/mouse) |\n| [`viji.mouse.leftButton`](/p5/mouse) | `boolean` | Left button state | [Mouse](/p5/mouse) |\n| [`viji.mouse.rightButton`](/p5/mouse) | `boolean` | Right button state | [Mouse](/p5/mouse) |\n| [`viji.mouse.middleButton`](/p5/mouse) | `boolean` | Middle button state | [Mouse](/p5/mouse) |\n| [`viji.mouse.deltaX`](/p5/mouse) | `number` | Horizontal movement since last frame | [Mouse](/p5/mouse) |\n| [`viji.mouse.deltaY`](/p5/mouse) | `number` | Vertical movement since last frame | [Mouse](/p5/mouse) |\n| [`viji.mouse.wheelDelta`](/p5/mouse) | `number` | Scroll wheel delta | [Mouse](/p5/mouse) |\n| [`viji.mouse.wheelX`](/p5/mouse) | `number` | Horizontal scroll delta | [Mouse](/p5/mouse) |\n| [`viji.mouse.wheelY`](/p5/mouse) | `number` | Vertical scroll delta | [Mouse](/p5/mouse) |\n| [`viji.mouse.wasPressed`](/p5/mouse) | `boolean` | True for one frame when pressed | [Mouse](/p5/mouse) |\n| [`viji.mouse.wasReleased`](/p5/mouse) | `boolean` | True for one frame when released | [Mouse](/p5/mouse) |\n| [`viji.mouse.wasMoved`](/p5/mouse) | `boolean` | True for one frame when moved | [Mouse](/p5/mouse) |\n\n## Keyboard\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.keyboard.isPressed(key)`](/p5/keyboard) | `(string) => boolean` | Whether a key is currently held | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.wasPressed(key)`](/p5/keyboard) | `(string) => boolean` | True for one frame when pressed | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.wasReleased(key)`](/p5/keyboard) | `(string) => boolean` | True for one frame when released | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.activeKeys`](/p5/keyboard) | `Set<string>` | All currently held keys | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.pressedThisFrame`](/p5/keyboard) | `Set<string>` | Keys pressed this frame | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.releasedThisFrame`](/p5/keyboard) | `Set<string>` | Keys released this frame | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.lastKeyPressed`](/p5/keyboard) | `string` | Most recently pressed key | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.lastKeyReleased`](/p5/keyboard) | `string` | Most recently released key | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.shift`](/p5/keyboard) | `boolean` | Shift key state | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.ctrl`](/p5/keyboard) | `boolean` | Ctrl/Cmd key state | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.alt`](/p5/keyboard) | `boolean` | Alt/Option key state | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.meta`](/p5/keyboard) | `boolean` | Meta/Win key state | [Keyboard](/p5/keyboard) |\n\n## Touch\n\n> **Note:** The property is `viji.touches` (plural), not `viji.touch`.\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.touches.points`](/p5/touch) | `TouchPoint[]` | All active touch points | [Touch](/p5/touch) |\n| [`viji.touches.count`](/p5/touch) | `number` | Number of active touches | [Touch](/p5/touch) |\n| [`viji.touches.started`](/p5/touch) | `TouchPoint[]` | Touch points that started this frame | [Touch](/p5/touch) |\n| [`viji.touches.moved`](/p5/touch) | `TouchPoint[]` | Touch points that moved this frame | [Touch](/p5/touch) |\n| [`viji.touches.ended`](/p5/touch) | `TouchPoint[]` | Touch points that ended this frame | [Touch](/p5/touch) |\n| [`viji.touches.primary`](/p5/touch) | `TouchPoint \\| null` | The first active touch point | [Touch](/p5/touch) |\n\n**`TouchPoint` fields:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force` (numbers); `isInCanvas`, `isNew`, `isActive`, `isEnding` (booleans); `deltaX`, `deltaY` (numbers); `velocity` `{ x, y }`.\n\n## Pointer (Unified)\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.pointer.x`](/p5/pointer) | `number` | Primary pointer X position | [Pointer](/p5/pointer) |\n| [`viji.pointer.y`](/p5/pointer) | `number` | Primary pointer Y position | [Pointer](/p5/pointer) |\n| [`viji.pointer.deltaX`](/p5/pointer) | `number` | Horizontal movement since last frame | [Pointer](/p5/pointer) |\n| [`viji.pointer.deltaY`](/p5/pointer) | `number` | Vertical movement since last frame | [Pointer](/p5/pointer) |\n| [`viji.pointer.isDown`](/p5/pointer) | `boolean` | Whether the pointer is active (click or touch) | [Pointer](/p5/pointer) |\n| [`viji.pointer.wasPressed`](/p5/pointer) | `boolean` | True for one frame when pressed | [Pointer](/p5/pointer) |\n| [`viji.pointer.wasReleased`](/p5/pointer) | `boolean` | True for one frame when released | [Pointer](/p5/pointer) |\n| [`viji.pointer.isInCanvas`](/p5/pointer) | `boolean` | Whether pointer is inside the canvas | [Pointer](/p5/pointer) |\n| [`viji.pointer.type`](/p5/pointer) | `'mouse' \\| 'touch' \\| 'none'` | Current input source | [Pointer](/p5/pointer) |\n\n## Device Sensors\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.device.motion`](/p5/sensors) | `DeviceMotionData \\| null` | Accelerometer and gyroscope data | [Device Sensors](/p5/sensors) |\n| [`viji.device.orientation`](/p5/sensors) | `DeviceOrientationData \\| null` | Device orientation (alpha, beta, gamma) | [Device Sensors](/p5/sensors) |\n\n**`DeviceMotionData`:** `acceleration` `{ x, y, z }`, `accelerationIncludingGravity` `{ x, y, z }`, `rotationRate` `{ alpha, beta, gamma }`, `interval`.\n\n**`DeviceOrientationData`:** `alpha`, `beta`, `gamma` (numbers or null), `absolute` (boolean).\n\n## External Devices\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.devices`](/p5/external-devices) | `DeviceState[]` | Connected external devices | [Overview](/p5/external-devices) |\n| [`viji.devices[i].id`](/p5/external-devices) | `string` | Unique device identifier | [Overview](/p5/external-devices) |\n| [`viji.devices[i].name`](/p5/external-devices) | `string` | User-friendly device name | [Overview](/p5/external-devices) |\n| [`viji.devices[i].motion`](/p5/external-devices/sensors) | `DeviceMotionData \\| null` | Device accelerometer/gyroscope | [Device Sensors](/p5/external-devices/sensors) |\n| [`viji.devices[i].orientation`](/p5/external-devices/sensors) | `DeviceOrientationData \\| null` | Device orientation | [Device Sensors](/p5/external-devices/sensors) |\n| [`viji.devices[i].video`](/p5/external-devices/video) | `VideoAPI \\| null` | Device camera video | [Device Video](/p5/external-devices/video) |\n| [`viji.devices[i].audio`](/p5/external-devices/audio) | `AudioStreamAPI \\| null` | Device audio stream | [Device Audio](/p5/external-devices/audio) |\n\n## Streams\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.videoStreams` | `VideoAPI[]` | Additional video streams provided by the host |\n| `viji.audioStreams` | `AudioStreamAPI[]` | Additional audio streams provided by the host |\n\nEach `videoStreams` element has the same shape as [`viji.video`](/p5/video). Each `audioStreams` element provides lightweight audio analysis (volume, frequency bands, spectral features) but does **not** include beat detection or BPM tracking — see [`viji.audio`](/p5/audio) for full analysis on the main stream.\n\nBoth arrays may be empty if the host does not provide additional streams. Audio streams from external devices appear on `device.audio`, not in `viji.audioStreams`.\n\n## Related\n\n- [Quick Start](/p5/quickstart) — getting started with the P5 renderer\n- [Scene Structure](/p5/scene-structure) — setup/render pattern and instance mode\n- [Drawing with P5](/p5/drawing) — Viji-specific drawing patterns\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers\n- [Native API Reference](/native/api-reference) — the same API in the Native renderer\n- [Shader API Reference](/shader/api-reference) — built-in uniforms for shaders\n- [P5.js Reference](https://p5js.org/reference/) — official P5.js documentation"
|
|
2012
|
+
"markdown": "# API Reference\n\nThis page lists every property and method available on the `viji` object passed to your P5 scene functions. The `viji` API is identical to the [Native renderer](/native/api-reference) — the difference is that P5 scenes also receive a `p5` instance as the second argument.\n\nNew to Viji P5? Start with the [Quick Start](/p5/quickstart) instead.\n\n## Entry Points\n\n```javascript\n// @renderer p5\n\nfunction setup(viji, p5) {\n // Called once when the scene starts (optional)\n}\n\nfunction render(viji, p5) {\n // Called every frame\n}\n```\n\nThe `p5` parameter is a full [P5.js](https://p5js.org/reference/) instance (v1.9.4) in instance mode. All P5 drawing methods (`p5.rect()`, `p5.fill()`, `p5.ellipse()`, etc.) are accessed through it. See [Drawing with P5](/p5/drawing) for Viji-specific drawing patterns.\n\n## Canvas & Context\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.canvas`](/p5/canvas-resolution) | `OffscreenCanvas` | The rendering canvas | [Canvas & Resolution](/p5/canvas-resolution) |\n| [`viji.width`](/p5/canvas-resolution) | `number` | Canvas width in pixels | [Canvas & Resolution](/p5/canvas-resolution) |\n| [`viji.height`](/p5/canvas-resolution) | `number` | Canvas height in pixels | [Canvas & Resolution](/p5/canvas-resolution) |\n\n> [!WARNING]\n> `viji.useContext()` is **not available** in P5 scenes. The canvas and its rendering context (2D or WEBGL, depending on the directive) are managed by P5 internally. Calling `useContext()` would conflict with P5's rendering pipeline.\n\n## Timing\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.time`](/p5/timing) | `number` | Seconds elapsed since the scene started | [Timing](/p5/timing) |\n| [`viji.deltaTime`](/p5/timing) | `number` | Seconds since the previous frame | [Timing](/p5/timing) |\n| [`viji.frameCount`](/p5/timing) | `number` | Monotonically increasing frame counter | [Timing](/p5/timing) |\n| [`viji.fps`](/p5/timing) | `number` | Target FPS based on the host's frame rate mode | [Timing](/p5/timing) |\n\n## Parameters\n\nAll parameter methods are called at the top level of your scene file. Read `.value` inside `render()` to get the current value.\n\n| Method | Returns | `.value` Type | Details |\n|--------|---------|---------------|---------|\n| [`viji.slider(default, config)`](/p5/parameters/slider) | `SliderParameter` | `number` | [Slider](/p5/parameters/slider) |\n| [`viji.color(default, config)`](/p5/parameters/color) | `ColorParameter` | `string` (hex) | [Color](/p5/parameters/color) |\n| [`viji.toggle(default, config)`](/p5/parameters/toggle) | `ToggleParameter` | `boolean` | [Toggle](/p5/parameters/toggle) |\n| [`viji.select(default, config)`](/p5/parameters/select) | `SelectParameter` | `string \\| number` | [Select](/p5/parameters/select) |\n| [`viji.number(default, config)`](/p5/parameters/number) | `NumberParameter` | `number` | [Number](/p5/parameters/number) |\n| [`viji.text(default, config)`](/p5/parameters/text) | `TextParameter` | `string` | [Text](/p5/parameters/text) |\n| [`viji.image(null, config)`](/p5/parameters/image) | `ImageParameter` | `ImageBitmap \\| null` | [Image](/p5/parameters/image) |\n| [`viji.button(config)`](/p5/parameters/button) | `ButtonParameter` | `boolean` (true for one frame) | [Button](/p5/parameters/button) |\n| [`viji.coordinate(default, config)`](/p5/parameters/coordinate) | `CoordinateParameter` | 2D coordinate pad — `{ x: number, y: number }`, both -1 to 1 | [Coordinate](/p5/parameters/coordinate) |\n\n> [!NOTE]\n> Image parameters have a `.p5` property for use with `p5.image()`. See [Drawing with P5 — Image Parameters](/p5/drawing) for the pattern.\n\nSee [Parameters Overview](/p5/parameters) for the declaration pattern, [Grouping](/p5/parameters/grouping) and [Categories](/p5/parameters/categories) for organization.\n\n## Audio\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.audio.isConnected`](/p5/audio) | `boolean` | Whether an audio source is active | [Overview](/p5/audio) |\n| [`viji.audio.volume.current`](/p5/audio/volume) | `number` | Current RMS volume 0–1 | [Volume](/p5/audio/volume) |\n| [`viji.audio.volume.peak`](/p5/audio/volume) | `number` | Peak volume 0–1 | [Volume](/p5/audio/volume) |\n| [`viji.audio.volume.smoothed`](/p5/audio/volume) | `number` | Smoothed volume 0–1 | [Volume](/p5/audio/volume) |\n| [`viji.audio.bands.low`](/p5/audio/bands) | `number` | Low frequency band energy (20–120 Hz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.lowMid`](/p5/audio/bands) | `number` | Low-mid band energy (120–500 Hz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.mid`](/p5/audio/bands) | `number` | Mid band energy (500–2 kHz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.highMid`](/p5/audio/bands) | `number` | High-mid band energy (2–6 kHz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.high`](/p5/audio/bands) | `number` | High band energy (6–16 kHz) | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.lowSmoothed`](/p5/audio/bands) | `number` | Smoothed low band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.lowMidSmoothed`](/p5/audio/bands) | `number` | Smoothed low-mid band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.midSmoothed`](/p5/audio/bands) | `number` | Smoothed mid band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.highMidSmoothed`](/p5/audio/bands) | `number` | Smoothed high-mid band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.bands.highSmoothed`](/p5/audio/bands) | `number` | Smoothed high band | [Frequency Bands](/p5/audio/bands) |\n| [`viji.audio.beat.kick`](/p5/audio/beat) | `number` | Kick beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.snare`](/p5/audio/beat) | `number` | Snare beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.hat`](/p5/audio/beat) | `number` | Hi-hat beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.any`](/p5/audio/beat) | `number` | Combined beat energy | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.kickSmoothed`](/p5/audio/beat) | `number` | Smoothed kick | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.snareSmoothed`](/p5/audio/beat) | `number` | Smoothed snare | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.hatSmoothed`](/p5/audio/beat) | `number` | Smoothed hi-hat | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.anySmoothed`](/p5/audio/beat) | `number` | Smoothed combined | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.kick`](/p5/audio/beat) | `boolean` | Kick trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.snare`](/p5/audio/beat) | `boolean` | Snare trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.hat`](/p5/audio/beat) | `boolean` | Hi-hat trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.triggers.any`](/p5/audio/beat) | `boolean` | Any beat trigger (true for one frame) | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.events`](/p5/audio/beat) | `Array<{ type, time, strength }>` | Beat events this frame | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.bpm`](/p5/audio/beat) | `number` | Tracked BPM | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.confidence`](/p5/audio/beat) | `number` | Beat-tracker confidence 0–1 | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.beat.isLocked`](/p5/audio/beat) | `boolean` | Whether beat tracking is locked | [Beat Detection](/p5/audio/beat) |\n| [`viji.audio.spectral.brightness`](/p5/audio/spectral) | `number` | Spectral brightness 0–1 | [Spectral Analysis](/p5/audio/spectral) |\n| [`viji.audio.spectral.flatness`](/p5/audio/spectral) | `number` | Spectral flatness 0–1 | [Spectral Analysis](/p5/audio/spectral) |\n| [`viji.audio.getFrequencyData()`](/p5/audio/frequency-data) | `() => Uint8Array` | Raw FFT frequency bins (0–255) | [Frequency Data](/p5/audio/frequency-data) |\n| [`viji.audio.getWaveform()`](/p5/audio/waveform) | `() => Float32Array` | Time-domain waveform (-1 to 1) | [Waveform](/p5/audio/waveform) |\n\n## Video & CV\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.video.isConnected`](/p5/video) | `boolean` | Whether a video source is active | [Overview](/p5/video) |\n| [`viji.video.currentFrame`](/p5/video/basics) | `OffscreenCanvas \\| ImageBitmap \\| null` | Current video frame | [Video Basics](/p5/video/basics) |\n| [`viji.video.frameWidth`](/p5/video/basics) | `number` | Frame width in pixels | [Video Basics](/p5/video/basics) |\n| [`viji.video.frameHeight`](/p5/video/basics) | `number` | Frame height in pixels | [Video Basics](/p5/video/basics) |\n| [`viji.video.frameRate`](/p5/video/basics) | `number` | Video frame rate | [Video Basics](/p5/video/basics) |\n| [`viji.video.getFrameData()`](/p5/video/basics) | `() => ImageData \\| null` | Pixel data for the current frame | [Video Basics](/p5/video/basics) |\n| [`viji.video.faces`](/p5/video/face-detection) | `FaceData[]` | Detected faces | [Face Detection](/p5/video/face-detection) |\n| [`viji.video.hands`](/p5/video/hand-tracking) | `HandData[]` | Detected hands | [Hand Tracking](/p5/video/hand-tracking) |\n| [`viji.video.pose`](/p5/video/pose-detection) | `PoseData \\| null` | Detected body pose | [Pose Detection](/p5/video/pose-detection) |\n| [`viji.video.segmentation`](/p5/video/body-segmentation) | `SegmentationData \\| null` | Body segmentation mask | [Body Segmentation](/p5/video/body-segmentation) |\n| [`viji.video.cv.enableFaceDetection(enabled)`](/p5/video/face-detection) | `(boolean) => Promise<void>` | Enable/disable face detection | [Face Detection](/p5/video/face-detection) |\n| [`viji.video.cv.enableFaceMesh(enabled)`](/p5/video/face-mesh) | `(boolean) => Promise<void>` | Enable/disable face mesh | [Face Mesh](/p5/video/face-mesh) |\n| [`viji.video.cv.enableEmotionDetection(enabled)`](/p5/video/emotion-detection) | `(boolean) => Promise<void>` | Enable/disable emotion detection | [Emotion Detection](/p5/video/emotion-detection) |\n| [`viji.video.cv.enableHandTracking(enabled)`](/p5/video/hand-tracking) | `(boolean) => Promise<void>` | Enable/disable hand tracking | [Hand Tracking](/p5/video/hand-tracking) |\n| [`viji.video.cv.enablePoseDetection(enabled)`](/p5/video/pose-detection) | `(boolean) => Promise<void>` | Enable/disable pose detection | [Pose Detection](/p5/video/pose-detection) |\n| [`viji.video.cv.enableBodySegmentation(enabled)`](/p5/video/body-segmentation) | `(boolean) => Promise<void>` | Enable/disable body segmentation | [Body Segmentation](/p5/video/body-segmentation) |\n| [`viji.video.cv.getActiveFeatures()`](/p5/video) | `() => CVFeature[]` | List of active CV features | [Overview](/p5/video) |\n| [`viji.video.cv.isProcessing()`](/p5/video) | `() => boolean` | Whether CV is currently processing | [Overview](/p5/video) |\n\n## Mouse\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.mouse.x`](/p5/mouse) | `number` | Cursor X position in pixels | [Mouse](/p5/mouse) |\n| [`viji.mouse.y`](/p5/mouse) | `number` | Cursor Y position in pixels | [Mouse](/p5/mouse) |\n| [`viji.mouse.isInCanvas`](/p5/mouse) | `boolean` | Whether cursor is inside the canvas | [Mouse](/p5/mouse) |\n| [`viji.mouse.isPressed`](/p5/mouse) | `boolean` | Whether any button is pressed | [Mouse](/p5/mouse) |\n| [`viji.mouse.leftButton`](/p5/mouse) | `boolean` | Left button state | [Mouse](/p5/mouse) |\n| [`viji.mouse.rightButton`](/p5/mouse) | `boolean` | Right button state | [Mouse](/p5/mouse) |\n| [`viji.mouse.middleButton`](/p5/mouse) | `boolean` | Middle button state | [Mouse](/p5/mouse) |\n| [`viji.mouse.deltaX`](/p5/mouse) | `number` | Horizontal movement since last frame | [Mouse](/p5/mouse) |\n| [`viji.mouse.deltaY`](/p5/mouse) | `number` | Vertical movement since last frame | [Mouse](/p5/mouse) |\n| [`viji.mouse.wheelDelta`](/p5/mouse) | `number` | Scroll wheel delta | [Mouse](/p5/mouse) |\n| [`viji.mouse.wheelX`](/p5/mouse) | `number` | Horizontal scroll delta | [Mouse](/p5/mouse) |\n| [`viji.mouse.wheelY`](/p5/mouse) | `number` | Vertical scroll delta | [Mouse](/p5/mouse) |\n| [`viji.mouse.wasPressed`](/p5/mouse) | `boolean` | True for one frame when pressed | [Mouse](/p5/mouse) |\n| [`viji.mouse.wasReleased`](/p5/mouse) | `boolean` | True for one frame when released | [Mouse](/p5/mouse) |\n| [`viji.mouse.wasMoved`](/p5/mouse) | `boolean` | True for one frame when moved | [Mouse](/p5/mouse) |\n\n## Keyboard\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.keyboard.isPressed(key)`](/p5/keyboard) | `(string) => boolean` | Whether a key is currently held | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.wasPressed(key)`](/p5/keyboard) | `(string) => boolean` | True for one frame when pressed | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.wasReleased(key)`](/p5/keyboard) | `(string) => boolean` | True for one frame when released | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.activeKeys`](/p5/keyboard) | `Set<string>` | All currently held keys | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.pressedThisFrame`](/p5/keyboard) | `Set<string>` | Keys pressed this frame | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.releasedThisFrame`](/p5/keyboard) | `Set<string>` | Keys released this frame | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.lastKeyPressed`](/p5/keyboard) | `string` | Most recently pressed key | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.lastKeyReleased`](/p5/keyboard) | `string` | Most recently released key | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.shift`](/p5/keyboard) | `boolean` | Shift key state | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.ctrl`](/p5/keyboard) | `boolean` | Ctrl/Cmd key state | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.alt`](/p5/keyboard) | `boolean` | Alt/Option key state | [Keyboard](/p5/keyboard) |\n| [`viji.keyboard.meta`](/p5/keyboard) | `boolean` | Meta/Win key state | [Keyboard](/p5/keyboard) |\n\n## Touch\n\n> **Note:** The property is `viji.touches` (plural), not `viji.touch`.\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.touches.points`](/p5/touch) | `TouchPoint[]` | All active touch points | [Touch](/p5/touch) |\n| [`viji.touches.count`](/p5/touch) | `number` | Number of active touches | [Touch](/p5/touch) |\n| [`viji.touches.started`](/p5/touch) | `TouchPoint[]` | Touch points that started this frame | [Touch](/p5/touch) |\n| [`viji.touches.moved`](/p5/touch) | `TouchPoint[]` | Touch points that moved this frame | [Touch](/p5/touch) |\n| [`viji.touches.ended`](/p5/touch) | `TouchPoint[]` | Touch points that ended this frame | [Touch](/p5/touch) |\n| [`viji.touches.primary`](/p5/touch) | `TouchPoint \\| null` | The first active touch point | [Touch](/p5/touch) |\n\n**`TouchPoint` fields:** `id`, `x`, `y`, `pressure`, `radius`, `radiusX`, `radiusY`, `rotationAngle`, `force` (numbers); `isInCanvas`, `isNew`, `isActive`, `isEnding` (booleans); `deltaX`, `deltaY` (numbers); `velocity` `{ x, y }`.\n\n## Pointer (Unified)\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.pointer.x`](/p5/pointer) | `number` | Primary pointer X position | [Pointer](/p5/pointer) |\n| [`viji.pointer.y`](/p5/pointer) | `number` | Primary pointer Y position | [Pointer](/p5/pointer) |\n| [`viji.pointer.deltaX`](/p5/pointer) | `number` | Horizontal movement since last frame | [Pointer](/p5/pointer) |\n| [`viji.pointer.deltaY`](/p5/pointer) | `number` | Vertical movement since last frame | [Pointer](/p5/pointer) |\n| [`viji.pointer.isDown`](/p5/pointer) | `boolean` | Whether the pointer is active (click or touch) | [Pointer](/p5/pointer) |\n| [`viji.pointer.wasPressed`](/p5/pointer) | `boolean` | True for one frame when pressed | [Pointer](/p5/pointer) |\n| [`viji.pointer.wasReleased`](/p5/pointer) | `boolean` | True for one frame when released | [Pointer](/p5/pointer) |\n| [`viji.pointer.isInCanvas`](/p5/pointer) | `boolean` | Whether pointer is inside the canvas | [Pointer](/p5/pointer) |\n| [`viji.pointer.type`](/p5/pointer) | `'mouse' \\| 'touch' \\| 'none'` | Current input source | [Pointer](/p5/pointer) |\n\n## Device Sensors\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.device.motion`](/p5/sensors) | `DeviceMotionData \\| null` | Accelerometer and gyroscope data | [Device Sensors](/p5/sensors) |\n| [`viji.device.orientation`](/p5/sensors) | `DeviceOrientationData \\| null` | Device orientation (alpha, beta, gamma) | [Device Sensors](/p5/sensors) |\n\n**`DeviceMotionData`:** `acceleration` `{ x, y, z }`, `accelerationIncludingGravity` `{ x, y, z }`, `rotationRate` `{ alpha, beta, gamma }`, `interval`.\n\n**`DeviceOrientationData`:** `alpha`, `beta`, `gamma` (numbers or null), `absolute` (boolean).\n\n## External Devices\n\n| Member | Type | Description | Details |\n|--------|------|-------------|---------|\n| [`viji.devices`](/p5/external-devices) | `DeviceState[]` | Connected external devices | [Overview](/p5/external-devices) |\n| [`viji.devices[i].id`](/p5/external-devices) | `string` | Unique device identifier | [Overview](/p5/external-devices) |\n| [`viji.devices[i].name`](/p5/external-devices) | `string` | User-friendly device name | [Overview](/p5/external-devices) |\n| [`viji.devices[i].motion`](/p5/external-devices/sensors) | `DeviceMotionData \\| null` | Device accelerometer/gyroscope | [Device Sensors](/p5/external-devices/sensors) |\n| [`viji.devices[i].orientation`](/p5/external-devices/sensors) | `DeviceOrientationData \\| null` | Device orientation | [Device Sensors](/p5/external-devices/sensors) |\n| [`viji.devices[i].video`](/p5/external-devices/video) | `VideoAPI \\| null` | Device camera video | [Device Video](/p5/external-devices/video) |\n| [`viji.devices[i].audio`](/p5/external-devices/audio) | `AudioStreamAPI \\| null` | Device audio stream | [Device Audio](/p5/external-devices/audio) |\n\n## Streams\n\n| Member | Type | Description |\n|--------|------|-------------|\n| `viji.videoStreams` | `VideoAPI[]` | Additional video streams provided by the host |\n| `viji.audioStreams` | `AudioStreamAPI[]` | Additional audio streams provided by the host |\n\nEach `videoStreams` element has the same shape as [`viji.video`](/p5/video). Each `audioStreams` element provides lightweight audio analysis (volume, frequency bands, spectral features) but does **not** include beat detection or BPM tracking — see [`viji.audio`](/p5/audio) for full analysis on the main stream.\n\nBoth arrays may be empty if the host does not provide additional streams. Audio streams from external devices appear on `device.audio`, not in `viji.audioStreams`.\n\n## Related\n\n- [Quick Start](/p5/quickstart) — getting started with the P5 renderer\n- [Scene Structure](/p5/scene-structure) — setup/render pattern and instance mode\n- [Drawing with P5](/p5/drawing) — Viji-specific drawing patterns\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers\n- [Native API Reference](/native/api-reference) — the same API in the Native renderer\n- [Shader API Reference](/shader/api-reference) — built-in uniforms for shaders\n- [P5.js Reference](https://p5js.org/reference/) — official P5.js documentation"
|
|
1977
2013
|
}
|
|
1978
2014
|
]
|
|
1979
2015
|
},
|
|
@@ -2099,7 +2135,7 @@ export const docsApi = {
|
|
|
2099
2135
|
"content": [
|
|
2100
2136
|
{
|
|
2101
2137
|
"type": "text",
|
|
2102
|
-
"markdown": "# Parameters\n\nParameters give users real-time control over your P5 scene. Define them at the top level, and Viji renders corresponding UI controls in the host application. Read `.value` inside `render()` to get the current state.\n\n## Parameter Types\n\n| Type | Function | Value | Use For |\n|---|---|---|---|\n| [Slider](slider/) | [`viji.slider(default, config)`](slider/) | `number` | Continuous numeric ranges (speed, size, opacity) |\n| [Number](number/) | [`viji.number(default, config)`](number/) | `number` | Precise numeric input (counts, thresholds) |\n| [Color](color/) | [`viji.color(default, config)`](color/) | `string` | Hex color values (`'#rrggbb'`) |\n| [Toggle](toggle/) | [`viji.toggle(default, config)`](toggle/) | `boolean` | On/off switches (enable audio, show trail) |\n| [Select](select/) | [`viji.select(default, config)`](select/) | `string \\| number` | Dropdown from predefined options (blend mode, shape type) |\n| [Text](text/) | [`viji.text(default, config)`](text/) | `string` | Free-form text input (titles, labels) |\n| [Image](image/) | [`viji.image(default, config)`](image/) | `ImageBitmap \\| null` | User-uploaded images and textures |\n| [Button](button/) | [`viji.button(config)`](button/) | `boolean` | Momentary trigger — true for 1 frame (resets, spawns) |\n\n## Basic Pattern\n\n```javascript\n// @renderer p5\n\n// 1. Define at top level — runs once\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst color = viji.color('#ff6600', { label: 'Color' });\nconst mirror = viji.toggle(false, { label: 'Mirror' });\n\n// 2. Read .value in render() — updates in real-time\nfunction render(viji, p5) {\n const r = parseInt(color.value.slice(1, 3), 16);\n const g = parseInt(color.value.slice(3, 5), 16);\n const b = parseInt(color.value.slice(5, 7), 16);\n p5.fill(r, g, b);\n // speed.value, mirror.value, etc.\n}\n```\n\n> [!WARNING]\n> Parameters must be declared at the **top level** of your scene, never inside `setup()` or `render()`. They are registered once and sent to the host before either function runs. Declaring them inside `setup()` would register the parameter too late — no UI control would appear. Declaring them inside `render()` would re-register the parameter every frame, resetting its value to the default.\n\n## Image Parameters in P5\n\nWhen using [`viji.image()`](image/) with P5 drawing functions, use the `.p5` property instead of `.value`:\n\n```javascript\nconst photo = viji.image(null, { label: 'Photo' });\n\nfunction render(viji, p5) {\n if (photo.value) {\n p5.image(photo.p5, 0, 0, viji.width, viji.height);\n }\n}\n```\n\nThe `.p5` property wraps the raw image data in a P5-compatible object. Use `.value` to check if an image is loaded, and `.p5` when passing to P5 drawing functions.\n\n## Common Config Keys\n\nAll parameter types share these optional configuration keys:\n\n| Key | Type | Default | Description |\n|---|---|---|---|\n| `label` | `string` | **(required)** | Display name shown in the parameter UI |\n| `description` | `string` | — | Tooltip or help text |\n| `group` | `string` | `'general'` | Group name for organizing parameters — see [Grouping](grouping/) |\n| `category` | `ParameterCategory` | `'general'` | Controls visibility based on capabilities — see [Categories](categories/) |\n\n## Organization\n\nAs scenes grow, you'll want to organize parameters into logical sections and control when they're visible:\n\n- **[Grouping](grouping/)** — Collect related parameters under named groups (e.g., \"animation\", \"shape\", \"audio\"). Parameters with the same `group` string appear together in the UI.\n- **[Categories](categories/)** — Tag parameters as `'general'`, `'audio'`, `'video'`, or `'interaction'` to automatically show/hide them based on what inputs are currently active.\n\n## Related\n\n- [Slider](slider/) — the most common parameter type\n- [Image](image/) — image parameters with the `.p5` property\n- [Grouping](grouping/) — organizing parameters into named groups\n- [Categories](categories/) — visibility based on capabilities\n- [Native Parameters](/native/parameters) — same system in the native renderer\n- [Shader Parameters](/shader/parameters) — comment-directive syntax for shaders\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
2138
|
+
"markdown": "# Parameters\n\nParameters give users real-time control over your P5 scene. Define them at the top level, and Viji renders corresponding UI controls in the host application. Read `.value` inside `render()` to get the current state.\n\n## Parameter Types\n\n| Type | Function | Value | Use For |\n|---|---|---|---|\n| [Slider](slider/) | [`viji.slider(default, config)`](slider/) | `number` | Continuous numeric ranges (speed, size, opacity) |\n| [Number](number/) | [`viji.number(default, config)`](number/) | `number` | Precise numeric input (counts, thresholds) |\n| [Color](color/) | [`viji.color(default, config)`](color/) | `string` | Hex color values (`'#rrggbb'`) |\n| [Toggle](toggle/) | [`viji.toggle(default, config)`](toggle/) | `boolean` | On/off switches (enable audio, show trail) |\n| [Select](select/) | [`viji.select(default, config)`](select/) | `string \\| number` | Dropdown from predefined options (blend mode, shape type) |\n| [Text](text/) | [`viji.text(default, config)`](text/) | `string` | Free-form text input (titles, labels) |\n| [Image](image/) | [`viji.image(default, config)`](image/) | `ImageBitmap \\| null` | User-uploaded images and textures |\n| [Button](button/) | [`viji.button(config)`](button/) | `boolean` | Momentary trigger — true for 1 frame (resets, spawns) |\n| Coordinate | [`viji.coordinate(default, config)`](coordinate/) | `{ x: number, y: number }` | 2D coordinate pad control. Both axes range from -1 to 1. |\n\n## Basic Pattern\n\n```javascript\n// @renderer p5\n\n// 1. Define at top level — runs once\nconst speed = viji.slider(1, { min: 0.1, max: 5, label: 'Speed' });\nconst color = viji.color('#ff6600', { label: 'Color' });\nconst mirror = viji.toggle(false, { label: 'Mirror' });\n\n// 2. Read .value in render() — updates in real-time\nfunction render(viji, p5) {\n const r = parseInt(color.value.slice(1, 3), 16);\n const g = parseInt(color.value.slice(3, 5), 16);\n const b = parseInt(color.value.slice(5, 7), 16);\n p5.fill(r, g, b);\n // speed.value, mirror.value, etc.\n}\n```\n\n> [!WARNING]\n> Parameters must be declared at the **top level** of your scene, never inside `setup()` or `render()`. They are registered once and sent to the host before either function runs. Declaring them inside `setup()` would register the parameter too late — no UI control would appear. Declaring them inside `render()` would re-register the parameter every frame, resetting its value to the default.\n\n## Image Parameters in P5\n\nWhen using [`viji.image()`](image/) with P5 drawing functions, use the `.p5` property instead of `.value`:\n\n```javascript\nconst photo = viji.image(null, { label: 'Photo' });\n\nfunction render(viji, p5) {\n if (photo.value) {\n p5.image(photo.p5, 0, 0, viji.width, viji.height);\n }\n}\n```\n\nThe `.p5` property wraps the raw image data in a P5-compatible object. Use `.value` to check if an image is loaded, and `.p5` when passing to P5 drawing functions.\n\n## Common Config Keys\n\nAll parameter types share these optional configuration keys:\n\n| Key | Type | Default | Description |\n|---|---|---|---|\n| `label` | `string` | **(required)** | Display name shown in the parameter UI |\n| `description` | `string` | — | Tooltip or help text |\n| `group` | `string` | `'general'` | Group name for organizing parameters — see [Grouping](grouping/) |\n| `category` | `ParameterCategory` | `'general'` | Controls visibility based on capabilities — see [Categories](categories/) |\n\n## Organization\n\nAs scenes grow, you'll want to organize parameters into logical sections and control when they're visible:\n\n- **[Grouping](grouping/)** — Collect related parameters under named groups (e.g., \"animation\", \"shape\", \"audio\"). Parameters with the same `group` string appear together in the UI.\n- **[Categories](categories/)** — Tag parameters as `'general'`, `'audio'`, `'video'`, or `'interaction'` to automatically show/hide them based on what inputs are currently active.\n\n## Related\n\n- [Slider](slider/) — the most common parameter type\n- [Coordinate](coordinate/) — 2D position control\n- [Image](image/) — image parameters with the `.p5` property\n- [Grouping](grouping/) — organizing parameters into named groups\n- [Categories](categories/) — visibility based on capabilities\n- [Native Parameters](/native/parameters) — same system in the native renderer\n- [Shader Parameters](/shader/parameters) — comment-directive syntax for shaders\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
2103
2139
|
}
|
|
2104
2140
|
]
|
|
2105
2141
|
},
|
|
@@ -2261,6 +2297,27 @@ export const docsApi = {
|
|
|
2261
2297
|
}
|
|
2262
2298
|
]
|
|
2263
2299
|
},
|
|
2300
|
+
"p5-param-coordinate": {
|
|
2301
|
+
"id": "p5-param-coordinate",
|
|
2302
|
+
"title": "Coordinate Parameter",
|
|
2303
|
+
"description": "Create a 2D coordinate control for x/y position values from -1 to 1 in P5.js scenes.",
|
|
2304
|
+
"content": [
|
|
2305
|
+
{
|
|
2306
|
+
"type": "text",
|
|
2307
|
+
"markdown": "# viji.coordinate()\n\n```\ncoordinate(defaultValue: CoordinateValue, config: CoordinateConfig): CoordinateParameter\n```\n\nCreates a 2D coordinate parameter that the host application renders as a draggable pad control. The value is an `{ x, y }` object where both components range from **-1 to 1**. The artist defines the coordinate at the top level of the scene, and reads its current value inside `draw()`.\n\n## Parameters\n\n| Name | Type | Required | Default | Description |\n|------|------|----------|---------|-------------|\n| `defaultValue` | `{ x: number, y: number }` | Yes | — | Initial coordinate value (both -1 to 1) |\n| `config.step` | `number` | No | `0.01` | Snap increment for the coordinate values |\n| `config.label` | `string` | Yes | — | Display name shown in the parameter UI |\n| `config.description` | `string` | No | — | Tooltip or help text |\n| `config.group` | `string` | No | `'general'` | Group name for organizing parameters — see [Grouping](../grouping/) |\n| `config.category` | `ParameterCategory` | No | `'general'` | Controls visibility based on capabilities — see [Categories](../categories/) |\n\n## Return Value\n\nReturns a `CoordinateParameter` object:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `value` | `{ x: number, y: number }` | Current coordinate. Updates in real-time when the user drags the control. Both components are -1 to 1. |\n| `step` | `number` | Step increment |\n| `label` | `string` | Display label |\n| `description` | `string \\| undefined` | Description text |\n| `group` | `string` | Group name |\n| `category` | `ParameterCategory` | Parameter category |\n\n## Usage\n\nDefine coordinates at the **top level** of your scene code. Read `.value.x` and `.value.y` inside `draw()` to get the current position.\n\n```javascript\n// @renderer p5\n\nconst origin = viji.coordinate({ x: 0, y: 0 }, {\n label: 'Circle Position',\n group: 'position'\n});\n\nfunction draw(viji, p5) {\n p5.background(26, 26, 46);\n\n const cx = p5.width / 2 + origin.value.x * p5.width * 0.4;\n const cy = p5.height / 2 - origin.value.y * p5.height * 0.4;\n\n p5.fill(255, 107, 107);\n p5.noStroke();\n p5.ellipse(cx, cy, 80, 80);\n}\n```\n\n> [!NOTE]\n> Parameters must be defined at the top level, not inside `draw()`. They are registered once during scene initialization. Defining them inside `draw()` would re-register the parameter every frame, resetting its value to the default and making user changes ineffective."
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
"type": "live-example",
|
|
2311
|
+
"title": "Basic Coordinate",
|
|
2312
|
+
"sceneCode": "// @renderer p5\n\nconst origin = viji.coordinate({ x: 0, y: 0 }, {\n label: 'Circle Position',\n description: 'Drag to move the circle',\n group: 'position'\n});\n\nconst size = viji.slider(0.1, {\n min: 0.03,\n max: 0.3,\n step: 0.01,\n label: 'Size',\n group: 'position'\n});\n\nconst color = viji.color('#ff6b6b', {\n label: 'Color',\n group: 'appearance'\n});\n\nfunction draw(viji, p5) {\n p5.background(26, 26, 46);\n\n const s = Math.min(p5.width, p5.height);\n\n // Draw grid\n p5.stroke(255, 255, 255, 15);\n p5.strokeWeight(1);\n for (let i = -1; i <= 1; i += 0.25) {\n const px = p5.width / 2 + i * p5.width * 0.4;\n const py = p5.height / 2 - i * p5.height * 0.4;\n p5.line(px, 0, px, p5.height);\n p5.line(0, py, p5.width, py);\n }\n\n // Draw crosshair\n p5.stroke(255, 255, 255, 40);\n p5.line(p5.width / 2, 0, p5.width / 2, p5.height);\n p5.line(0, p5.height / 2, p5.width, p5.height / 2);\n\n // Map coordinate\n const cx = p5.width / 2 + origin.value.x * p5.width * 0.4;\n const cy = p5.height / 2 - origin.value.y * p5.height * 0.4;\n const r = size.value * s;\n\n // Draw circle\n p5.noStroke();\n p5.fill(color.value);\n p5.ellipse(cx, cy, r * 2, r * 2);\n\n // Coordinate readout\n p5.fill(255, 255, 255, 130);\n p5.textAlign(p5.CENTER);\n p5.textSize(Math.round(s * 0.025));\n p5.text(\n 'x: ' + origin.value.x.toFixed(2) + ' y: ' + origin.value.y.toFixed(2),\n p5.width / 2, p5.height - s * 0.03\n );\n}\n",
|
|
2313
|
+
"sceneFile": "coordinate-p5.scene.js"
|
|
2314
|
+
},
|
|
2315
|
+
{
|
|
2316
|
+
"type": "text",
|
|
2317
|
+
"markdown": "## Coordinate Space\n\nThe coordinate value uses a **normalized -1 to 1 range** on both axes:\n\n| Value | Position |\n|-------|----------|\n| `{ x: -1, y: -1 }` | Bottom-left |\n| `{ x: 0, y: 0 }` | Center |\n| `{ x: 1, y: 1 }` | Top-right |\n\nThe y-axis follows mathematical convention: positive y points **up**. When mapping to P5 canvas pixels, invert y since P5 canvas y increases downward.\n\n## Related\n\n- [Slider](../slider/) — single-axis numeric range\n- [Number](../number/) — precise numeric input\n- [Grouping](../grouping/) — organizing parameters into named groups\n- [Categories](../categories/) — controlling parameter visibility based on capabilities\n- [Native Coordinate](/native/parameters/coordinate) — equivalent for the Native renderer\n- [Shader Coordinate](/shader/parameters/coordinate) — equivalent for the Shader renderer"
|
|
2318
|
+
}
|
|
2319
|
+
]
|
|
2320
|
+
},
|
|
2264
2321
|
"p5-param-grouping": {
|
|
2265
2322
|
"id": "p5-param-grouping",
|
|
2266
2323
|
"title": "Grouping Parameters",
|
|
@@ -2911,7 +2968,7 @@ export const docsApi = {
|
|
|
2911
2968
|
},
|
|
2912
2969
|
{
|
|
2913
2970
|
"type": "text",
|
|
2914
|
-
"markdown": "### What's Happening\r\n\r\n**Comment directives — parsed before compilation:**\r\n\r\n- `// @renderer shader` tells Viji to use the shader renderer.\r\n- `// @viji-slider:speed ...` declares a parameter. Viji generates a `uniform float speed;` automatically.\r\n- `// @viji-color:tint ...` declares a color parameter. Viji generates a `uniform vec3 tint;`.\r\n- `// @viji-accumulator:phase rate:speed` creates a CPU-side accumulator that adds `speed × deltaTime` every frame. The result is a `uniform float phase;` that increases smoothly — no jumps when the slider changes.\r\n\r\n**`void main()` — runs for every pixel, every frame:**\r\n\r\n- `gl_FragCoord.xy / u_resolution` gives normalized UV coordinates (0–1).\r\n- `phase` is the accumulator — use it instead of `u_time * speed` for smooth, slider-driven animation.\r\n- `speed`, `scale`, `tint` are your parameter uniforms — updated live as the user adjusts controls.\r\n- `gl_FragColor` sets the output color for each pixel.\r\n\r\n> [!NOTE]\r\n> Parameter declarations use **single-line `//` comments only**. Block comments `/* */` are not parsed for `@viji-*` directives.\r\n\r\n## Scene Structure\r\n\r\nA shader scene is a GLSL fragment shader with comment directives:\r\n\r\n```glsl\r\n// @renderer shader\r\n// @viji-slider:brightness label:\"Brightness\" default:1.0 min:0.0 max:2.0\r\n\r\nvoid main() {\r\n vec2 uv = gl_FragCoord.xy / u_resolution;\r\n gl_FragColor = vec4(uv * brightness, 0.5, 1.0);\r\n}\r\n```\r\n\r\n- **No `precision` or `uniform` declarations needed.** Viji auto-injects `precision mediump float;` and all uniform declarations.\r\n- **No vertex shader.** Viji renders a fullscreen quad; your fragment shader defines the color of every pixel.\r\n- **Parameters become uniforms.** `// @viji-slider:name` becomes `uniform float name;` automatically.\r\n\r\n> [!NOTE]\r\n> The Viji shader renderer automatically injects `precision mediump float;` and all `uniform` declarations — both built-in uniforms (`u_resolution`, `u_time`, etc.) and parameter uniforms from `@viji-*` directives. Write only your helper functions and `void main() { ... }`. Do NOT redeclare `precision` or any uniforms — they will conflict. If you use `#version 300 es`, Viji will handle its placement automatically.\r\n\r\n## Parameter Types\r\n\r\nDeclare parameters with `// @viji-TYPE:uniformName key:value` syntax:\r\n\r\n| Type | Uniform |
|
|
2971
|
+
"markdown": "### What's Happening\r\n\r\n**Comment directives — parsed before compilation:**\r\n\r\n- `// @renderer shader` tells Viji to use the shader renderer.\r\n- `// @viji-slider:speed ...` declares a parameter. Viji generates a `uniform float speed;` automatically.\r\n- `// @viji-color:tint ...` declares a color parameter. Viji generates a `uniform vec3 tint;`.\r\n- `// @viji-accumulator:phase rate:speed` creates a CPU-side accumulator that adds `speed × deltaTime` every frame. The result is a `uniform float phase;` that increases smoothly — no jumps when the slider changes.\r\n\r\n**`void main()` — runs for every pixel, every frame:**\r\n\r\n- `gl_FragCoord.xy / u_resolution` gives normalized UV coordinates (0–1).\r\n- `phase` is the accumulator — use it instead of `u_time * speed` for smooth, slider-driven animation.\r\n- `speed`, `scale`, `tint` are your parameter uniforms — updated live as the user adjusts controls.\r\n- `gl_FragColor` sets the output color for each pixel.\r\n\r\n> [!NOTE]\r\n> Parameter declarations use **single-line `//` comments only**. Block comments `/* */` are not parsed for `@viji-*` directives.\r\n\r\n## Scene Structure\r\n\r\nA shader scene is a GLSL fragment shader with comment directives:\r\n\r\n```glsl\r\n// @renderer shader\r\n// @viji-slider:brightness label:\"Brightness\" default:1.0 min:0.0 max:2.0\r\n\r\nvoid main() {\r\n vec2 uv = gl_FragCoord.xy / u_resolution;\r\n gl_FragColor = vec4(uv * brightness, 0.5, 1.0);\r\n}\r\n```\r\n\r\n- **No `precision` or `uniform` declarations needed.** Viji auto-injects `precision mediump float;` and all uniform declarations.\r\n- **No vertex shader.** Viji renders a fullscreen quad; your fragment shader defines the color of every pixel.\r\n- **Parameters become uniforms.** `// @viji-slider:name` becomes `uniform float name;` automatically.\r\n\r\n> [!NOTE]\r\n> The Viji shader renderer automatically injects `precision mediump float;` and all `uniform` declarations — both built-in uniforms (`u_resolution`, `u_time`, etc.) and parameter uniforms from `@viji-*` directives. Write only your helper functions and `void main() { ... }`. Do NOT redeclare `precision` or any uniforms — they will conflict. If you use `#version 300 es`, Viji will handle its placement automatically.\r\n\r\n## Parameter Types\r\n\r\nDeclare parameters with `// @viji-TYPE:uniformName key:value` syntax:\r\n\r\n| Type | Directive | Uniform Type | Default | Description |\r\n|------|-----------|--------------|---------|-------------|\r\n| `slider` | `@viji-slider` | `float` | `default:1.0 min:0.0 max:5.0` | `// @viji-slider:speed label:\"Speed\" default:1.0 min:0.0 max:5.0` |\r\n| `number` | `@viji-number` | `float` | `default:10.0 min:1.0 max:100.0` | `// @viji-number:count label:\"Count\" default:10.0 min:1.0 max:100.0` |\r\n| `color` | `@viji-color` | `vec3` | `default:#ff6600` | `// @viji-color:tint label:\"Tint\" default:#ff6600` |\r\n| `toggle` | `@viji-toggle` | `bool` | `default:false` | `// @viji-toggle:invert label:\"Invert\" default:false` |\r\n| `select` | `@viji-select` | `int` | `default:0 options:[\"Wave\",\"Spiral\",\"Grid\"]` | `// @viji-select:mode label:\"Mode\" default:0 options:[\"Wave\",\"Spiral\",\"Grid\"]` |\r\n| `image` | `@viji-image` | `sampler2D` | `label:\"Texture\"` | `// @viji-image:tex label:\"Texture\"` |\r\n| `button` | `@viji-button` | `bool` | `label:\"Trigger\"` | `// @viji-button:trigger label:\"Trigger\"` |\r\n| `coordinate` | `@viji-coordinate` | `vec2` | `default:[0,0]` | 2D position pad, -1 to 1 |\r\n| `accumulator` | `@viji-accumulator` | `float` | `rate:speed` | `// @viji-accumulator:phase rate:speed` |\r\n\r\nConfig keys: `label`, `default`, `min`, `max`, `step`, `description`, `group`, `category`.\r\n\r\n### Accumulators\r\n\r\nAccumulators solve the \"jumping animation\" problem. When you write `u_time * speed`, changing the `speed` slider causes a visible jump because the entire phase is recalculated instantly. Accumulators integrate the rate over time on the CPU side:\r\n\r\n```glsl\r\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\r\n// @viji-accumulator:phase rate:speed\r\n```\r\n\r\n- `phase` increases by `speed × deltaTime` each frame — changing `speed` only affects future growth, never jumps backward.\r\n- `rate` can reference any declared parameter name or be a numeric constant (e.g., `rate:1.5`).\r\n- Accumulators have no UI control — they are internal uniform values.\r\n- Optional `default` sets the starting value (defaults to 0).\r\n\r\n> [!WARNING]\r\n> Do not use the `u_` prefix for your parameter uniform names — it is reserved for built-in Viji uniforms. Use descriptive names like `speed`, `colorMix`, `intensity` instead.\r\n\r\n## Built-in Uniforms\r\n\r\nThese are always available — no declaration needed:\r\n\r\n| Uniform | Type | Description |\r\n|---------|------|-------------|\r\n| `u_resolution` | `vec2` | Canvas width and height in pixels |\r\n| `u_time` | `float` | Elapsed seconds since scene start |\r\n| `u_deltaTime` | `float` | Seconds since last frame |\r\n| `u_frame` | `int` | Current frame number |\r\n| `u_pointer` | `vec2` | Unified input position — mouse or touch (pixels) |\r\n| `u_pointerDown` | `bool` | Unified input active (left-click or touch) |\r\n| `u_mouse` | `vec2` | Mouse position in pixels |\r\n| `u_mousePressed` | `bool` | Any mouse button is pressed |\r\n| `u_audioVolume` | `float` | Overall audio volume (0–1) |\r\n| `u_audioLow` | `float` | Low frequency energy (0–1) |\r\n| `u_audioMid` | `float` | Mid frequency energy (0–1) |\r\n| `u_audioHigh` | `float` | High frequency energy (0–1) |\r\n| `u_audioKick` | `float` | Kick beat detection (0–1) |\r\n| `u_video` | `sampler2D` | Current video frame |\r\n\r\nSee [API Reference](/shader/api-reference) for the complete list of 100+ built-in uniforms.\r\n\r\n## Essential Patterns\r\n\r\n**Normalized coordinates:**\r\n\r\n```glsl\r\nvec2 uv = gl_FragCoord.xy / u_resolution; // 0..1\r\nvec2 centered = uv - 0.5; // -0.5..0.5\r\ncentered.x *= u_resolution.x / u_resolution.y; // aspect-corrected\r\n```\r\n\r\n**Distance fields:**\r\n\r\n```glsl\r\nfloat d = length(centered); // distance from center\r\nfloat circle = smoothstep(0.3, 0.29, d); // anti-aliased circle\r\n```\r\n\r\n> [!NOTE]\r\n> Always use `u_resolution` for positioning and sizing and `u_time` / `u_deltaTime` for animation. This keeps your shader resolution-agnostic and frame-rate-independent.\r\n\r\n## GLSL Version\r\n\r\nBy default, shaders use **GLSL ES 1.00** (WebGL 1). If you need WebGL 2 features, add `#version 300 es` as the first line:\r\n\r\n```glsl\r\n#version 300 es\r\n// @renderer shader\r\n\r\n// ES 3.00 requires explicit output declaration\r\nout vec4 fragColor;\r\n\r\nvoid main() {\r\n vec2 uv = gl_FragCoord.xy / u_resolution;\r\n fragColor = vec4(uv, sin(u_time), 1.0);\r\n}\r\n```\r\n\r\nES 3.00 differences: `gl_FragColor` → `out vec4`, `texture2D()` → `texture()`. Use ES 1.00 for maximum compatibility.\r\n\r\n## Backbuffer (Previous Frame)\r\n\r\nViji gives you access to the previous frame as a texture — just reference `backbuffer` in your code and it's automatically enabled:\r\n\r\n```glsl\r\nvoid main() {\r\n vec2 uv = gl_FragCoord.xy / u_resolution;\r\n vec4 prev = texture2D(backbuffer, uv); // previous frame\r\n vec3 current = vec3(/* ... your effect ... */);\r\n gl_FragColor = vec4(mix(prev.rgb, current, 0.1), 1.0); // 90% trail\r\n}\r\n```\r\n\r\nThis enables feedback effects, trails, motion blur, and accumulation buffers. No setup needed — Viji detects the `backbuffer` reference and creates the ping-pong framebuffers automatically.\r\n\r\nSee [Backbuffer](/shader/backbuffer) for detailed patterns and techniques.\r\n\r\n## Shadertoy Compatibility\r\n\r\nIf you have existing Shadertoy shaders, see [Shadertoy Compatibility](/shader/shadertoy) for a mapping of Shadertoy uniforms to Viji equivalents.\r\n\r\n## Next Steps\r\n\r\n- [Shader Basics](/shader/basics) — uniforms, coordinate systems, techniques\r\n- [Parameters](/shader/parameters) — all parameter types for shaders\r\n- [Audio Uniforms](/shader/audio) — react to music in GLSL\r\n- [Backbuffer](/shader/backbuffer) — feedback effects using the previous frame\r\n- [API Reference](/shader/api-reference) — complete list of built-in uniforms\r\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
2915
2972
|
}
|
|
2916
2973
|
]
|
|
2917
2974
|
},
|
|
@@ -2922,7 +2979,7 @@ export const docsApi = {
|
|
|
2922
2979
|
"content": [
|
|
2923
2980
|
{
|
|
2924
2981
|
"type": "text",
|
|
2925
|
-
"markdown": "# API Reference\n\nViji auto-injects 160+ uniforms into every shader scene. This page is the complete list — use it as a quick lookup. Each entry links to its dedicated documentation page for full details and examples.\n\nAll uniforms listed below are always declared in the shader preamble (except [`backbuffer`](/shader/backbuffer), which is conditional). When data is not available, uniforms hold default values (zeros, false, or empty textures). Your shader compiles once with all declarations present — you do not need to conditionally declare them.\n\nNew to Viji shaders? Start with [Shader Basics](/shader/basics) instead.\n\n## Core / Timing\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_time`](/shader/timing) | `float` | Seconds elapsed since the scene started | [Timing](/shader/timing) |\n| [`u_deltaTime`](/shader/timing) | `float` | Seconds since the previous frame | [Timing](/shader/timing) |\n| [`u_frame`](/shader/timing) | `int` | Frame index (monotonically increasing) | [Timing](/shader/timing) |\n| [`u_fps`](/shader/timing) | `float` | Target FPS based on host's frame rate mode | [Timing](/shader/timing) |\n\n## Resolution\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_resolution`](/shader/resolution) | `vec2` | Canvas width and height in pixels | [Resolution](/shader/resolution) |\n\n## Mouse\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_mouse`](/shader/mouse) | `vec2` | Cursor position in pixels (WebGL Y-flipped) | [Mouse](/shader/mouse) |\n| [`u_mouseInCanvas`](/shader/mouse) | `bool` | Whether cursor is inside the canvas | [Mouse](/shader/mouse) |\n| [`u_mousePressed`](/shader/mouse) | `bool` | Whether any button is pressed | [Mouse](/shader/mouse) |\n| [`u_mouseLeft`](/shader/mouse) | `bool` | Left button state | [Mouse](/shader/mouse) |\n| [`u_mouseRight`](/shader/mouse) | `bool` | Right button state | [Mouse](/shader/mouse) |\n| [`u_mouseMiddle`](/shader/mouse) | `bool` | Middle button state | [Mouse](/shader/mouse) |\n| [`u_mouseDelta`](/shader/mouse) | `vec2` | Pixel movement this frame (Y-flipped) | [Mouse](/shader/mouse) |\n| [`u_mouseWheel`](/shader/mouse) | `float` | Scroll delta this frame | [Mouse](/shader/mouse) |\n| [`u_mouseWasPressed`](/shader/mouse) | `bool` | True for one frame when pressed | [Mouse](/shader/mouse) |\n| [`u_mouseWasReleased`](/shader/mouse) | `bool` | True for one frame when released | [Mouse](/shader/mouse) |\n\n## Keyboard\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_keySpace`](/shader/keyboard) | `bool` | Space bar | [Keyboard](/shader/keyboard) |\n| [`u_keyShift`](/shader/keyboard) | `bool` | Shift key | [Keyboard](/shader/keyboard) |\n| [`u_keyCtrl`](/shader/keyboard) | `bool` | Ctrl/Cmd key | [Keyboard](/shader/keyboard) |\n| [`u_keyAlt`](/shader/keyboard) | `bool` | Alt/Option key | [Keyboard](/shader/keyboard) |\n| [`u_keyW`](/shader/keyboard) | `bool` | W key | [Keyboard](/shader/keyboard) |\n| [`u_keyA`](/shader/keyboard) | `bool` | A key | [Keyboard](/shader/keyboard) |\n| [`u_keyS`](/shader/keyboard) | `bool` | S key | [Keyboard](/shader/keyboard) |\n| [`u_keyD`](/shader/keyboard) | `bool` | D key | [Keyboard](/shader/keyboard) |\n| [`u_keyUp`](/shader/keyboard) | `bool` | Up arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyDown`](/shader/keyboard) | `bool` | Down arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyLeft`](/shader/keyboard) | `bool` | Left arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyRight`](/shader/keyboard) | `bool` | Right arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyboard`](/shader/keyboard) | `sampler2D` | 256×3 LUMINANCE texture (row 0: held, row 1: pressed, row 2: toggle) | [Keyboard](/shader/keyboard) |\n\n## Touch\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_touchCount`](/shader/touch) | `int` | Number of active touches (0–5) | [Touch](/shader/touch) |\n| [`u_touch0`](/shader/touch) | `vec2` | Touch point 0 position (pixels, Y-flipped) | [Touch](/shader/touch) |\n| [`u_touch1`](/shader/touch) | `vec2` | Touch point 1 position | [Touch](/shader/touch) |\n| [`u_touch2`](/shader/touch) | `vec2` | Touch point 2 position | [Touch](/shader/touch) |\n| [`u_touch3`](/shader/touch) | `vec2` | Touch point 3 position | [Touch](/shader/touch) |\n| [`u_touch4`](/shader/touch) | `vec2` | Touch point 4 position | [Touch](/shader/touch) |\n\n## Pointer (Unified)\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_pointer`](/shader/pointer) | `vec2` | Primary pointer position (pixels, Y-flipped) | [Pointer](/shader/pointer) |\n| [`u_pointerDelta`](/shader/pointer) | `vec2` | Movement delta (Y-flipped) | [Pointer](/shader/pointer) |\n| [`u_pointerDown`](/shader/pointer) | `bool` | Whether pointer is active (click or touch) | [Pointer](/shader/pointer) |\n| [`u_pointerWasPressed`](/shader/pointer) | `bool` | True for one frame when pressed | [Pointer](/shader/pointer) |\n| [`u_pointerWasReleased`](/shader/pointer) | `bool` | True for one frame when released | [Pointer](/shader/pointer) |\n| [`u_pointerInCanvas`](/shader/pointer) | `bool` | Whether pointer is inside the canvas | [Pointer](/shader/pointer) |\n\n## Audio — Scalars\n\n### Volume\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioVolume`](/shader/audio/volume) | `float` | Current RMS volume 0–1 | [Volume](/shader/audio/volume) |\n| [`u_audioPeak`](/shader/audio/volume) | `float` | Peak volume 0–1 | [Volume](/shader/audio/volume) |\n| [`u_audioVolumeSmoothed`](/shader/audio/volume) | `float` | Smoothed volume (~200ms decay) | [Volume](/shader/audio/volume) |\n\n### Frequency Bands\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioLow`](/shader/audio/bands) | `float` | Low band energy (20–120 Hz) | [Bands](/shader/audio/bands) |\n| [`u_audioLowMid`](/shader/audio/bands) | `float` | Low-mid band energy (120–500 Hz) | [Bands](/shader/audio/bands) |\n| [`u_audioMid`](/shader/audio/bands) | `float` | Mid band energy (500–2 kHz) | [Bands](/shader/audio/bands) |\n| [`u_audioHighMid`](/shader/audio/bands) | `float` | High-mid band energy (2–6 kHz) | [Bands](/shader/audio/bands) |\n| [`u_audioHigh`](/shader/audio/bands) | `float` | High band energy (6–16 kHz) | [Bands](/shader/audio/bands) |\n| [`u_audioLowSmoothed`](/shader/audio/bands) | `float` | Smoothed low band | [Bands](/shader/audio/bands) |\n| [`u_audioLowMidSmoothed`](/shader/audio/bands) | `float` | Smoothed low-mid band | [Bands](/shader/audio/bands) |\n| [`u_audioMidSmoothed`](/shader/audio/bands) | `float` | Smoothed mid band | [Bands](/shader/audio/bands) |\n| [`u_audioHighMidSmoothed`](/shader/audio/bands) | `float` | Smoothed high-mid band | [Bands](/shader/audio/bands) |\n| [`u_audioHighSmoothed`](/shader/audio/bands) | `float` | Smoothed high band | [Bands](/shader/audio/bands) |\n\n### Beat Detection\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioKick`](/shader/audio/beat) | `float` | Kick beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioSnare`](/shader/audio/beat) | `float` | Snare beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioHat`](/shader/audio/beat) | `float` | Hi-hat beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioAny`](/shader/audio/beat) | `float` | Combined beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioKickSmoothed`](/shader/audio/beat) | `float` | Smoothed kick | [Beat](/shader/audio/beat) |\n| [`u_audioSnareSmoothed`](/shader/audio/beat) | `float` | Smoothed snare | [Beat](/shader/audio/beat) |\n| [`u_audioHatSmoothed`](/shader/audio/beat) | `float` | Smoothed hi-hat | [Beat](/shader/audio/beat) |\n| [`u_audioAnySmoothed`](/shader/audio/beat) | `float` | Smoothed combined | [Beat](/shader/audio/beat) |\n| [`u_audioKickTrigger`](/shader/audio/beat) | `bool` | Kick trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioSnareTrigger`](/shader/audio/beat) | `bool` | Snare trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioHatTrigger`](/shader/audio/beat) | `bool` | Hi-hat trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioAnyTrigger`](/shader/audio/beat) | `bool` | Any beat trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioBPM`](/shader/audio/beat) | `float` | Tracked BPM | [Beat](/shader/audio/beat) |\n| [`u_audioConfidence`](/shader/audio/beat) | `float` | Beat-tracker confidence 0–1 | [Beat](/shader/audio/beat) |\n| [`u_audioIsLocked`](/shader/audio/beat) | `bool` | Whether beat tracking is locked | [Beat](/shader/audio/beat) |\n\n### Spectral Analysis\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioBrightness`](/shader/audio/spectral) | `float` | Spectral brightness 0–1 | [Spectral](/shader/audio/spectral) |\n| [`u_audioFlatness`](/shader/audio/spectral) | `float` | Spectral flatness 0–1 | [Spectral](/shader/audio/spectral) |\n\n## Audio — Textures\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioFFT`](/shader/audio/fft) | `sampler2D` | FFT as 1D LUMINANCE strip (bin count × 1, values 0–255) | [FFT Texture](/shader/audio/fft) |\n| [`u_audioWaveform`](/shader/audio/waveform) | `sampler2D` | Time-domain waveform as 1D LUMINANCE strip (-1…1 mapped to 0–255) | [Waveform Texture](/shader/audio/waveform) |\n\n## Video\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_video`](/shader/video/basics) | `sampler2D` | Main video frame texture | [Video Basics](/shader/video/basics) |\n| [`u_videoResolution`](/shader/video/basics) | `vec2` | Video frame size in pixels (0,0 if disconnected) | [Video Basics](/shader/video/basics) |\n| [`u_videoFrameRate`](/shader/video/basics) | `float` | Video frame rate | [Video Basics](/shader/video/basics) |\n\n## CV — Face Detection\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_faceCount`](/shader/video/face-detection) | `int` | Number of detected faces | [Face Detection](/shader/video/face-detection) |\n| [`u_face0Bounds`](/shader/video/face-detection) | `vec4` | Bounding box (x, y, w, h) normalized 0–1 | [Face Detection](/shader/video/face-detection) |\n| [`u_face0Center`](/shader/video/face-detection) | `vec2` | Face center normalized 0–1 | [Face Detection](/shader/video/face-detection) |\n| [`u_face0HeadPose`](/shader/video/face-mesh) | `vec3` | Pitch, yaw, roll in degrees | [Face Mesh](/shader/video/face-mesh) |\n| [`u_face0Confidence`](/shader/video/face-detection) | `float` | Detection confidence | [Face Detection](/shader/video/face-detection) |\n\n### Expressions\n\n| Uniform | Type | Details |\n|---------|------|---------|\n| [`u_face0Neutral`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Happy`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Sad`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Angry`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Surprised`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Disgusted`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Fearful`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n\n### Blendshapes (52 uniforms)\n\nAll blendshapes are `float` values 0–1, following the ARKit naming convention. See [Face Mesh](/shader/video/face-mesh) for the full list and usage.\n\n| Uniform | Uniform | Uniform |\n|---------|---------|---------|\n| `u_face0BrowDownLeft` | `u_face0BrowDownRight` | `u_face0BrowInnerUp` |\n| `u_face0BrowOuterUpLeft` | `u_face0BrowOuterUpRight` | `u_face0CheekPuff` |\n| `u_face0CheekSquintLeft` | `u_face0CheekSquintRight` | `u_face0EyeBlinkLeft` |\n| `u_face0EyeBlinkRight` | `u_face0EyeLookDownLeft` | `u_face0EyeLookDownRight` |\n| `u_face0EyeLookInLeft` | `u_face0EyeLookInRight` | `u_face0EyeLookOutLeft` |\n| `u_face0EyeLookOutRight` | `u_face0EyeLookUpLeft` | `u_face0EyeLookUpRight` |\n| `u_face0EyeSquintLeft` | `u_face0EyeSquintRight` | `u_face0EyeWideLeft` |\n| `u_face0EyeWideRight` | `u_face0JawForward` | `u_face0JawLeft` |\n| `u_face0JawOpen` | `u_face0JawRight` | `u_face0MouthClose` |\n| `u_face0MouthDimpleLeft` | `u_face0MouthDimpleRight` | `u_face0MouthFrownLeft` |\n| `u_face0MouthFrownRight` | `u_face0MouthFunnel` | `u_face0MouthLeft` |\n| `u_face0MouthLowerDownLeft` | `u_face0MouthLowerDownRight` | `u_face0MouthPressLeft` |\n| `u_face0MouthPressRight` | `u_face0MouthPucker` | `u_face0MouthRight` |\n| `u_face0MouthRollLower` | `u_face0MouthRollUpper` | `u_face0MouthShrugLower` |\n| `u_face0MouthShrugUpper` | `u_face0MouthSmileLeft` | `u_face0MouthSmileRight` |\n| `u_face0MouthStretchLeft` | `u_face0MouthStretchRight` | `u_face0MouthUpperUpLeft` |\n| `u_face0MouthUpperUpRight` | `u_face0NoseSneerLeft` | `u_face0NoseSneerRight` |\n| `u_face0TongueOut` | | |\n\n## CV — Hand Tracking\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_handCount`](/shader/video/hand-tracking) | `int` | Number of detected hands (0–2) | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandPalm`](/shader/video/hand-tracking) | `vec3` | Left hand palm position | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_rightHandPalm`](/shader/video/hand-tracking) | `vec3` | Right hand palm position | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandConfidence`](/shader/video/hand-tracking) | `float` | Left hand confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_rightHandConfidence`](/shader/video/hand-tracking) | `float` | Right hand confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandBounds`](/shader/video/hand-tracking) | `vec4` | Left hand bounding box (x, y, w, h) | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_rightHandBounds`](/shader/video/hand-tracking) | `vec4` | Right hand bounding box (x, y, w, h) | [Hand Tracking](/shader/video/hand-tracking) |\n\n### Gesture Scores (per hand)\n\nAll gesture uniforms are `float` values 0–1. Replace `left` with `right` for the other hand.\n\n| Uniform | Description | Details |\n|---------|-------------|---------|\n| [`u_leftHandFist`](/shader/video/hand-tracking) | Fist gesture confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandOpenPalm`](/shader/video/hand-tracking) | Open palm confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandPeace`](/shader/video/hand-tracking) | Peace/V-sign confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandThumbsUp`](/shader/video/hand-tracking) | Thumbs up confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandThumbsDown`](/shader/video/hand-tracking) | Thumbs down confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandPointing`](/shader/video/hand-tracking) | Pointing confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandILoveYou`](/shader/video/hand-tracking) | I Love You sign confidence | [Hand Tracking](/shader/video/hand-tracking) |\n\n## CV — Pose Detection\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_poseDetected`](/shader/video/pose-detection) | `bool` | Whether a body pose is detected | [Pose Detection](/shader/video/pose-detection) |\n| [`u_poseConfidence`](/shader/video/pose-detection) | `float` | Pose detection confidence | [Pose Detection](/shader/video/pose-detection) |\n| [`u_nosePosition`](/shader/video/pose-detection) | `vec2` | Nose landmark position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftShoulderPosition`](/shader/video/pose-detection) | `vec2` | Left shoulder position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightShoulderPosition`](/shader/video/pose-detection) | `vec2` | Right shoulder position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftElbowPosition`](/shader/video/pose-detection) | `vec2` | Left elbow position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightElbowPosition`](/shader/video/pose-detection) | `vec2` | Right elbow position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftWristPosition`](/shader/video/pose-detection) | `vec2` | Left wrist position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightWristPosition`](/shader/video/pose-detection) | `vec2` | Right wrist position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftHipPosition`](/shader/video/pose-detection) | `vec2` | Left hip position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightHipPosition`](/shader/video/pose-detection) | `vec2` | Right hip position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftKneePosition`](/shader/video/pose-detection) | `vec2` | Left knee position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightKneePosition`](/shader/video/pose-detection) | `vec2` | Right knee position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftAnklePosition`](/shader/video/pose-detection) | `vec2` | Left ankle position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightAnklePosition`](/shader/video/pose-detection) | `vec2` | Right ankle position | [Pose Detection](/shader/video/pose-detection) |\n\n## CV — Body Segmentation\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_segmentationMask`](/shader/video/body-segmentation) | `sampler2D` | Body mask (LUMINANCE: 0 = background, 1 = person) | [Segmentation](/shader/video/body-segmentation) |\n| [`u_segmentationRes`](/shader/video/body-segmentation) | `vec2` | Mask dimensions in pixels | [Segmentation](/shader/video/body-segmentation) |\n\n## Device Sensors\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_deviceAcceleration`](/shader/sensors) | `vec3` | Acceleration without gravity (m/s²) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceAccelerationGravity`](/shader/sensors) | `vec3` | Acceleration with gravity (m/s²) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceRotationRate`](/shader/sensors) | `vec3` | Gyroscope: alpha, beta, gamma (deg/s) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceOrientation`](/shader/sensors) | `vec3` | Orientation: alpha, beta, gamma (degrees) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceOrientationAbsolute`](/shader/sensors) | `bool` | Whether orientation is magnetometer-based | [Sensor Uniforms](/shader/sensors) |\n\n## External Devices — Video\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_deviceCount`](/shader/external-devices) | `int` | Number of devices with active cameras (0–8) | [Overview](/shader/external-devices) |\n| [`u_device0`](/shader/external-devices/video) – `u_device7` | `sampler2D` | Device camera frame texture | [Video Textures](/shader/external-devices/video) |\n| [`u_device0Resolution`](/shader/external-devices/video) – `u_device7Resolution` | `vec2` | Device camera frame size | [Video Textures](/shader/external-devices/video) |\n| [`u_device0Connected`](/shader/external-devices/video) – `u_device7Connected` | `bool` | Whether device camera is active | [Video Textures](/shader/external-devices/video) |\n\n> [!NOTE]\n> Audio stream uniforms from devices are accessed via `u_audioStream{i}*` uniforms (same pool as additional audio streams, different index range managed by the host).\n\n## External Devices — Sensors\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_externalDeviceCount`](/shader/external-devices) | `int` | Number of connected external devices (0–8) | [Overview](/shader/external-devices) |\n| [`u_device0Acceleration`](/shader/external-devices/sensors) – `u_device7Acceleration` | `vec3` | Per-device acceleration without gravity | [Sensor Uniforms](/shader/external-devices/sensors) |\n| [`u_device0AccelerationGravity`](/shader/external-devices/sensors) – `u_device7AccelerationGravity` | `vec3` | Per-device acceleration with gravity | [Sensor Uniforms](/shader/external-devices/sensors) |\n| [`u_device0RotationRate`](/shader/external-devices/sensors) – `u_device7RotationRate` | `vec3` | Per-device rotation rate | [Sensor Uniforms](/shader/external-devices/sensors) |\n| [`u_device0Orientation`](/shader/external-devices/sensors) – `u_device7Orientation` | `vec3` | Per-device orientation angles | [Sensor Uniforms](/shader/external-devices/sensors) |\n\n> [!NOTE]\n> `u_device{i}` (sampler2D) is the **camera texture** for device slot `i`. `u_device{i}Acceleration` and similar are the **IMU sensors** for the same device — different data, same index.\n\n## Streams (Compositor)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_videoStreamCount` | `int` | Number of active streams (0–8) |\n| `u_videoStream0` – `u_videoStream7` | `sampler2D` | Stream frame textures |\n| `u_videoStream0Resolution` – `u_videoStream7Resolution` | `vec2` | Stream frame sizes in pixels |\n| `u_videoStream0Connected` – `u_videoStream7Connected` | `bool` | Whether stream has an active frame |\n\nStreams are additional video sources injected by the host application — they are used internally by Viji's compositor for mixing multiple scenes together. When no streams are provided, `u_videoStreamCount` is `0` and the textures sample as black. Each stream works the same way as [`u_video`](/shader/video/basics).\n\n## Audio Streams\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioStreamCount` | `int` | Number of active audio streams (0–8) |\n| `u_audioStream0Connected` – `u_audioStream7Connected` | `bool` | Whether stream is actively providing audio |\n| `u_audioStream0Volume` – `u_audioStream7Volume` | `float` | Stream volume (0–1) |\n| `u_audioStream0Low` – `u_audioStream7Low` | `float` | Low frequency band energy (0–1) |\n| `u_audioStream0LowMid` – `u_audioStream7LowMid` | `float` | Low-mid band energy (0–1) |\n| `u_audioStream0Mid` – `u_audioStream7Mid` | `float` | Mid band energy (0–1) |\n| `u_audioStream0HighMid` – `u_audioStream7HighMid` | `float` | High-mid band energy (0–1) |\n| `u_audioStream0High` – `u_audioStream7High` | `float` | High band energy (0–1) |\n| `u_audioStream0Brightness` – `u_audioStream7Brightness` | `float` | Spectral brightness (0–1) |\n| `u_audioStream0Flatness` – `u_audioStream7Flatness` | `float` | Spectral flatness (0–1) |\n\nAdditional audio streams provide lightweight scalar uniforms only — **no** FFT or waveform textures. Beat detection, BPM, and onset uniforms are only available on the main audio stream (`u_audioVolume`, `u_audioBPM`, etc.).\n\nWhen no audio streams are provided, `u_audioStreamCount` is `0` and all per-stream uniforms default to `0.0` / `false`.\n\n## Backbuffer\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`backbuffer`](/shader/backbuffer) | `sampler2D` | Previous frame texture (feedback effects) | [Backbuffer & Feedback](/shader/backbuffer) |\n\n> [!WARNING]\n> `backbuffer` is **conditional** — it is only injected if the word `backbuffer` appears anywhere in your shader source (including comments). It has no `u_` prefix. See [Backbuffer & Feedback](/shader/backbuffer) for details.\n\n## Parameter Directives\n\nDeclare parameters using `// @viji-TYPE:uniformName key:value ...` comments. Each directive generates a uniform and a UI control in the host.\n\n| Directive | Uniform Type | UI Control | Details |\n|-----------|-------------|------------|---------|\n| [`@viji-slider`](/shader/parameters/slider) | `float` | Numeric slider | [Slider](/shader/parameters/slider) |\n| [`@viji-number`](/shader/parameters/number) | `float` | Numeric input | [Number](/shader/parameters/number) |\n| [`@viji-color`](/shader/parameters/color) | `vec3` | Color picker (hex → RGB 0–1) | [Color](/shader/parameters/color) |\n| [`@viji-toggle`](/shader/parameters/toggle) | `bool` | On/off switch | [Toggle](/shader/parameters/toggle) |\n| [`@viji-select`](/shader/parameters/select) | `int` | Dropdown (0-based option index) | [Select](/shader/parameters/select) |\n| [`@viji-image`](/shader/parameters/image) | `sampler2D` | Image upload | [Image](/shader/parameters/image) |\n| [`@viji-button`](/shader/parameters/button) | `bool` | Momentary button (true for one frame) | [Button](/shader/parameters/button) |\n| [`@viji-accumulator`](/shader/parameters/accumulator) | `float` | CPU-side: `+= rate × deltaTime` | [Accumulator](/shader/parameters/accumulator) |\n\nSee [Parameters Overview](/shader/parameters) for syntax, [Grouping](/shader/parameters/grouping) and [Categories](/shader/parameters/categories) for organization.\n\n## Related\n\n- [Shader Basics](/shader/basics) — auto-injection, GLSL versions, `@renderer shader`\n- [Shader Quick Start](/shader/quickstart) — getting started with shader scenes\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers\n- [Native API Reference](/native/api-reference) — JavaScript API for the Native renderer\n- [P5 API Reference](/p5/api-reference) — JavaScript API for the P5 renderer"
|
|
2982
|
+
"markdown": "# API Reference\n\nViji auto-injects 160+ uniforms into every shader scene. This page is the complete list — use it as a quick lookup. Each entry links to its dedicated documentation page for full details and examples.\n\nAll uniforms listed below are always declared in the shader preamble (except [`backbuffer`](/shader/backbuffer), which is conditional). When data is not available, uniforms hold default values (zeros, false, or empty textures). Your shader compiles once with all declarations present — you do not need to conditionally declare them.\n\nNew to Viji shaders? Start with [Shader Basics](/shader/basics) instead.\n\n## Core / Timing\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_time`](/shader/timing) | `float` | Seconds elapsed since the scene started | [Timing](/shader/timing) |\n| [`u_deltaTime`](/shader/timing) | `float` | Seconds since the previous frame | [Timing](/shader/timing) |\n| [`u_frame`](/shader/timing) | `int` | Frame index (monotonically increasing) | [Timing](/shader/timing) |\n| [`u_fps`](/shader/timing) | `float` | Target FPS based on host's frame rate mode | [Timing](/shader/timing) |\n\n## Resolution\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_resolution`](/shader/resolution) | `vec2` | Canvas width and height in pixels | [Resolution](/shader/resolution) |\n\n## Mouse\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_mouse`](/shader/mouse) | `vec2` | Cursor position in pixels (WebGL Y-flipped) | [Mouse](/shader/mouse) |\n| [`u_mouseInCanvas`](/shader/mouse) | `bool` | Whether cursor is inside the canvas | [Mouse](/shader/mouse) |\n| [`u_mousePressed`](/shader/mouse) | `bool` | Whether any button is pressed | [Mouse](/shader/mouse) |\n| [`u_mouseLeft`](/shader/mouse) | `bool` | Left button state | [Mouse](/shader/mouse) |\n| [`u_mouseRight`](/shader/mouse) | `bool` | Right button state | [Mouse](/shader/mouse) |\n| [`u_mouseMiddle`](/shader/mouse) | `bool` | Middle button state | [Mouse](/shader/mouse) |\n| [`u_mouseDelta`](/shader/mouse) | `vec2` | Pixel movement this frame (Y-flipped) | [Mouse](/shader/mouse) |\n| [`u_mouseWheel`](/shader/mouse) | `float` | Scroll delta this frame | [Mouse](/shader/mouse) |\n| [`u_mouseWasPressed`](/shader/mouse) | `bool` | True for one frame when pressed | [Mouse](/shader/mouse) |\n| [`u_mouseWasReleased`](/shader/mouse) | `bool` | True for one frame when released | [Mouse](/shader/mouse) |\n\n## Keyboard\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_keySpace`](/shader/keyboard) | `bool` | Space bar | [Keyboard](/shader/keyboard) |\n| [`u_keyShift`](/shader/keyboard) | `bool` | Shift key | [Keyboard](/shader/keyboard) |\n| [`u_keyCtrl`](/shader/keyboard) | `bool` | Ctrl/Cmd key | [Keyboard](/shader/keyboard) |\n| [`u_keyAlt`](/shader/keyboard) | `bool` | Alt/Option key | [Keyboard](/shader/keyboard) |\n| [`u_keyW`](/shader/keyboard) | `bool` | W key | [Keyboard](/shader/keyboard) |\n| [`u_keyA`](/shader/keyboard) | `bool` | A key | [Keyboard](/shader/keyboard) |\n| [`u_keyS`](/shader/keyboard) | `bool` | S key | [Keyboard](/shader/keyboard) |\n| [`u_keyD`](/shader/keyboard) | `bool` | D key | [Keyboard](/shader/keyboard) |\n| [`u_keyUp`](/shader/keyboard) | `bool` | Up arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyDown`](/shader/keyboard) | `bool` | Down arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyLeft`](/shader/keyboard) | `bool` | Left arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyRight`](/shader/keyboard) | `bool` | Right arrow | [Keyboard](/shader/keyboard) |\n| [`u_keyboard`](/shader/keyboard) | `sampler2D` | 256×3 LUMINANCE texture (row 0: held, row 1: pressed, row 2: toggle) | [Keyboard](/shader/keyboard) |\n\n## Touch\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_touchCount`](/shader/touch) | `int` | Number of active touches (0–5) | [Touch](/shader/touch) |\n| [`u_touch0`](/shader/touch) | `vec2` | Touch point 0 position (pixels, Y-flipped) | [Touch](/shader/touch) |\n| [`u_touch1`](/shader/touch) | `vec2` | Touch point 1 position | [Touch](/shader/touch) |\n| [`u_touch2`](/shader/touch) | `vec2` | Touch point 2 position | [Touch](/shader/touch) |\n| [`u_touch3`](/shader/touch) | `vec2` | Touch point 3 position | [Touch](/shader/touch) |\n| [`u_touch4`](/shader/touch) | `vec2` | Touch point 4 position | [Touch](/shader/touch) |\n\n## Pointer (Unified)\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_pointer`](/shader/pointer) | `vec2` | Primary pointer position (pixels, Y-flipped) | [Pointer](/shader/pointer) |\n| [`u_pointerDelta`](/shader/pointer) | `vec2` | Movement delta (Y-flipped) | [Pointer](/shader/pointer) |\n| [`u_pointerDown`](/shader/pointer) | `bool` | Whether pointer is active (click or touch) | [Pointer](/shader/pointer) |\n| [`u_pointerWasPressed`](/shader/pointer) | `bool` | True for one frame when pressed | [Pointer](/shader/pointer) |\n| [`u_pointerWasReleased`](/shader/pointer) | `bool` | True for one frame when released | [Pointer](/shader/pointer) |\n| [`u_pointerInCanvas`](/shader/pointer) | `bool` | Whether pointer is inside the canvas | [Pointer](/shader/pointer) |\n\n## Audio — Scalars\n\n### Volume\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioVolume`](/shader/audio/volume) | `float` | Current RMS volume 0–1 | [Volume](/shader/audio/volume) |\n| [`u_audioPeak`](/shader/audio/volume) | `float` | Peak volume 0–1 | [Volume](/shader/audio/volume) |\n| [`u_audioVolumeSmoothed`](/shader/audio/volume) | `float` | Smoothed volume (~200ms decay) | [Volume](/shader/audio/volume) |\n\n### Frequency Bands\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioLow`](/shader/audio/bands) | `float` | Low band energy (20–120 Hz) | [Bands](/shader/audio/bands) |\n| [`u_audioLowMid`](/shader/audio/bands) | `float` | Low-mid band energy (120–500 Hz) | [Bands](/shader/audio/bands) |\n| [`u_audioMid`](/shader/audio/bands) | `float` | Mid band energy (500–2 kHz) | [Bands](/shader/audio/bands) |\n| [`u_audioHighMid`](/shader/audio/bands) | `float` | High-mid band energy (2–6 kHz) | [Bands](/shader/audio/bands) |\n| [`u_audioHigh`](/shader/audio/bands) | `float` | High band energy (6–16 kHz) | [Bands](/shader/audio/bands) |\n| [`u_audioLowSmoothed`](/shader/audio/bands) | `float` | Smoothed low band | [Bands](/shader/audio/bands) |\n| [`u_audioLowMidSmoothed`](/shader/audio/bands) | `float` | Smoothed low-mid band | [Bands](/shader/audio/bands) |\n| [`u_audioMidSmoothed`](/shader/audio/bands) | `float` | Smoothed mid band | [Bands](/shader/audio/bands) |\n| [`u_audioHighMidSmoothed`](/shader/audio/bands) | `float` | Smoothed high-mid band | [Bands](/shader/audio/bands) |\n| [`u_audioHighSmoothed`](/shader/audio/bands) | `float` | Smoothed high band | [Bands](/shader/audio/bands) |\n\n### Beat Detection\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioKick`](/shader/audio/beat) | `float` | Kick beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioSnare`](/shader/audio/beat) | `float` | Snare beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioHat`](/shader/audio/beat) | `float` | Hi-hat beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioAny`](/shader/audio/beat) | `float` | Combined beat energy | [Beat](/shader/audio/beat) |\n| [`u_audioKickSmoothed`](/shader/audio/beat) | `float` | Smoothed kick | [Beat](/shader/audio/beat) |\n| [`u_audioSnareSmoothed`](/shader/audio/beat) | `float` | Smoothed snare | [Beat](/shader/audio/beat) |\n| [`u_audioHatSmoothed`](/shader/audio/beat) | `float` | Smoothed hi-hat | [Beat](/shader/audio/beat) |\n| [`u_audioAnySmoothed`](/shader/audio/beat) | `float` | Smoothed combined | [Beat](/shader/audio/beat) |\n| [`u_audioKickTrigger`](/shader/audio/beat) | `bool` | Kick trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioSnareTrigger`](/shader/audio/beat) | `bool` | Snare trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioHatTrigger`](/shader/audio/beat) | `bool` | Hi-hat trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioAnyTrigger`](/shader/audio/beat) | `bool` | Any beat trigger (true for one frame) | [Beat](/shader/audio/beat) |\n| [`u_audioBPM`](/shader/audio/beat) | `float` | Tracked BPM | [Beat](/shader/audio/beat) |\n| [`u_audioConfidence`](/shader/audio/beat) | `float` | Beat-tracker confidence 0–1 | [Beat](/shader/audio/beat) |\n| [`u_audioIsLocked`](/shader/audio/beat) | `bool` | Whether beat tracking is locked | [Beat](/shader/audio/beat) |\n\n### Spectral Analysis\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioBrightness`](/shader/audio/spectral) | `float` | Spectral brightness 0–1 | [Spectral](/shader/audio/spectral) |\n| [`u_audioFlatness`](/shader/audio/spectral) | `float` | Spectral flatness 0–1 | [Spectral](/shader/audio/spectral) |\n\n## Audio — Textures\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_audioFFT`](/shader/audio/fft) | `sampler2D` | FFT as 1D LUMINANCE strip (bin count × 1, values 0–255) | [FFT Texture](/shader/audio/fft) |\n| [`u_audioWaveform`](/shader/audio/waveform) | `sampler2D` | Time-domain waveform as 1D LUMINANCE strip (-1…1 mapped to 0–255) | [Waveform Texture](/shader/audio/waveform) |\n\n## Video\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_video`](/shader/video/basics) | `sampler2D` | Main video frame texture | [Video Basics](/shader/video/basics) |\n| [`u_videoResolution`](/shader/video/basics) | `vec2` | Video frame size in pixels (0,0 if disconnected) | [Video Basics](/shader/video/basics) |\n| [`u_videoFrameRate`](/shader/video/basics) | `float` | Video frame rate | [Video Basics](/shader/video/basics) |\n\n## CV — Face Detection\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_faceCount`](/shader/video/face-detection) | `int` | Number of detected faces | [Face Detection](/shader/video/face-detection) |\n| [`u_face0Bounds`](/shader/video/face-detection) | `vec4` | Bounding box (x, y, w, h) normalized 0–1 | [Face Detection](/shader/video/face-detection) |\n| [`u_face0Center`](/shader/video/face-detection) | `vec2` | Face center normalized 0–1 | [Face Detection](/shader/video/face-detection) |\n| [`u_face0HeadPose`](/shader/video/face-mesh) | `vec3` | Pitch, yaw, roll in degrees | [Face Mesh](/shader/video/face-mesh) |\n| [`u_face0Confidence`](/shader/video/face-detection) | `float` | Detection confidence | [Face Detection](/shader/video/face-detection) |\n\n### Expressions\n\n| Uniform | Type | Details |\n|---------|------|---------|\n| [`u_face0Neutral`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Happy`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Sad`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Angry`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Surprised`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Disgusted`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n| [`u_face0Fearful`](/shader/video/emotion-detection) | `float` | [Emotion Detection](/shader/video/emotion-detection) |\n\n### Blendshapes (52 uniforms)\n\nAll blendshapes are `float` values 0–1, following the ARKit naming convention. See [Face Mesh](/shader/video/face-mesh) for the full list and usage.\n\n| Uniform | Uniform | Uniform |\n|---------|---------|---------|\n| `u_face0BrowDownLeft` | `u_face0BrowDownRight` | `u_face0BrowInnerUp` |\n| `u_face0BrowOuterUpLeft` | `u_face0BrowOuterUpRight` | `u_face0CheekPuff` |\n| `u_face0CheekSquintLeft` | `u_face0CheekSquintRight` | `u_face0EyeBlinkLeft` |\n| `u_face0EyeBlinkRight` | `u_face0EyeLookDownLeft` | `u_face0EyeLookDownRight` |\n| `u_face0EyeLookInLeft` | `u_face0EyeLookInRight` | `u_face0EyeLookOutLeft` |\n| `u_face0EyeLookOutRight` | `u_face0EyeLookUpLeft` | `u_face0EyeLookUpRight` |\n| `u_face0EyeSquintLeft` | `u_face0EyeSquintRight` | `u_face0EyeWideLeft` |\n| `u_face0EyeWideRight` | `u_face0JawForward` | `u_face0JawLeft` |\n| `u_face0JawOpen` | `u_face0JawRight` | `u_face0MouthClose` |\n| `u_face0MouthDimpleLeft` | `u_face0MouthDimpleRight` | `u_face0MouthFrownLeft` |\n| `u_face0MouthFrownRight` | `u_face0MouthFunnel` | `u_face0MouthLeft` |\n| `u_face0MouthLowerDownLeft` | `u_face0MouthLowerDownRight` | `u_face0MouthPressLeft` |\n| `u_face0MouthPressRight` | `u_face0MouthPucker` | `u_face0MouthRight` |\n| `u_face0MouthRollLower` | `u_face0MouthRollUpper` | `u_face0MouthShrugLower` |\n| `u_face0MouthShrugUpper` | `u_face0MouthSmileLeft` | `u_face0MouthSmileRight` |\n| `u_face0MouthStretchLeft` | `u_face0MouthStretchRight` | `u_face0MouthUpperUpLeft` |\n| `u_face0MouthUpperUpRight` | `u_face0NoseSneerLeft` | `u_face0NoseSneerRight` |\n| `u_face0TongueOut` | | |\n\n## CV — Hand Tracking\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_handCount`](/shader/video/hand-tracking) | `int` | Number of detected hands (0–2) | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandPalm`](/shader/video/hand-tracking) | `vec3` | Left hand palm position | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_rightHandPalm`](/shader/video/hand-tracking) | `vec3` | Right hand palm position | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandConfidence`](/shader/video/hand-tracking) | `float` | Left hand confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_rightHandConfidence`](/shader/video/hand-tracking) | `float` | Right hand confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandBounds`](/shader/video/hand-tracking) | `vec4` | Left hand bounding box (x, y, w, h) | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_rightHandBounds`](/shader/video/hand-tracking) | `vec4` | Right hand bounding box (x, y, w, h) | [Hand Tracking](/shader/video/hand-tracking) |\n\n### Gesture Scores (per hand)\n\nAll gesture uniforms are `float` values 0–1. Replace `left` with `right` for the other hand.\n\n| Uniform | Description | Details |\n|---------|-------------|---------|\n| [`u_leftHandFist`](/shader/video/hand-tracking) | Fist gesture confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandOpenPalm`](/shader/video/hand-tracking) | Open palm confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandPeace`](/shader/video/hand-tracking) | Peace/V-sign confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandThumbsUp`](/shader/video/hand-tracking) | Thumbs up confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandThumbsDown`](/shader/video/hand-tracking) | Thumbs down confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandPointing`](/shader/video/hand-tracking) | Pointing confidence | [Hand Tracking](/shader/video/hand-tracking) |\n| [`u_leftHandILoveYou`](/shader/video/hand-tracking) | I Love You sign confidence | [Hand Tracking](/shader/video/hand-tracking) |\n\n## CV — Pose Detection\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_poseDetected`](/shader/video/pose-detection) | `bool` | Whether a body pose is detected | [Pose Detection](/shader/video/pose-detection) |\n| [`u_poseConfidence`](/shader/video/pose-detection) | `float` | Pose detection confidence | [Pose Detection](/shader/video/pose-detection) |\n| [`u_nosePosition`](/shader/video/pose-detection) | `vec2` | Nose landmark position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftShoulderPosition`](/shader/video/pose-detection) | `vec2` | Left shoulder position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightShoulderPosition`](/shader/video/pose-detection) | `vec2` | Right shoulder position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftElbowPosition`](/shader/video/pose-detection) | `vec2` | Left elbow position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightElbowPosition`](/shader/video/pose-detection) | `vec2` | Right elbow position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftWristPosition`](/shader/video/pose-detection) | `vec2` | Left wrist position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightWristPosition`](/shader/video/pose-detection) | `vec2` | Right wrist position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftHipPosition`](/shader/video/pose-detection) | `vec2` | Left hip position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightHipPosition`](/shader/video/pose-detection) | `vec2` | Right hip position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftKneePosition`](/shader/video/pose-detection) | `vec2` | Left knee position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightKneePosition`](/shader/video/pose-detection) | `vec2` | Right knee position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_leftAnklePosition`](/shader/video/pose-detection) | `vec2` | Left ankle position | [Pose Detection](/shader/video/pose-detection) |\n| [`u_rightAnklePosition`](/shader/video/pose-detection) | `vec2` | Right ankle position | [Pose Detection](/shader/video/pose-detection) |\n\n## CV — Body Segmentation\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_segmentationMask`](/shader/video/body-segmentation) | `sampler2D` | Body mask (LUMINANCE: 0 = background, 1 = person) | [Segmentation](/shader/video/body-segmentation) |\n| [`u_segmentationRes`](/shader/video/body-segmentation) | `vec2` | Mask dimensions in pixels | [Segmentation](/shader/video/body-segmentation) |\n\n## Device Sensors\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_deviceAcceleration`](/shader/sensors) | `vec3` | Acceleration without gravity (m/s²) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceAccelerationGravity`](/shader/sensors) | `vec3` | Acceleration with gravity (m/s²) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceRotationRate`](/shader/sensors) | `vec3` | Gyroscope: alpha, beta, gamma (deg/s) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceOrientation`](/shader/sensors) | `vec3` | Orientation: alpha, beta, gamma (degrees) | [Sensor Uniforms](/shader/sensors) |\n| [`u_deviceOrientationAbsolute`](/shader/sensors) | `bool` | Whether orientation is magnetometer-based | [Sensor Uniforms](/shader/sensors) |\n\n## External Devices — Video\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_deviceCount`](/shader/external-devices) | `int` | Number of devices with active cameras (0–8) | [Overview](/shader/external-devices) |\n| [`u_device0`](/shader/external-devices/video) – `u_device7` | `sampler2D` | Device camera frame texture | [Video Textures](/shader/external-devices/video) |\n| [`u_device0Resolution`](/shader/external-devices/video) – `u_device7Resolution` | `vec2` | Device camera frame size | [Video Textures](/shader/external-devices/video) |\n| [`u_device0Connected`](/shader/external-devices/video) – `u_device7Connected` | `bool` | Whether device camera is active | [Video Textures](/shader/external-devices/video) |\n\n> [!NOTE]\n> Audio stream uniforms from devices are accessed via `u_audioStream{i}*` uniforms (same pool as additional audio streams, different index range managed by the host).\n\n## External Devices — Sensors\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`u_externalDeviceCount`](/shader/external-devices) | `int` | Number of connected external devices (0–8) | [Overview](/shader/external-devices) |\n| [`u_device0Acceleration`](/shader/external-devices/sensors) – `u_device7Acceleration` | `vec3` | Per-device acceleration without gravity | [Sensor Uniforms](/shader/external-devices/sensors) |\n| [`u_device0AccelerationGravity`](/shader/external-devices/sensors) – `u_device7AccelerationGravity` | `vec3` | Per-device acceleration with gravity | [Sensor Uniforms](/shader/external-devices/sensors) |\n| [`u_device0RotationRate`](/shader/external-devices/sensors) – `u_device7RotationRate` | `vec3` | Per-device rotation rate | [Sensor Uniforms](/shader/external-devices/sensors) |\n| [`u_device0Orientation`](/shader/external-devices/sensors) – `u_device7Orientation` | `vec3` | Per-device orientation angles | [Sensor Uniforms](/shader/external-devices/sensors) |\n\n> [!NOTE]\n> `u_device{i}` (sampler2D) is the **camera texture** for device slot `i`. `u_device{i}Acceleration` and similar are the **IMU sensors** for the same device — different data, same index.\n\n## Streams (Compositor)\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_videoStreamCount` | `int` | Number of active streams (0–8) |\n| `u_videoStream0` – `u_videoStream7` | `sampler2D` | Stream frame textures |\n| `u_videoStream0Resolution` – `u_videoStream7Resolution` | `vec2` | Stream frame sizes in pixels |\n| `u_videoStream0Connected` – `u_videoStream7Connected` | `bool` | Whether stream has an active frame |\n\nStreams are additional video sources injected by the host application — they are used internally by Viji's compositor for mixing multiple scenes together. When no streams are provided, `u_videoStreamCount` is `0` and the textures sample as black. Each stream works the same way as [`u_video`](/shader/video/basics).\n\n## Audio Streams\n\n| Uniform | Type | Description |\n|---------|------|-------------|\n| `u_audioStreamCount` | `int` | Number of active audio streams (0–8) |\n| `u_audioStream0Connected` – `u_audioStream7Connected` | `bool` | Whether stream is actively providing audio |\n| `u_audioStream0Volume` – `u_audioStream7Volume` | `float` | Stream volume (0–1) |\n| `u_audioStream0Low` – `u_audioStream7Low` | `float` | Low frequency band energy (0–1) |\n| `u_audioStream0LowMid` – `u_audioStream7LowMid` | `float` | Low-mid band energy (0–1) |\n| `u_audioStream0Mid` – `u_audioStream7Mid` | `float` | Mid band energy (0–1) |\n| `u_audioStream0HighMid` – `u_audioStream7HighMid` | `float` | High-mid band energy (0–1) |\n| `u_audioStream0High` – `u_audioStream7High` | `float` | High band energy (0–1) |\n| `u_audioStream0Brightness` – `u_audioStream7Brightness` | `float` | Spectral brightness (0–1) |\n| `u_audioStream0Flatness` – `u_audioStream7Flatness` | `float` | Spectral flatness (0–1) |\n\nAdditional audio streams provide lightweight scalar uniforms only — **no** FFT or waveform textures. Beat detection, BPM, and onset uniforms are only available on the main audio stream (`u_audioVolume`, `u_audioBPM`, etc.).\n\nWhen no audio streams are provided, `u_audioStreamCount` is `0` and all per-stream uniforms default to `0.0` / `false`.\n\n## Backbuffer\n\n| Uniform | Type | Description | Details |\n|---------|------|-------------|---------|\n| [`backbuffer`](/shader/backbuffer) | `sampler2D` | Previous frame texture (feedback effects) | [Backbuffer & Feedback](/shader/backbuffer) |\n\n> [!WARNING]\n> `backbuffer` is **conditional** — it is only injected if the word `backbuffer` appears anywhere in your shader source (including comments). It has no `u_` prefix. See [Backbuffer & Feedback](/shader/backbuffer) for details.\n\n## Parameter Directives\n\nDeclare parameters using `// @viji-TYPE:uniformName key:value ...` comments. Each directive generates a uniform and a UI control in the host.\n\n| Directive | Uniform Type | UI Control | Details |\n|-----------|-------------|------------|---------|\n| [`@viji-slider`](/shader/parameters/slider) | `float` | Numeric slider | [Slider](/shader/parameters/slider) |\n| [`@viji-number`](/shader/parameters/number) | `float` | Numeric input | [Number](/shader/parameters/number) |\n| [`@viji-color`](/shader/parameters/color) | `vec3` | Color picker (hex → RGB 0–1) | [Color](/shader/parameters/color) |\n| [`@viji-toggle`](/shader/parameters/toggle) | `bool` | On/off switch | [Toggle](/shader/parameters/toggle) |\n| [`@viji-select`](/shader/parameters/select) | `int` | Dropdown (0-based option index) | [Select](/shader/parameters/select) |\n| [`@viji-image`](/shader/parameters/image) | `sampler2D` | Image upload | [Image](/shader/parameters/image) |\n| [`@viji-button`](/shader/parameters/button) | `bool` | Momentary button (true for one frame) | [Button](/shader/parameters/button) |\n| [`@viji-coordinate`](/shader/parameters/coordinate) | `vec2` | 2D coordinate pad — both components -1 to 1 | [Coordinate](/shader/parameters/coordinate) |\n| [`@viji-accumulator`](/shader/parameters/accumulator) | `float` | CPU-side: `+= rate × deltaTime` | [Accumulator](/shader/parameters/accumulator) |\n\nSee [Parameters Overview](/shader/parameters) for syntax, [Grouping](/shader/parameters/grouping) and [Categories](/shader/parameters/categories) for organization.\n\n## Related\n\n- [Shader Basics](/shader/basics) — auto-injection, GLSL versions, `@renderer shader`\n- [Shader Quick Start](/shader/quickstart) — getting started with shader scenes\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers\n- [Native API Reference](/native/api-reference) — JavaScript API for the Native renderer\n- [P5 API Reference](/p5/api-reference) — JavaScript API for the P5 renderer"
|
|
2926
2983
|
}
|
|
2927
2984
|
]
|
|
2928
2985
|
},
|
|
@@ -3026,7 +3083,7 @@ export const docsApi = {
|
|
|
3026
3083
|
"content": [
|
|
3027
3084
|
{
|
|
3028
3085
|
"type": "text",
|
|
3029
|
-
"markdown": "# Shader Parameters\n\nParameters are the primary way to give users control over your scene. You declare them at the top of your shader, and Viji renders corresponding UI controls (sliders, color pickers, toggles, etc.) in the host application. Values update in real-time as users interact with the controls.\n\nIn the shader renderer, parameters are declared using `// @viji-*` comment directives. Each directive creates a UI control and a corresponding GLSL uniform — no manual `uniform` declarations needed. Read the uniform directly in your shader code to get the current value.\n\n## Parameter Types\n\n| Directive | Uniform Type | Value | Use For |\n|---|---|---|---|\n| [`@viji-slider`](slider/) | `float` | Continuous range | Speed, intensity, size |\n| [`@viji-number`](number/) | `float` | Precise numeric | Count, threshold |\n| [`@viji-color`](color/) | `vec3` | RGB (0–1) | Tint, palette |\n| [`@viji-toggle`](toggle/) | `bool` | On/off | Invert, enable effect |\n| [`@viji-select`](select/) | `int` | Index (0-based) | Mode, pattern selection |\n| [`@viji-image`](image/) | `sampler2D` | Texture | Overlay, displacement map |\n| [`@viji-button`](button/) | `bool` | Momentary trigger | Reset, spawn, one-shot action |\n| [`@viji-accumulator`](accumulator/) | `float` | CPU-side integration | Smooth animation phase |\n\n## Basic Pattern\n\n```glsl\n// @renderer shader\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n// @viji-color:tint label:\"Tint\" default:#ff6600\n// @viji-toggle:invert label:\"Invert\" default:false\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n vec3 col = tint * uv.x * speed;\n if (invert) col = 1.0 - col;\n gl_FragColor = vec4(col, 1.0);\n}\n```\n\nEach `@viji-*` directive auto-generates a `uniform` declaration with the name after the colon. `speed` becomes `uniform float speed;`, `tint` becomes `uniform vec3 tint;`, etc.\n\n> [!WARNING]\n> Do not use the `u_` prefix for parameter names — it is reserved for built-in Viji uniforms. Use descriptive names like `speed`, `tint`, `brightness`.\n\n> [!NOTE]\n> Parameter directives use **single-line `//` comments only**. Block comments `/* */` are not parsed for `@viji-*` directives.\n\n## Directive Syntax\n\n```\n// @viji-TYPE:uniformName key:value key:\"string value\" key:[array]\n```\n\n- **TYPE** — one of: [`slider`](slider/), [`number`](number/), [`color`](color/), [`toggle`](toggle/), [`select`](select/), [`image`](image/), [`button`](button/), [`accumulator`](accumulator/)\n- **uniformName** — the GLSL uniform name (no `u_` prefix)\n- **key:value** pairs — configure the parameter\n\n## Common Config Keys\n\n| Key | Type | Description |\n|---|---|---|\n| `label` | `string` | **(required)** Display name in the UI |\n| `default` | varies | **(required for most types)** Initial value |\n| `min` | `number` | Minimum value ([slider](slider/)/[number](number/)) |\n| `max` | `number` | Maximum value ([slider](slider/)/[number](number/)) |\n| `step` | `number` | Step increment ([slider](slider/)/[number](number/)) |\n| `description` | `string` | Help text |\n| `group` | `string` | Group name for organizing parameters — see [Grouping](grouping/) |\n| `category` | `string` | Visibility category — see [Categories](categories/) |\n| `options` | `array` | Options list ([select](select/) only) |\n\n## Uniform Type Mapping\n\n| Parameter Type | GLSL Uniform | Notes |\n|---|---|---|\n| [`slider`](slider/) | `uniform float` | |\n| [`number`](number/) | `uniform float` | Same as slider |\n| [`color`](color/) | `uniform vec3` | RGB components, each 0–1 |\n| [`toggle`](toggle/) | `uniform bool` | |\n| [`select`](select/) | `uniform int` | 0-based index of selected option |\n| [`image`](image/) | `uniform sampler2D` | |\n| [`button`](button/) | `uniform bool` | `true` for 1 frame after click, then `false` |\n| [`accumulator`](accumulator/) | `uniform float` | CPU-side `value += rate × deltaTime` each frame |\n\n> [!WARNING]\n> All `@viji-*` directives must appear as top-level comments before `void main()`. They are parsed once during shader compilation. Viji's shader auto-injection places the generated `uniform` declarations before your code.\n\n## Organization\n\nAs scenes grow, you'll want to organize parameters into logical sections and control when they're visible:\n\n- **[Grouping](grouping/)** — Use the `group:` key to collect related parameters under a shared heading (e.g., `group:animation`). Parameters with the same `group` value appear together in the UI.\n- **[Categories](categories/)** — Use the `category:` key to tag parameters as `general`, `audio`, `video`, or `interaction` to automatically show/hide them based on what inputs are currently active.\n\n## Related\n\n- [Slider](slider/) — the most common parameter type\n- [Accumulator](accumulator/) — smooth animation without `u_time * speed` jumps\n- [Grouping](grouping/) — organizing parameters into named groups\n- [Categories](categories/) — visibility based on capabilities\n- [Native Parameters](/native/parameters) — equivalent JavaScript API\n- [P5 Parameters](/p5/parameters) — same system in the P5 renderer\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
3086
|
+
"markdown": "# Shader Parameters\n\nParameters are the primary way to give users control over your scene. You declare them at the top of your shader, and Viji renders corresponding UI controls (sliders, color pickers, toggles, etc.) in the host application. Values update in real-time as users interact with the controls.\n\nIn the shader renderer, parameters are declared using `// @viji-*` comment directives. Each directive creates a UI control and a corresponding GLSL uniform — no manual `uniform` declarations needed. Read the uniform directly in your shader code to get the current value.\n\n## Parameter Types\n\n| Directive | Uniform Type | Value | Use For |\n|---|---|---|---|\n| [`@viji-slider`](slider/) | `float` | Continuous range | Speed, intensity, size |\n| [`@viji-number`](number/) | `float` | Precise numeric | Count, threshold |\n| [`@viji-color`](color/) | `vec3` | RGB (0–1) | Tint, palette |\n| [`@viji-toggle`](toggle/) | `bool` | On/off | Invert, enable effect |\n| [`@viji-select`](select/) | `int` | Index (0-based) | Mode, pattern selection |\n| [`@viji-image`](image/) | `sampler2D` | Texture | Overlay, displacement map |\n| [`@viji-button`](button/) | `bool` | Momentary trigger | Reset, spawn, one-shot action |\n| Coordinate | `@viji-coordinate` | `vec2` | 2D coordinate pad control. Both axes range from -1 to 1. |\n| [`@viji-accumulator`](accumulator/) | `float` | CPU-side integration | Smooth animation phase |\n\n## Basic Pattern\n\n```glsl\n// @renderer shader\n// @viji-slider:speed label:\"Speed\" default:1.0 min:0.1 max:5.0\n// @viji-color:tint label:\"Tint\" default:#ff6600\n// @viji-toggle:invert label:\"Invert\" default:false\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n vec3 col = tint * uv.x * speed;\n if (invert) col = 1.0 - col;\n gl_FragColor = vec4(col, 1.0);\n}\n```\n\nEach `@viji-*` directive auto-generates a `uniform` declaration with the name after the colon. `speed` becomes `uniform float speed;`, `tint` becomes `uniform vec3 tint;`, etc.\n\n> [!WARNING]\n> Do not use the `u_` prefix for parameter names — it is reserved for built-in Viji uniforms. Use descriptive names like `speed`, `tint`, `brightness`.\n\n> [!NOTE]\n> Parameter directives use **single-line `//` comments only**. Block comments `/* */` are not parsed for `@viji-*` directives.\n\n## Directive Syntax\n\n```\n// @viji-TYPE:uniformName key:value key:\"string value\" key:[array]\n```\n\n- **TYPE** — one of: [`slider`](slider/), [`number`](number/), [`color`](color/), [`toggle`](toggle/), [`select`](select/), [`image`](image/), [`button`](button/), [`coordinate`](coordinate/), [`accumulator`](accumulator/)\n- **uniformName** — the GLSL uniform name (no `u_` prefix)\n- **key:value** pairs — configure the parameter\n\n## Common Config Keys\n\n| Key | Type | Description |\n|---|---|---|\n| `label` | `string` | **(required)** Display name in the UI |\n| `default` | varies | **(required for most types)** Initial value |\n| `min` | `number` | Minimum value ([slider](slider/)/[number](number/)) |\n| `max` | `number` | Maximum value ([slider](slider/)/[number](number/)) |\n| `step` | `number` | Step increment ([slider](slider/)/[number](number/)) |\n| `description` | `string` | Help text |\n| `group` | `string` | Group name for organizing parameters — see [Grouping](grouping/) |\n| `category` | `string` | Visibility category — see [Categories](categories/) |\n| `options` | `array` | Options list ([select](select/) only) |\n\n## Uniform Type Mapping\n\n| Parameter Type | GLSL Uniform | Notes |\n|---|---|---|\n| [`slider`](slider/) | `uniform float` | |\n| [`number`](number/) | `uniform float` | Same as slider |\n| [`color`](color/) | `uniform vec3` | RGB components, each 0–1 |\n| [`toggle`](toggle/) | `uniform bool` | |\n| [`select`](select/) | `uniform int` | 0-based index of selected option |\n| [`image`](image/) | `uniform sampler2D` | |\n| [`button`](button/) | `uniform bool` | `true` for 1 frame after click, then `false` |\n| `coordinate` | `vec2` | `{ x: number, y: number }` mapped to `vec2(x, y)` |\n| [`accumulator`](accumulator/) | `uniform float` | CPU-side `value += rate × deltaTime` each frame |\n\n> [!WARNING]\n> All `@viji-*` directives must appear as top-level comments before `void main()`. They are parsed once during shader compilation. Viji's shader auto-injection places the generated `uniform` declarations before your code.\n\n## Organization\n\nAs scenes grow, you'll want to organize parameters into logical sections and control when they're visible:\n\n- **[Grouping](grouping/)** — Use the `group:` key to collect related parameters under a shared heading (e.g., `group:animation`). Parameters with the same `group` value appear together in the UI.\n- **[Categories](categories/)** — Use the `category:` key to tag parameters as `general`, `audio`, `video`, or `interaction` to automatically show/hide them based on what inputs are currently active.\n\n## Related\n\n- [Slider](slider/) — the most common parameter type\n- [Coordinate](coordinate/) — 2D position control\n- [Accumulator](accumulator/) — smooth animation without `u_time * speed` jumps\n- [Grouping](grouping/) — organizing parameters into named groups\n- [Categories](categories/) — visibility based on capabilities\n- [Native Parameters](/native/parameters) — equivalent JavaScript API\n- [P5 Parameters](/p5/parameters) — same system in the P5 renderer\n- [Best Practices](/getting-started/best-practices) — essential patterns for all renderers"
|
|
3030
3087
|
}
|
|
3031
3088
|
]
|
|
3032
3089
|
},
|
|
@@ -3167,6 +3224,27 @@ export const docsApi = {
|
|
|
3167
3224
|
}
|
|
3168
3225
|
]
|
|
3169
3226
|
},
|
|
3227
|
+
"shader-param-coordinate": {
|
|
3228
|
+
"id": "shader-param-coordinate",
|
|
3229
|
+
"title": "Coordinate Parameter",
|
|
3230
|
+
"description": "Declare a 2D coordinate control that maps to a uniform vec2 with x/y values from -1 to 1.",
|
|
3231
|
+
"content": [
|
|
3232
|
+
{
|
|
3233
|
+
"type": "text",
|
|
3234
|
+
"markdown": "# @viji-coordinate\n\n```glsl\n// @viji-coordinate:origin label:\"Effect Origin\" default:[0,0]\n```\n\nDeclares a 2D coordinate parameter. The host renders it as a draggable pad control. The value is injected as a `uniform vec2` where both components range from **-1 to 1**.\n\n## Directive Syntax\n\n```\n// @viji-coordinate:uniformName key:value key:value ...\n```\n\n| Key | Required | Default | Description |\n|-----|----------|---------|-------------|\n| `default` | Yes | — | Initial value as a 2-element array, e.g. `default:[0,0]` |\n| `label` | Yes | — | Display name in the parameter UI |\n| `step` | No | `0.01` | Snap increment |\n| `description` | No | — | Tooltip text (use quotes: `description:\"Help text\"`) |\n| `group` | No | `general` | Group name (use quotes: `group:\"position\"`) |\n| `category` | No | `general` | Visibility category |\n\n## Uniform Type\n\nThe coordinate is injected as a `vec2`:\n\n| Component | Range | Description |\n|-----------|-------|-------------|\n| `uniformName.x` | -1 to 1 | Horizontal position (left to right) |\n| `uniformName.y` | -1 to 1 | Vertical position (bottom to top) |\n\n> [!WARNING]\n> Do not use the `u_` prefix for your parameter uniform names — it is reserved for built-in Viji uniforms. Use descriptive names like `origin`, `center`, `offset` instead.\n\n## Usage\n\n```glsl\n// @renderer shader\n// @viji-coordinate:origin label:\"Effect Origin\" default:[0,0]\n// @viji-color:tint label:\"Color\" default:#ff6b6b\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n vec2 centered = uv * 2.0 - 1.0;\n centered.x *= u_resolution.x / u_resolution.y;\n\n float d = length(centered - origin);\n float circle = smoothstep(0.3, 0.28, d);\n\n vec3 col = tint * circle;\n gl_FragColor = vec4(col, 1.0);\n}\n```\n\n> [!WARNING]\n> The directive must use `//` comments only. Block comments (`/* */`) are not parsed."
|
|
3235
|
+
},
|
|
3236
|
+
{
|
|
3237
|
+
"type": "live-example",
|
|
3238
|
+
"title": "Basic Coordinate",
|
|
3239
|
+
"sceneCode": "// @renderer shader\n// @viji-coordinate:origin label:\"Effect Origin\" default:[0,0]\n// @viji-color:tint label:\"Tint\" default:#ff6b6b\n// @viji-slider:radius label:\"Radius\" default:0.3 min:0.05 max:0.8 step:0.01\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_resolution;\n vec2 centered = uv * 2.0 - 1.0;\n centered.x *= u_resolution.x / u_resolution.y;\n\n // Grid lines\n vec2 grid = abs(fract(centered * 4.0) - 0.5);\n float gridLine = 1.0 - smoothstep(0.0, 0.02, min(grid.x, grid.y));\n\n // Crosshair at center\n float cross = 1.0 - smoothstep(0.0, 0.005, min(abs(centered.x), abs(centered.y)));\n\n // Circle at origin coordinate\n float d = length(centered - origin);\n float circle = smoothstep(radius, radius - 0.01, d);\n float glow = 0.05 / (d + 0.01);\n\n // Background\n vec3 bg = vec3(0.1, 0.1, 0.18);\n bg += gridLine * 0.03;\n bg += cross * 0.08;\n\n // Composite\n vec3 col = bg + tint * (circle + glow * 0.3);\n gl_FragColor = vec4(col, 1.0);\n}\n",
|
|
3240
|
+
"sceneFile": "coordinate-shader.scene.glsl"
|
|
3241
|
+
},
|
|
3242
|
+
{
|
|
3243
|
+
"type": "text",
|
|
3244
|
+
"markdown": "## Default Value Syntax\n\nThe `default` key takes a JSON-style array of two numbers:\n\n```\ndefault:[0,0] // center\ndefault:[-0.5,0.3] // offset left and up\ndefault:[1,-1] // bottom-right corner\n```\n\nBoth values must be between -1 and 1.\n\n## Coordinate Space\n\nThe coordinate follows **NDC (Normalized Device Coordinates)** convention:\n\n| Value | Position |\n|-------|----------|\n| `vec2(-1, -1)` | Bottom-left |\n| `vec2(0, 0)` | Center |\n| `vec2(1, 1)` | Top-right |\n\nThis matches the standard UV-based coordinate system used in shader code after mapping `gl_FragCoord` to the -1..1 range.\n\n## Rules\n\n- The `label` key is required\n- The `default` key is required and must be a 2-element numeric array\n- String values use quotes: `label:\"Effect Origin\"`\n- The uniform name in the directive becomes a `uniform vec2` declaration\n\n## Related\n\n- [Shader Basics](/shader/basics) — shader file structure and directives\n- [Slider](../slider/) — single-axis `uniform float`\n- [Color](../color/) — color picker as `uniform vec3`\n- [Native Coordinate](/native/parameters/coordinate) — equivalent for the Native renderer\n- [P5 Coordinate](/p5/parameters/coordinate) — equivalent for the P5 renderer"
|
|
3245
|
+
}
|
|
3246
|
+
]
|
|
3247
|
+
},
|
|
3170
3248
|
"shader-param-accumulator": {
|
|
3171
3249
|
"id": "shader-param-accumulator",
|
|
3172
3250
|
"title": "shader-param-accumulator",
|