/**
 * @fileoverview Viji Artist API - JavaScript IntelliSense Support
 * Auto-generated from TypeScript definitions - DO NOT EDIT MANUALLY
 */

/**
 * Configuration object passed to `viji.slider()`. Defines the slider's bounds, increment, label, and UI grouping/visibility.
 * @typedef {Object} SliderConfig
 * @property {number} [min] - Inclusive minimum value of the slider. Default: `0`.
 * @property {number} [max] - Inclusive maximum value of the slider. Default: `100`.
 * @property {number} [step] - Increment between values. When omitted, auto-derives from `min`/`max` as the largest power of 10 giving ~100 positions across the range (e.g., range `0..1` → `0.01`, range `0..100` → `1`, range `0.1..5` → `0.01`, range `0..1000` → `10`). Specify explicitly for integer counts (`step: 1` on a range of `3..30`) or fine precision (`step: 0.001`).
 * @property {string} label - Display name shown next to the control in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.color()`. Defines the color picker's label and UI grouping/visibility.
 * @typedef {Object} ColorConfig
 * @property {string} label - Display name shown next to the color swatch in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.toggle()`. Defines the on/off switch's label and UI grouping/visibility.
 * @typedef {Object} ToggleConfig
 * @property {string} label - Display name shown next to the switch in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.select()`. The host renders the choices as a dropdown or segmented control.
 * @typedef {Object} SelectConfig
 * @property {string[] | number[]} options - Available choices. The element type (`string` or `number`) becomes the parameter's value type. Required.
 * @property {string} label - Display name shown next to the dropdown in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.text()`. The host renders a single-line text input field.
 * @typedef {Object} TextConfig
 * @property {string} label - Display name shown next to the text field in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 * @property {number} [maxLength] - Maximum character count enforced by the host UI. Default: `1000`.
 */

/**
 * Configuration object passed to `viji.number()`. Defines the bounds, step, label, and UI grouping/visibility for a precise numeric input.
 * @typedef {Object} NumberConfig
 * @property {number} [min] - Inclusive minimum value. Default: `0`.
 * @property {number} [max] - Inclusive maximum value. Default: `100`.
 * @property {number} [step] - Increment between values. When omitted, auto-derives from `min`/`max` as the largest power of 10 giving ~100 positions across the range (e.g., range `0..1` → `0.01`, range `0..100` → `1`, range `0.1..5` → `0.01`). Specify explicitly for integer counts (`step: 1`) or fine precision (`step: 0.001`).
 * @property {string} label - Display name shown next to the input in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.image()`. The host renders an upload field; the user-supplied image becomes available as an `ImageBitmap` (Native) or a P5 image wrapper (P5 renderer).
 * @typedef {Object} ImageConfig
 * @property {string} label - Display name shown next to the upload field in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.button()`. The host renders a clickable momentary button. The resulting `value` is `true` for one frame after press, then auto-resets to `false`.
 * @typedef {Object} ButtonConfig
 * @property {string} label - Display name shown on the button in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Configuration object passed to `viji.coordinate()`. The host renders a 2D draggable pad; both `x` and `y` are clamped to `-1..1`.
 * @typedef {Object} CoordinateConfig
 * @property {number} [step] - Snap increment for both `x` and `y` components. Default: `0.01`.
 * @property {string} label - Display name shown next to the pad in the parameter UI. Required.
 * @property {string} [description] - Optional tooltip / help text shown next to the control.
 * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
 * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
 */

/**
 * Reactive object returned by `viji.slider()`. `value` updates in real-time as the user drags the control; the remaining fields mirror the configuration.
 * @typedef {Object} SliderParameter
 * @property {number} value - Current slider value in the configured `min..max` range. Updates in real-time.
 * @property {number} min - Inclusive minimum value of the slider.
 * @property {number} max - Inclusive maximum value of the slider.
 * @property {number} step - Increment between values.
 * @property {string} label - Display name shown next to the control in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.color()`. `value` is always a canonical lowercase 6-digit hex string; `rgb` and `hsb` are derived accessors that are recomputed (and frozen) every time the user changes the color.
 * @typedef {Object} ColorParameter
 * @property {string} value - Canonical hex color string `#rrggbb` (lowercase). Updates in real-time.
 * @property {Object} rgb - RGB components as integers in 0..255 (frozen, recomputed when value changes).
 * @property {number} rgb.r - Red component, integer in 0..255.
 * @property {number} rgb.g - Green component, integer in 0..255.
 * @property {number} rgb.b - Blue component, integer in 0..255.
 * @property {Object} hsb - HSB components: `h` in 0..360, `s` and `b` in 0..100 (frozen, recomputed when value changes).
 * @property {number} hsb.h - Hue in 0..360.
 * @property {number} hsb.s - Saturation in 0..100.
 * @property {number} hsb.b - Brightness in 0..100.
 * @property {string} label - Display name shown next to the swatch in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.toggle()`. `value` flips between `true` and `false` as the user interacts with the switch.
 * @typedef {Object} ToggleParameter
 * @property {boolean} value - Current state of the switch. Updates in real-time when the user toggles it.
 * @property {string} label - Display name shown next to the switch in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.select()`. `value` matches the element type of the configured `options` array (`string` or `number`).
 * @typedef {Object} SelectParameter
 * @property {string | number} value - Currently selected option. Updates in real-time when the user changes the selection.
 * @property {string[] | number[]} options - The full list of choices originally configured.
 * @property {string} label - Display name shown next to the dropdown in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.text()`. `value` updates as the user types and is enforced to be no longer than `maxLength` by the host UI.
 * @typedef {Object} TextParameter
 * @property {string} value - Current text content. Updates in real-time as the user types.
 * @property {number} [maxLength] - Maximum character count enforced by the host UI.
 * @property {string} label - Display name shown next to the input in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.number()`. Like `SliderParameter` but the host UI renders a precise numeric input rather than a draggable slider.
 * @typedef {Object} NumberParameter
 * @property {number} value - Current numeric value in the configured `min..max` range. Updates in real-time.
 * @property {number} min - Inclusive minimum value.
 * @property {number} max - Inclusive maximum value.
 * @property {number} step - Increment between values.
 * @property {string} label - Display name shown next to the input in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.image()`. `value` is `null` until the user uploads an image; in P5 scenes a `.p5` accessor is also added at runtime so the image works directly with `image()`, `texture()`, etc.
 * @typedef {Object} ImageParameter
 * @property {ImageBitmap |null} value - Uploaded image as an `ImageBitmap`, or `null` until the user provides one.
 * @property {string} label - P5-compatible image wrapper. Only available in the P5 renderer; added at runtime by the P5 adapter. Display name shown next to the upload field in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.button()`. `value` is a momentary flag: `true` for exactly one frame after the user clicks, then auto-resets to `false`. Use it to trigger discrete events from `render()`.
 * @typedef {Object} ButtonParameter
 * @property {boolean} value - `true` for the single frame after the user clicks the button, `false` otherwise.
 * @property {string} label - Display name shown on the button in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Reactive object returned by `viji.coordinate()`. `value.x` and `value.y` are always in `-1..1`; the host UI renders a draggable 2D pad.
 * @typedef {Object} CoordinateParameter
 * @property {CoordinateValue} value - Current `{ x, y }` position. Both components are in `-1..1`. Updates in real-time.
 * @property {number} step - Snap increment for both `x` and `y` components.
 * @property {string} label - Display name shown next to the pad in the parameter UI.
 * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
 * @property {string} group - Group name under which the control appears in the UI.
 * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
 */

/**
 * Real-time audio analysis for the main audio stream (`viji.audio`). Provides volume, frequency bands, beat detection (with triggers, events, BPM), spectral features, and access to raw FFT / waveform data. All numeric outputs are zeroed when `isConnected` is `false`.
 * @typedef {Object} AudioAPI
 * @property {boolean} isConnected - `true` when an audio source is connected; otherwise all numeric fields read as `0` and helper methods return empty data.
 * @property {Object} volume - Overall loudness across the stream.
 * @property {number} volume.current - Instantaneous RMS volume in 0..1.
 * @property {number} volume.peak - Instantaneous peak amplitude in 0..1.
 * @property {number} volume.smoothed - Volume with a 200ms decay envelope; rises fast, falls smoothly. Use for flicker-free animations.
 * @property {Object} bands - Energy in five fixed frequency bands, plus a smoothed companion (~150ms decay) for each. All in 0..1.
 * @property {number} bands.low - Instant low-band energy (20-120 Hz, bass/kick range). 0..1.
 * @property {number} bands.lowMid - Instant low-mid energy (120-400 Hz). 0..1.
 * @property {number} bands.mid - Instant mid energy (400-1600 Hz, vocals/instruments). 0..1.
 * @property {number} bands.highMid - Instant high-mid energy (1600-6000 Hz, cymbals/hi-hats). 0..1.
 * @property {number} bands.high - Instant high-band energy (6000-16000 Hz, air/brilliance). 0..1.
 * @property {number} bands.lowSmoothed - Smoothed `low` (~150ms decay). 0..1.
 * @property {number} bands.lowMidSmoothed - Smoothed `lowMid` (~150ms decay). 0..1.
 * @property {number} bands.midSmoothed - Smoothed `mid` (~150ms decay). 0..1.
 * @property {number} bands.highMidSmoothed - Smoothed `highMid` (~150ms decay). 0..1.
 * @property {number} bands.highSmoothed - Smoothed `high` (~150ms decay). 0..1.
 * @property {Object} beat - Beat detection: fast/smoothed energy curves, single-frame boolean triggers, raw event list, and BPM tracking.
 * @property {number} beat.kick - Kick energy curve in 0..1 with a 300ms decay. Peaks on each detected kick.
 * @property {number} beat.snare - Snare energy curve in 0..1 with a 300ms decay.
 * @property {number} beat.hat - Hi-hat energy curve in 0..1 with a 300ms decay.
 * @property {number} beat.any - Energy curve for any beat type in 0..1 with a 300ms decay.
 * @property {number} beat.kickSmoothed - Smoothed `kick` curve in 0..1 with a 500ms decay. Use for ambient pulses.
 * @property {number} beat.snareSmoothed - Smoothed `snare` curve in 0..1 with a 500ms decay.
 * @property {number} beat.hatSmoothed - Smoothed `hat` curve in 0..1 with a 500ms decay.
 * @property {number} beat.anySmoothed - Smoothed `any` curve in 0..1 with a 500ms decay.
 * @property {number} beat.bpm - Currently detected tempo in beats per minute. Defaults to `120` when no audio.
 * @property {number} beat.confidence - Confidence of the BPM tracker in 0..1.
 * @property {boolean} beat.isLocked - `true` when the BPM tracker has a stable lock on the current tempo.
 * @property {Object} spectral - High-level spectral features derived from the FFT.
 * @property {number} spectral.brightness - Normalized spectral centroid in 0..1. Higher values mean brighter, more treble-heavy sound.
 * @property {number} spectral.flatness - Normalized spectral flatness in 0..1. Higher values mean noisier (white-noise-like) sound; lower values mean tonal.
 * @property {() => Uint8Array} getFrequencyData - Returns the raw FFT magnitude spectrum as a `Uint8Array` (1024 bins, each 0..255). Bin `i` covers frequency `i × (sampleRate / fftSize)`. The returned array is a snapshot from the latest analysis tick; repeated calls in the same frame return the same data. @example const fft = viji.audio.getFrequencyData(); for (let i = 0; i < fft.length; i++) drawBar(i, fft[i] / 255);
 * @property {() => Float32Array} getWaveform - Returns the raw time-domain waveform as a `Float32Array` (2048 PCM samples in -1..1). The returned array is a snapshot; repeated calls in the same frame return the same data. @example const wave = viji.audio.getWaveform(); for (let i = 0; i < wave.length; i++) drawSample(i, wave[i]);
 */

/**
 * Lightweight audio analysis for additional or device audio streams. A strict subset of `AudioAPI` that exposes volume, frequency bands, spectral features, and raw FFT/waveform access, but **no beat detection** (no `beat`, no BPM, no triggers, no events).
 * @typedef {Object} AudioStreamAPI
 * @property {boolean} isConnected - `true` when this audio stream is connected; otherwise all numeric fields read as `0`.
 * @property {Object} volume - Overall loudness across the stream.
 * @property {number} volume.current - Instantaneous RMS volume in 0..1.
 * @property {number} volume.peak - Instantaneous peak amplitude in 0..1.
 * @property {number} volume.smoothed - Volume with a 200ms decay envelope.
 * @property {Object} bands - Energy in five fixed frequency bands, plus a smoothed companion (~150ms decay) for each. All in 0..1.
 * @property {number} bands.low - Instant low-band energy (20-120 Hz). 0..1.
 * @property {number} bands.lowMid - Instant low-mid energy (120-400 Hz). 0..1.
 * @property {number} bands.mid - Instant mid energy (400-1600 Hz). 0..1.
 * @property {number} bands.highMid - Instant high-mid energy (1600-6000 Hz). 0..1.
 * @property {number} bands.high - Instant high-band energy (6000-16000 Hz). 0..1.
 * @property {number} bands.lowSmoothed - Smoothed `low` (~150ms decay). 0..1.
 * @property {number} bands.lowMidSmoothed - Smoothed `lowMid` (~150ms decay). 0..1.
 * @property {number} bands.midSmoothed - Smoothed `mid` (~150ms decay). 0..1.
 * @property {number} bands.highMidSmoothed - Smoothed `highMid` (~150ms decay). 0..1.
 * @property {number} bands.highSmoothed - Smoothed `high` (~150ms decay). 0..1.
 * @property {Object} spectral - High-level spectral features derived from the FFT.
 * @property {number} spectral.brightness - Normalized spectral centroid in 0..1.
 * @property {number} spectral.flatness - Normalized spectral flatness in 0..1.
 * @property {() => Uint8Array} getFrequencyData - Returns the raw FFT magnitude spectrum for this stream as a `Uint8Array` (1024 bins, each 0..255). Snapshot semantics; see `AudioAPI.getFrequencyData`.
 * @property {() => Float32Array} getWaveform - Returns the raw time-domain waveform for this stream as a `Float32Array` (2048 samples, each -1..1). Snapshot semantics; see `AudioAPI.getWaveform`.
 */

/**
 * Real-time video API: drawable frame, dimensions, and the source-side properties of the connected stream. All computer-vision data and controls (faces, hands, pose, segmentation, the analysed frame, and feature enable/disable verbs) live on `viji.video.cv`. When `isConnected` is `false`, `currentFrame` is `null`, all dimensions are `0`, and every member of `cv` holds its empty default.
 * @typedef {Object} VideoAPI
 * @property {boolean} isConnected - `true` when a video stream is connected. When `false`, all other fields hold their default empty values.
 * @property {OffscreenCanvas | ImageBitmap |null} currentFrame - Latest video frame, drawable directly with `ctx.drawImage()`. `null` when disconnected.
 * @property {number} frameWidth - Source video frame width in pixels. `0` when disconnected.
 * @property {number} frameHeight - Source video frame height in pixels. `0` when disconnected.
 * @property {number} frameRate - Source video frame rate in Hz (frames per second). `0` when disconnected.
 * @property {() => ImageData |null} getFrameData - Returns the latest frame as raw RGBA `ImageData` for per-pixel CPU analysis, or `null` when disconnected. Slow compared to drawing `currentFrame` directly; use only when you need to read individual pixel values.
 * @property {VideoCVAPI} cv - Computer-vision surface for this video stream. Holds both the data outputs (`faces`, `hands`, `pose`, `segmentation`, `analysedFrame`, `getAnalysedFrameData`) and the verbs that activate them (`enable*`/`disable*`/`getActiveFeatures`/`isProcessing`). Multiple features can be active simultaneously, but each adds CPU/GPU and WebGL-context cost; toggle only what you need. `analysedFrame` and the result fields refresh together once per host frame as an atomic snapshot: within a single `render()` call they are always paired.
 */

/**
 * Mouse input state for the current frame: position, individual button states, per-frame movement, scroll wheel, and frame-based press / release events. Coordinates are in canvas-space pixels with `(0, 0)` at the top-left corner. For interactions that should also work on touch devices, prefer `viji.pointer`.
 * @typedef {Object} MouseAPI
 * @property {number} x - Canvas-space X position in pixels.
 * @property {number} y - Canvas-space Y position in pixels.
 * @property {boolean} isInCanvas - `true` when the cursor is currently over the canvas.
 * @property {boolean} isPressed - `true` if any mouse button is currently held.
 * @property {boolean} leftButton - `true` while the left mouse button is held.
 * @property {boolean} rightButton - `true` while the right mouse button is held. The browser context menu is suppressed on the canvas.
 * @property {boolean} middleButton - `true` while the middle (wheel) mouse button is held.
 * @property {number} deltaX - Horizontal movement this frame in pixels. Resets to `0` each frame.
 * @property {number} deltaY - Vertical movement this frame in pixels. Resets to `0` each frame.
 * @property {number} wheelDelta - Vertical scroll accumulated this frame (alias of `wheelY`). Resets to `0` each frame.
 * @property {number} wheelX - Horizontal scroll accumulated this frame (e.g., trackpad gestures, tilt-wheel mice). Resets to `0` each frame.
 * @property {number} wheelY - Vertical scroll accumulated this frame. Resets to `0` each frame.
 * @property {boolean} wasPressed - `true` for exactly one frame when any button is first pressed, then auto-resets.
 * @property {boolean} wasReleased - `true` for exactly one frame when any button is released, then auto-resets.
 * @property {boolean} wasMoved - `true` if the mouse moved this frame (any non-zero `deltaX` / `deltaY`). Resets each frame.
 */

/**
 * Keyboard input state for the current frame: per-key press / hold / release queries (case-insensitive), the live set of held keys, modifier flags, and a Shadertoy-compatible texture buffer for shader-side keyboard reads. Key names follow the browser's `event.key` standard (`'a'`, `'arrowup'`, `' '` for Space, `'enter'`, `'escape'`, etc.).
 * @typedef {Object} KeyboardAPI
 * @property {(key: string) => boolean} isPressed - Returns `true` while the named key is held. Case-insensitive.
 * @property {(key: string) => boolean} wasPressed - Returns `true` for exactly one frame on the rising edge of the named key (no key-repeat). Case-insensitive.
 * @property {(key: string) => boolean} wasReleased - Returns `true` for exactly one frame on the falling edge of the named key. Case-insensitive.
 * @property {Set<string>} activeKeys - Set of all currently held keys, lowercased. Persists across frames.
 * @property {Set<string>} pressedThisFrame - Set of keys whose key-down fired this frame, lowercased. Cleared each frame.
 * @property {Set<string>} releasedThisFrame - Set of keys whose key-up fired this frame, lowercased. Cleared each frame.
 * @property {string} lastKeyPressed - Most recently pressed key in its original case (e.g., `'A'` when Shift is held).
 * @property {string} lastKeyReleased - Most recently released key in its original case.
 * @property {boolean} shift - `true` while the Shift key is held.
 * @property {boolean} ctrl - `true` while the Ctrl key is held.
 * @property {boolean} alt - `true` while the Alt (or Option) key is held.
 * @property {boolean} meta - `true` while the Meta (Windows / Cmd) key is held.
 * @property {Uint8Array} textureData - Shadertoy-compatible 256×3 keyboard texture (256 keycodes × 3 rows). Row 0: held state (1 / 0). Row 1: pressed-this-frame (1 / 0). Row 2: per-key toggle. Bound to a uniform sampler in shader scenes; rarely needed in JS.
 */

/**
 * Multi-touch input state. Lists all active touches, plus per-frame `started` / `moved` / `ended` arrays for frame-based gesture handling. For single-point interactions that should also work with a mouse, prefer `viji.pointer`. It switches automatically between mouse and primary touch.
 * @typedef {Object} TouchAPI
 * @property {TouchPoint[]} points - All currently active touch points. Order is stable but not ordered by id.
 * @property {number} count - Number of currently active touches (equivalent to `points.length`).
 * @property {TouchPoint[]} started - Touches that started this frame (also visible in `points`). Cleared each frame.
 * @property {TouchPoint[]} moved - Touches that moved this frame. Cleared each frame.
 * @property {TouchPoint[]} ended - Touches that ended this frame. Each entry has `isEnding === true`. Cleared each frame.
 * @property {TouchPoint |null} primary - Convenience shortcut to `points[0]`, or `null` when no touches are active.
 */

/**
 * The Viji API surface available to artist code as the global `viji` object. Groups canvas access, timing, connected media APIs, user interaction, device sensors, parameter helpers, and the `useContext()` selector.
 * @typedef {Object} VijiAPI
 * @property {OffscreenCanvas} canvas - The `OffscreenCanvas` driving the scene. The host owns its lifecycle and dimensions; prefer `useContext()` over touching this directly.
 * @property {OffscreenCanvasRenderingContext2D} [ctx] - 2D rendering context. `undefined` until `viji.useContext('2d')` is called; afterwards equals the cached context.
 * @property {WebGLRenderingContext | WebGL2RenderingContext} [gl] - WebGL rendering context. `undefined` until `viji.useContext('webgl')` or `'webgl2'` is called; afterwards equals the cached context.
 * @property {number} width - Current canvas width in pixels. Updates automatically when the host resizes the canvas; read every frame.
 * @property {number} height - Current canvas height in pixels. Updates automatically when the host resizes the canvas; read every frame.
 * @property {number} time - Seconds elapsed since the scene started (monotonically increasing float). Use for oscillations and absolute-time effects.
 * @property {number} deltaTime - Seconds since the previous frame. Use for accumulation: movement, physics, fades, anything that should progress per second regardless of FPS.
 * @property {number} frameCount - Integer frame counter starting at `0` and incrementing by `1` each frame.
 * @property {number} fps - Target frames-per-second for the host's current frame-rate mode (`60` for `'full'`, `30` for `'half'`).
 * @property {AudioAPI} audio - Real-time analysis of the main audio stream: volume, frequency bands, beat detection, spectral features. Fields are zeroed when no audio source is connected.
 * @property {VideoAPI} video - Main video stream API: pixel access, frame metadata, and computer-vision results (face, hands, pose, segmentation).
 * @property {VideoAPI[]} videoStreams - Additional video streams provided by the host. These do not run CV processing; use them for raw pixel access only.
 * @property {AudioStreamAPI[]} audioStreams - Additional audio streams (lightweight analysis: volume, bands, spectral). No beat detection; use the main `audio` for that.
 * @property {MouseAPI} mouse - Mouse position, buttons, wheel, and per-frame movement state. Coordinates are in canvas pixels.
 * @property {KeyboardAPI} keyboard - Keyboard state: per-frame press/release queries, currently held keys, and modifier flags.
 * @property {TouchAPI} touches - Multi-touch state: count, primary touch shortcut, and the per-frame `started` / `moved` / `ended` arrays.
 * @property {PointerAPI} pointer - Unified pointer (mouse + primary touch). Convenient single-point input that works on both desktop and mobile.
 * @property {DeviceSensorState} device - Internal device sensors (motion + orientation) reported by the device running the scene.
 * @property {DeviceState[]} devices - External connected devices reporting sensor / camera / audio. Each entry has its own `id`, `name`, and per-device API surface.
 * @property {(defaultValue: number, config: SliderConfig) => SliderParameter} slider - Declares a numeric slider parameter. The host UI renders a draggable slider. Must be called at the top level of the scene, never inside `render()`. @example const radius = viji.slider(50, { min: 10, max: 200, step: 1, label: 'Radius' }); // ... function render(viji) { drawCircle(radius.value); }
 * @property {(defaultValue: ColorInput, config: ColorConfig) => ColorParameter} color - Declares a color parameter. Accepts hex strings, CSS color functions, or RGB / HSB objects; the value is always normalized to a canonical lowercase hex string and exposes derived `.rgb` / `.hsb` accessors. Must be called at the top level of the scene, never inside `render()`. @example const tint = viji.color('#ff6600', { label: 'Tint' }); // tint.value -> '#ff6600', tint.rgb -> { r: 255, g: 102, b: 0 }, tint.hsb -> { h: 24, s: 100, b: 100 }
 * @property {(defaultValue: boolean, config: ToggleConfig) => ToggleParameter} toggle - Declares a boolean toggle parameter. The host UI renders an on/off switch. Must be called at the top level of the scene, never inside `render()`. @example const showTrail = viji.toggle(true, { label: 'Show Trail' });
 * @property {(defaultValue: string | number, config: SelectConfig) => SelectParameter} select - Declares a dropdown selection parameter. The element type of `options` (`string` or `number`) determines the parameter's value type. Must be called at the top level of the scene, never inside `render()`. @example const shape = viji.select('circle', { options: ['circle', 'square', 'triangle'], label: 'Shape' });
 * @property {(defaultValue: string, config: TextConfig) => TextParameter} text - Declares a text input parameter. The host UI renders a single-line text field. Must be called at the top level of the scene, never inside `render()`. @example const caption = viji.text('Hello', { label: 'Caption', maxLength: 64 });
 * @property {(defaultValue: number, config: NumberConfig) => NumberParameter} number - Declares a precise numeric input parameter. Like `slider()` but the host UI shows a number field instead of a draggable handle. Must be called at the top level of the scene, never inside `render()`. @example const count = viji.number(12, { min: 1, max: 64, step: 1, label: 'Count' });
 * @property {(defaultValue: null, config: ImageConfig) => ImageParameter} image - Declares an image upload parameter. The user-supplied image becomes available as `value` (an `ImageBitmap`); in P5 scenes a `.p5` accessor is also added at runtime. Must be called at the top level of the scene, never inside `render()`. @example const tex = viji.image(null, { label: 'Texture' }); if (tex.value) ctx.drawImage(tex.value, 0, 0, viji.width, viji.height);
 * @property {(config: ButtonConfig) => ButtonParameter} button - Declares a momentary button parameter. `value` is `true` for one frame after the user clicks, then auto-resets. Perfect for triggering discrete events. Must be called at the top level of the scene, never inside `render()`. @example const reset = viji.button({ label: 'Reset' }); function render(viji) { if (reset.value) state = initialState; }
 * @property {(defaultValue: CoordinateValue, config: CoordinateConfig) => CoordinateParameter} coordinate - Declares a 2D coordinate parameter. Both `value.x` and `value.y` are in `-1..1`. Must be called at the top level of the scene, never inside `render()`. @example const origin = viji.coordinate({ x: 0, y: 0 }, { label: 'Origin' }); const cx = viji.width / 2 + origin.value.x * viji.width * 0.4;
 * @property {(type: '2d') => OffscreenCanvasRenderingContext2D} useContext - Selects the 2D canvas rendering context. Returns the same instance on subsequent calls and also stores it on `viji.ctx`. A canvas only supports one context type. If a different context type was already requested, the call returns `null`. Choose ONE type and use it for the entire scene. @example const ctx = viji.useContext('2d'); ctx.fillRect(0, 0, viji.width, viji.height);
 * @property {(type: 'webgl') => WebGLRenderingContext} useContext - Selects a WebGL 1 rendering context. Returns the same instance on subsequent calls and also stores it on `viji.gl`. A canvas only supports one context type. If a different context type was already requested, the call returns `null`. Choose ONE type and use it for the entire scene.
 * @property {(type: 'webgl2') => WebGL2RenderingContext} useContext - Selects a WebGL 2 rendering context. Returns the same instance on subsequent calls and also stores it on `viji.gl`. A canvas only supports one context type. If a different context type was already requested, the call returns `null`. Choose ONE type and use it for the entire scene.
 */

/**
 * One detected face produced by the video CV pipeline. Each field is populated only by its source model; fields whose source model is not enabled read as `null` so the absence is loud rather than silent. Enable the relevant `enable*` verb on `viji.video.cv` to populate each group: - `bounds`, `center`, `confidence`: populated by `enableFaceDetection(true)`. - `landmarks`: populated by `enableFaceMesh(true)` (empty array otherwise). - `headPose`: populated by `enableFaceMesh(true)`. - `blendshapes`, `expressions`: populated by `enableEmotionDetection(true)`. If a field is `null`, call the corresponding `enable*` verb on `viji.video.cv` to populate it. Each active CV feature consumes its own WebGL context for MediaPipe; enabling many at once on lower-end hardware can hit context limits.
 * @typedef {Object} FaceData
 * @property {number} id - Index-based face identifier (`0`, `1`, …). Stable within a single frame, may change between frames.
 * @property {Object} bounds - Bounding box, all components normalized to 0..1 of the source frame. `null` unless face detection is enabled.
 * @property {number} bounds.x - Left edge of the face bounding box, normalized 0..1.
 * @property {number} bounds.y - Top edge of the face bounding box, normalized 0..1.
 * @property {number} bounds.width - Width of the face bounding box, normalized 0..1.
 * @property {number} bounds.height - Height of the face bounding box, normalized 0..1.
 * @property {Object} center - Center of the bounding box, normalized 0..1. `null` unless face detection is enabled.
 * @property {number} center.x - Horizontal center of the face, normalized 0..1.
 * @property {number} center.y - Vertical center of the face, normalized 0..1.
 * @property {number |null} confidence - Detection confidence in 0..1. `null` unless face detection is enabled.
 * @property {Object} landmarks - 468 normalized face mesh landmarks when face mesh is enabled; empty array otherwise.
 * @property {number} landmarks.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} landmarks.y - Vertical landmark coordinate, normalized 0..1.
 * @property {number} landmarks.z - Optional depth (relative).
 * @property {Object} headPose - Estimated head rotation in degrees. `null` unless face mesh is enabled.
 * @property {number} headPose.pitch - Up/down rotation in degrees (-90..90). Positive = head looking up, negative = looking down.
 * @property {number} headPose.yaw - Left/right rotation in degrees (-90..90). Positive = head turned to the subject's right, negative = to the left.
 * @property {number} headPose.roll - Tilt rotation in degrees (-180..180). Positive = head tilted to the subject's right (right ear toward right shoulder).
 * @property {Object} expressions - Seven expression confidence scores in 0..1. `null` unless emotion detection is enabled.
 * @property {number} expressions.neutral - Confidence (0..1) of a neutral expression.
 * @property {number} expressions.happy - Confidence (0..1) of a happy / smiling expression.
 * @property {number} expressions.sad - Confidence (0..1) of a sad expression.
 * @property {number} expressions.angry - Confidence (0..1) of an angry expression.
 * @property {number} expressions.surprised - Confidence (0..1) of a surprised expression.
 * @property {number} expressions.disgusted - Confidence (0..1) of a disgusted expression.
 * @property {number} expressions.fearful - Confidence (0..1) of a fearful expression.
 * @property {FaceBlendshapes |null} blendshapes - 52 ARKit-compatible facial muscle coefficients. `null` unless emotion detection is enabled.
 */

/**
 * 52 ARKit-compatible face blendshape coefficients (each in 0..1) derived from MediaPipe FaceLandmarker. All fields are `0` unless emotion detection is enabled. Available on each `FaceData.blendshapes`.
 * @typedef {Object} FaceBlendshapes
 * @property {number} browDownLeft - Coefficient (0..1) for the inner brow of the left eye pulling down.
 * @property {number} browDownRight - Coefficient (0..1) for the inner brow of the right eye pulling down.
 * @property {number} browInnerUp - Coefficient (0..1) for both inner brows pulling up.
 * @property {number} browOuterUpLeft - Coefficient (0..1) for the outer left brow pulling up.
 * @property {number} browOuterUpRight - Coefficient (0..1) for the outer right brow pulling up.
 * @property {number} cheekPuff - Coefficient (0..1) for puffed cheeks.
 * @property {number} cheekSquintLeft - Coefficient (0..1) for the left cheek squinting.
 * @property {number} cheekSquintRight - Coefficient (0..1) for the right cheek squinting.
 * @property {number} eyeBlinkLeft - Coefficient (0..1) for the left eyelid closing.
 * @property {number} eyeBlinkRight - Coefficient (0..1) for the right eyelid closing.
 * @property {number} eyeLookDownLeft - Coefficient (0..1) for the left eye looking down.
 * @property {number} eyeLookDownRight - Coefficient (0..1) for the right eye looking down.
 * @property {number} eyeLookInLeft - Coefficient (0..1) for the left eye looking inward (toward the nose).
 * @property {number} eyeLookInRight - Coefficient (0..1) for the right eye looking inward.
 * @property {number} eyeLookOutLeft - Coefficient (0..1) for the left eye looking outward (away from the nose).
 * @property {number} eyeLookOutRight - Coefficient (0..1) for the right eye looking outward.
 * @property {number} eyeLookUpLeft - Coefficient (0..1) for the left eye looking up.
 * @property {number} eyeLookUpRight - Coefficient (0..1) for the right eye looking up.
 * @property {number} eyeSquintLeft - Coefficient (0..1) for the left eye squinting.
 * @property {number} eyeSquintRight - Coefficient (0..1) for the right eye squinting.
 * @property {number} eyeWideLeft - Coefficient (0..1) for the left eye opening wide.
 * @property {number} eyeWideRight - Coefficient (0..1) for the right eye opening wide.
 * @property {number} jawForward - Coefficient (0..1) for the jaw moving forward.
 * @property {number} jawLeft - Coefficient (0..1) for the jaw moving left.
 * @property {number} jawOpen - Coefficient (0..1) for the jaw opening (mouth open).
 * @property {number} jawRight - Coefficient (0..1) for the jaw moving right.
 * @property {number} mouthClose - Coefficient (0..1) for the mouth closing tightly.
 * @property {number} mouthDimpleLeft - Coefficient (0..1) for a dimple appearing on the left side.
 * @property {number} mouthDimpleRight - Coefficient (0..1) for a dimple appearing on the right side.
 * @property {number} mouthFrownLeft - Coefficient (0..1) for the left mouth corner pulling down (frown).
 * @property {number} mouthFrownRight - Coefficient (0..1) for the right mouth corner pulling down (frown).
 * @property {number} mouthFunnel - Coefficient (0..1) for funneling the lips outward.
 * @property {number} mouthLeft - Coefficient (0..1) for the mouth shifting left.
 * @property {number} mouthLowerDownLeft - Coefficient (0..1) for the lower lip on the left pulling down.
 * @property {number} mouthLowerDownRight - Coefficient (0..1) for the lower lip on the right pulling down.
 * @property {number} mouthPressLeft - Coefficient (0..1) for the left lip pressing inward.
 * @property {number} mouthPressRight - Coefficient (0..1) for the right lip pressing inward.
 * @property {number} mouthPucker - Coefficient (0..1) for puckered lips.
 * @property {number} mouthRight - Coefficient (0..1) for the mouth shifting right.
 * @property {number} mouthRollLower - Coefficient (0..1) for the lower lip rolling inward.
 * @property {number} mouthRollUpper - Coefficient (0..1) for the upper lip rolling inward.
 * @property {number} mouthShrugLower - Coefficient (0..1) for the lower lip shrugging.
 * @property {number} mouthShrugUpper - Coefficient (0..1) for the upper lip shrugging.
 * @property {number} mouthSmileLeft - Coefficient (0..1) for the left mouth corner pulling up (smile).
 * @property {number} mouthSmileRight - Coefficient (0..1) for the right mouth corner pulling up (smile).
 * @property {number} mouthStretchLeft - Coefficient (0..1) for the left mouth corner stretching outward.
 * @property {number} mouthStretchRight - Coefficient (0..1) for the right mouth corner stretching outward.
 * @property {number} mouthUpperUpLeft - Coefficient (0..1) for the upper lip on the left raising.
 * @property {number} mouthUpperUpRight - Coefficient (0..1) for the upper lip on the right raising.
 * @property {number} noseSneerLeft - Coefficient (0..1) for the left side of the nose sneering.
 * @property {number} noseSneerRight - Coefficient (0..1) for the right side of the nose sneering.
 * @property {number} tongueOut - Coefficient (0..1) for the tongue protruding.
 */

/**
 * One detected hand produced by the video CV pipeline. Carries 21 landmarks, a palm shortcut, and ML-classified gesture confidence scores. Up to two hands appear in `VideoAPI.hands` simultaneously.
 * @typedef {Object} HandData
 * @property {number} id - Index-based hand identifier (`0` or `1`).
 * @property {'left' | 'right'} handedness - Which hand. Always lowercase.
 * @property {number} confidence - Detection confidence in 0..1.
 * @property {Object} bounds - Bounding box, all components normalized to 0..1 of the source frame.
 * @property {number} bounds.x - Left edge of the hand bounding box, normalized 0..1.
 * @property {number} bounds.y - Top edge of the hand bounding box, normalized 0..1.
 * @property {number} bounds.width - Width of the hand bounding box, normalized 0..1.
 * @property {number} bounds.height - Height of the hand bounding box, normalized 0..1.
 * @property {Object} landmarks - 21 MediaPipe hand landmarks, normalized 0..1.
 * @property {number} landmarks.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} landmarks.y - Vertical landmark coordinate, normalized 0..1.
 * @property {number} landmarks.z - Depth (relative).
 * @property {Object} palm - Palm center, equivalent to `landmarks[9]` (middle-finger MCP).
 * @property {number} palm.x - Palm horizontal coordinate, normalized 0..1.
 * @property {number} palm.y - Palm vertical coordinate, normalized 0..1.
 * @property {number} palm.z - Palm depth (relative).
 * @property {Object} gestures - ML-classified gesture confidences from MediaPipe GestureRecognizer. Each value is in 0..1; multiple gestures can fire simultaneously.
 * @property {number} gestures.fist - Confidence (0..1) of a closed-fist gesture.
 * @property {number} gestures.openPalm - Confidence (0..1) of an open-palm gesture.
 * @property {number} gestures.peace - Confidence (0..1) of a peace / victory sign.
 * @property {number} gestures.thumbsUp - Confidence (0..1) of a thumbs-up gesture.
 * @property {number} gestures.thumbsDown - Confidence (0..1) of a thumbs-down gesture.
 * @property {number} gestures.pointing - Confidence (0..1) of a pointing-up gesture.
 * @property {number} gestures.iLoveYou - Confidence (0..1) of the ASL "I love you" sign.
 */

/**
 * Detected body pose from MediaPipe BlazePose. `landmarks` contains 33 points; the `face` / `torso` / `leftArm` / `rightArm` / `leftLeg` / `rightLeg` arrays are pre-grouped slices for convenience.
 * @typedef {Object} PoseData
 * @property {number} confidence - Average landmark visibility in 0..1.
 * @property {Object} landmarks - 33 BlazePose landmarks, normalized 0..1. Each carries a per-point `visibility` score.
 * @property {number} landmarks.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} landmarks.y - Vertical landmark coordinate, normalized 0..1.
 * @property {number} landmarks.z - Depth (relative).
 * @property {number} landmarks.visibility - Visibility / confidence of this individual landmark in 0..1.
 * @property {Object} face - Face landmarks (BlazePose indices 0..10). Coordinates normalized 0..1.
 * @property {number} face.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} face.y - Vertical landmark coordinate, normalized 0..1.
 * @property {Object} torso - Torso landmarks (BlazePose indices 11, 12, 23, 24). Coordinates normalized 0..1.
 * @property {number} torso.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} torso.y - Vertical landmark coordinate, normalized 0..1.
 * @property {Object} leftArm - Left-arm landmarks (BlazePose indices 11, 13, 15). Coordinates normalized 0..1.
 * @property {number} leftArm.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} leftArm.y - Vertical landmark coordinate, normalized 0..1.
 * @property {Object} rightArm - Right-arm landmarks (BlazePose indices 12, 14, 16). Coordinates normalized 0..1.
 * @property {number} rightArm.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} rightArm.y - Vertical landmark coordinate, normalized 0..1.
 * @property {Object} leftLeg - Left-leg landmarks (BlazePose indices 23, 25, 27, 29, 31). Coordinates normalized 0..1.
 * @property {number} leftLeg.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} leftLeg.y - Vertical landmark coordinate, normalized 0..1.
 * @property {Object} rightLeg - Right-leg landmarks (BlazePose indices 24, 26, 28, 30, 32). Coordinates normalized 0..1.
 * @property {number} rightLeg.x - Horizontal landmark coordinate, normalized 0..1.
 * @property {number} rightLeg.y - Vertical landmark coordinate, normalized 0..1.
 */

/**
 * Per-pixel person/background segmentation mask. Mask dimensions reflect the ML model's output and may differ from the source video frame.
 * @typedef {Object} SegmentationData
 * @property {Uint8Array} mask - Flat per-pixel mask: each byte is `0` (background) or `1` (person). Length = `width * height`.
 * @property {number} width - Mask width in pixels.
 * @property {number} height - Mask height in pixels.
 */

/**
 * Device motion data sourced from the platform's `DeviceMotionEvent`. All accelerations are in metres per second squared (m/s²); rotation rates are in degrees per second. Inner objects may be `null` when the underlying sensor is unavailable, and individual axes may be `null` on platforms that report only some components.
 * @typedef {Object} DeviceMotionData
 * @property {Object} acceleration - Acceleration without gravity (m/s²). `null` when no accelerometer is available.
 * @property {number |null} acceleration.x - Acceleration along the device's X axis in m/s². `null` if unsupported.
 * @property {number |null} acceleration.y - Acceleration along the device's Y axis in m/s². `null` if unsupported.
 * @property {number |null} acceleration.z - Acceleration along the device's Z axis in m/s². `null` if unsupported.
 * @property {Object} accelerationIncludingGravity - Acceleration including gravity (m/s²). `null` when no accelerometer is available.
 * @property {number |null} accelerationIncludingGravity.x - Acceleration including gravity along the device's X axis in m/s². `null` if unsupported.
 * @property {number |null} accelerationIncludingGravity.y - Acceleration including gravity along the device's Y axis in m/s². `null` if unsupported.
 * @property {number |null} accelerationIncludingGravity.z - Acceleration including gravity along the device's Z axis in m/s². `null` if unsupported.
 * @property {Object} rotationRate - Angular rotation rate (degrees per second). `null` when no gyroscope is available.
 * @property {number |null} rotationRate.alpha - Rotation rate around the device's Z axis in deg/s. `null` if unsupported.
 * @property {number |null} rotationRate.beta - Rotation rate around the device's X axis in deg/s. `null` if unsupported.
 * @property {number |null} rotationRate.gamma - Rotation rate around the device's Y axis in deg/s. `null` if unsupported.
 * @property {number} interval - Interval between sensor updates in milliseconds.
 */

/**
 * DeviceOrientationEvent data Matches native DeviceOrientationEvent structure
 * @typedef {Object} DeviceOrientationData
 * @property {number |null} alpha - Rotation around Z-axis (0-360 degrees, compass heading)
 * @property {number |null} beta - Rotation around X-axis (-180 to 180 degrees, front-to-back tilt)
 * @property {number |null} gamma - Rotation around Y-axis (-90 to 90 degrees, left-to-right tilt)
 * @property {boolean} absolute - True if using magnetometer (compass) for absolute orientation
 */

/**
 * Sensor snapshot for the device running the scene. Both fields read `null` when the corresponding sensor is unavailable or has not delivered a sample yet.
 * @typedef {Object} DeviceSensorState
 * @property {DeviceMotionData |null} motion - Motion data (acceleration, rotation rate, sampling interval). `null` if no motion sensor is available.
 * @property {DeviceOrientationData |null} orientation - Orientation data (alpha/beta/gamma in degrees). `null` if no orientation sensor is available.
 */

/**
 * External device state (includes id and name)
 * @typedef {Object} DeviceState
 * @property {string} id - Unique device identifier
 * @property {string} name - User-friendly device name
 * @property {VideoAPI |null} video - Device camera video (null if not available)
 * @property {AudioStreamAPI |null} audio - Device audio stream (null if not available)
 */

/**
 * @typedef {function(VijiAPI): void} Render
 */

/**
 * @typedef {function(VijiAPI): void} Setup
 */

/** Global viji object available in artist code */
declare const viji: VijiAPI;

/** Artist render function - called every frame */
declare function render(viji: VijiAPI): void;

/** Artist setup function - called once at initialization */
declare function setup(viji: VijiAPI): void;
