@viji-dev/core 0.16.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -284,16 +284,28 @@ declare global {
284
284
  group?: string;
285
285
  /** Visibility category. The control hides when its capability is unavailable. Default: `'general'`. */
286
286
  category?: ParameterCategory;
287
+ /**
288
+ * Enable a transparency channel. When `true` the canonical value is always an
289
+ * 8-digit `#rrggbbaa` (opaque inputs are padded `ff`), the picker shows an alpha
290
+ * slider, and the shader uniform is a `vec4`. When `false` (default) the value is
291
+ * `#rrggbb` and any alpha-bearing input is rejected. Default: `false`.
292
+ */
293
+ alpha?: boolean;
287
294
  }
288
295
 
289
296
  /**
290
297
  * Accepted input forms for color parameters. Internally normalized to canonical
291
- * lowercase 6-digit hex `#rrggbb`. See `viji.color()` for full documentation.
298
+ * lowercase hex: `#rrggbb` for an opaque parameter, `#rrggbbaa` for a parameter
299
+ * declared with `alpha: true`. See `viji.color()` for full documentation.
292
300
  *
293
301
  * - `string`: hex (`#rrggbb`, `#rgb`), CSS `rgb(r, g, b)`, CSS `hsl(h, s%, l%)`,
294
302
  * GLSL-style `vec3(r, g, b)` (0..1), or P5-style `hsb(h, s, b)` (0..360 / 0..100 / 0..100)
295
303
  * - `{ r, g, b }`: RGB object with components in 0..255
296
304
  * - `{ h, s, b }`: HSB object with `h` in 0..360, `s` and `b` in 0..100
305
+ *
306
+ * Alpha-bearing forms (`#rrggbbaa`, `#rgba`, `rgba()`, `hsla()`, `vec4()`, and the
307
+ * objects with an `a` field in 0..1) are accepted ONLY by a parameter declared with
308
+ * `alpha: true`; an opaque parameter rejects them even when the alpha is `1`.
297
309
  */
298
310
  type ColorInput = string | {
299
311
  /** Red component in 0..255. */
@@ -302,6 +314,8 @@ declare global {
302
314
  g: number;
303
315
  /** Blue component in 0..255. */
304
316
  b: number;
317
+ /** Alpha in 0..1. Only valid on a parameter declared with `alpha: true`. */
318
+ a?: number;
305
319
  } | {
306
320
  /** Hue in 0..360. */
307
321
  h: number;
@@ -309,16 +323,22 @@ declare global {
309
323
  s: number;
310
324
  /** Brightness in 0..100. */
311
325
  b: number;
326
+ /** Alpha in 0..1. Only valid on a parameter declared with `alpha: true`. */
327
+ a?: number;
312
328
  };
313
329
 
314
330
  /**
315
331
  * Reactive object returned by `viji.color()`. `value` is always a canonical
316
- * lowercase 6-digit hex string; `rgb` and `hsb` are derived accessors that are
317
- * recomputed (and frozen) every time the user changes the color.
332
+ * lowercase hex string whose width is fixed by the parameter's mode (`#rrggbb`,
333
+ * or `#rrggbbaa` when declared with `alpha: true`); `rgb`, `hsb` and `alpha` are
334
+ * derived accessors that are recomputed (and frozen) every time the user changes
335
+ * the color.
318
336
  */
319
337
  interface ColorParameter {
320
- /** Canonical hex color string `#rrggbb` (lowercase). Updates in real-time. */
338
+ /** Canonical lowercase hex color string: `#rrggbb`, or `#rrggbbaa` when `alpha: true`. Updates in real-time. */
321
339
  value: string;
340
+ /** Alpha in 0..1. Always present: `1` on an opaque parameter, the live alpha when `alpha: true`. */
341
+ alpha: number;
322
342
  /** RGB components as integers in 0..255 (frozen, recomputed when value changes). */
323
343
  rgb: {
324
344
  /** Red component, integer in 0..255. */
@@ -708,6 +728,101 @@ declare global {
708
728
  max: number;
709
729
  }
710
730
 
731
+ /**
732
+ * Configuration object passed to `viji.gradient()`. Defines the ramp editor's
733
+ * stop bounds, transparency mode, label and UI grouping/visibility.
734
+ */
735
+ interface GradientConfig {
736
+ /**
737
+ * Advanced: explicit parameter identity. Normally you do NOT set this —
738
+ * the parameter's name is inferred from the variable or object key you
739
+ * assign it to (`const ramp = viji.gradient(...)` → `ramp`). Set `name`
740
+ * only for parameters not assigned to a variable or key (created in an
741
+ * array, loop, or factory). Must be a valid identifier and scene-globally
742
+ * unique. When set, it overrides the inferred name.
743
+ */
744
+ name?: string;
745
+ /** Minimum number of stops the editor allows. Integer in `2..32`. Default: `2`. */
746
+ minStops?: number;
747
+ /** Maximum number of stops the editor allows. Integer in `2..32`; sizes the shader uniform arrays. Default: `8`. */
748
+ maxStops?: number;
749
+ /** Display name shown next to the ramp in the parameter UI. Optional — defaults to the parameter's name. */
750
+ label?: string;
751
+ /** Optional tooltip / help text shown next to the control. */
752
+ description?: string;
753
+ /** Group name for organizing related parameters under a shared heading. Default: `'general'`. */
754
+ group?: string;
755
+ /** Visibility category. The control hides when its capability is unavailable. Default: `'general'`. */
756
+ category?: ParameterCategory;
757
+ /**
758
+ * Enable per-stop transparency. When `true` every stop color is `#rrggbbaa`
759
+ * (opaque inputs padded `ff`) and the shader sampler returns a `vec4`. When
760
+ * `false` (default) stops are `#rrggbb` and alpha-bearing stop colors are rejected.
761
+ */
762
+ alpha?: boolean;
763
+ }
764
+
765
+ /**
766
+ * Stop list accepted by `viji.gradient()` and `setParameter()`. Any order;
767
+ * normalized to a sorted, canonical {@link GradientValue}.
768
+ */
769
+ type GradientInput = ReadonlyArray<GradientStopInput>;
770
+
771
+ /**
772
+ * Reactive object returned by `viji.gradient()`. `value` is the live, frozen,
773
+ * sorted stop list; `at(t)` samples the ramp with CSS `linear-gradient`
774
+ * semantics (premultiplied sRGB between stops, hard edges on duplicate
775
+ * positions) and returns a canonical hex string in the same width as the stops.
776
+ */
777
+ interface GradientParameter {
778
+ /** Current stops, frozen and sorted ascending by position. Updates in real-time. */
779
+ value: GradientValue;
780
+ /**
781
+ * Sample the ramp at `t` (clamped to `0..1`). Returns canonical hex in the
782
+ * gradient's width. The shader renderer exposes the same function as
783
+ * `<name>(float t)` in GLSL.
784
+ */
785
+ at(t: number): string;
786
+ /** Display name shown next to the ramp in the parameter UI. */
787
+ label?: string;
788
+ /** Tooltip / help text for the control (empty string when not configured). */
789
+ description?: string;
790
+ /** Group name under which the control appears in the UI. */
791
+ group: string;
792
+ /** Visibility category that controls when the parameter is shown. */
793
+ category: ParameterCategory;
794
+ }
795
+
796
+ /**
797
+ * One stop of a gradient value. `color` is canonical lowercase hex in the
798
+ * gradient's mode (`#rrggbb`, or `#rrggbbaa` when declared with `alpha: true`).
799
+ */
800
+ interface GradientStop {
801
+ /** Canonical hex color of this stop. */
802
+ color: string;
803
+ /** Position along the ramp in `0..1`. */
804
+ position: number;
805
+ }
806
+
807
+ /**
808
+ * One artist- or host-supplied gradient stop. `color` accepts every form a
809
+ * color parameter accepts, normalized per the gradient's `alpha` mode.
810
+ */
811
+ interface GradientStopInput {
812
+ /** Any accepted color form (hex, CSS functions, RGB / HSB objects). */
813
+ color: ColorInput;
814
+ /** Position along the ramp in `0..1`. */
815
+ position: number;
816
+ }
817
+
818
+ /**
819
+ * Value of a gradient parameter: a frozen list of stops sorted ascending by
820
+ * position. Duplicate positions are allowed and form a hard edge. The length is
821
+ * within the parameter's `minStops..maxStops`. No wrapper: geometry (linear,
822
+ * radial, angle) is the scene's concern.
823
+ */
824
+ type GradientValue = readonly GradientStop[];
825
+
711
826
  /**
712
827
  * One detected hand produced by the video CV pipeline. Carries 21 landmarks,
713
828
  * a palm shortcut, and ML-classified gesture confidence scores. Up to two
@@ -802,7 +917,12 @@ declare global {
802
917
  * the image works directly with `image()`, `texture()`, etc.
803
918
  */
804
919
  interface ImageParameter {
805
- /** Uploaded image as an `ImageBitmap`, or `null` until the user provides one. */
920
+ /**
921
+ * Uploaded image as an `ImageBitmap`, or `null` until the user provides one.
922
+ * Read it where you use it (inside `render()`): when the host replaces or
923
+ * clears the image, the previous bitmap is closed, so a reference kept from
924
+ * an earlier frame becomes unusable.
925
+ */
806
926
  value: ImageBitmap | null;
807
927
  /** P5-compatible image wrapper. Only available in the P5 renderer; added at runtime by the P5 adapter. */
808
928
  readonly p5?: any;
@@ -1350,7 +1470,7 @@ declare global {
1350
1470
  isEnding: boolean;
1351
1471
  }
1352
1472
 
1353
- const VERSION = "0.16.1";
1473
+ const VERSION = "0.18.0";
1354
1474
 
1355
1475
  /**
1356
1476
  * Real-time video API: drawable frame, dimensions, and the source-side
@@ -1594,12 +1714,17 @@ declare global {
1594
1714
  slider: (defaultValue: number, config: SliderConfig) => SliderParameter;
1595
1715
  /**
1596
1716
  * Declares a color parameter. Accepts hex strings, CSS color functions, or RGB / HSB objects;
1597
- * the value is always normalized to a canonical lowercase hex string and exposes derived `.rgb` / `.hsb` accessors.
1717
+ * the value is always normalized to a canonical lowercase hex string and exposes derived
1718
+ * `.rgb` / `.hsb` / `.alpha` accessors. Pass `alpha: true` to enable transparency: the value
1719
+ * becomes `#rrggbbaa` and alpha-bearing inputs (`rgba()`, `#rrggbbaa`, ...) are accepted.
1720
+ * Without it, alpha-bearing inputs are rejected.
1598
1721
  * Must be called at the top level of the scene, never inside `render()`.
1599
1722
  *
1600
1723
  * @example
1601
1724
  * const tint = viji.color('#ff6600', { label: 'Tint' });
1602
- * // tint.value -> '#ff6600', tint.rgb -> { r: 255, g: 102, b: 0 }, tint.hsb -> { h: 24, s: 100, b: 100 }
1725
+ * // tint.value -> '#ff6600', tint.rgb -> { r: 255, g: 102, b: 0 }, tint.hsb -> { h: 24, s: 100, b: 100 }, tint.alpha -> 1
1726
+ * const glow = viji.color('#ffffff80', { label: 'Glow', alpha: true });
1727
+ * // glow.value -> '#ffffff80', glow.alpha -> 0.5
1603
1728
  */
1604
1729
  color: (defaultValue: ColorInput, config: ColorConfig) => ColorParameter;
1605
1730
  /**
@@ -1665,6 +1790,27 @@ declare global {
1665
1790
  * const cx = viji.width / 2 + origin.value.x * viji.width * 0.4;
1666
1791
  */
1667
1792
  coordinate: (defaultValue: CoordinateValue, config: CoordinateConfig) => CoordinateParameter;
1793
+ /**
1794
+ * Declares a gradient parameter. The host renders a ramp editor; `value` is the live,
1795
+ * sorted stop list and `at(t)` samples the ramp (CSS `linear-gradient` semantics).
1796
+ * Stop colors accept every color form; pass `alpha: true` for per-stop transparency.
1797
+ * `default` is required (no evenly-spaced shorthand). Must be called at the top level
1798
+ * of the scene, never inside `render()`.
1799
+ *
1800
+ * @example
1801
+ * const ramp = viji.gradient(
1802
+ * [{ color: '#ff6b6b', position: 0 }, { color: '#4ecdc4', position: 1 }],
1803
+ * { label: 'Ramp' }
1804
+ * );
1805
+ * function render(viji) {
1806
+ * const fill = viji.ctx.createLinearGradient(0, 0, viji.width, 0);
1807
+ * for (const stop of ramp.value) fill.addColorStop(stop.position, stop.color);
1808
+ * viji.ctx.fillStyle = fill;
1809
+ * viji.ctx.fillRect(0, 0, viji.width, viji.height);
1810
+ * viji.ctx.fillStyle = ramp.at(0.5); // per-element color, same math as the fill
1811
+ * }
1812
+ */
1813
+ gradient: (defaultValue: GradientInput, config: GradientConfig) => GradientParameter;
1668
1814
  /**
1669
1815
  * Selects the 2D canvas rendering context. Returns the same instance on
1670
1816
  * subsequent calls and also stores it on `viji.ctx`. A canvas only supports
@@ -284,16 +284,28 @@ declare global {
284
284
  group?: string;
285
285
  /** Visibility category. The control hides when its capability is unavailable. Default: `'general'`. */
286
286
  category?: ParameterCategory;
287
+ /**
288
+ * Enable a transparency channel. When `true` the canonical value is always an
289
+ * 8-digit `#rrggbbaa` (opaque inputs are padded `ff`), the picker shows an alpha
290
+ * slider, and the shader uniform is a `vec4`. When `false` (default) the value is
291
+ * `#rrggbb` and any alpha-bearing input is rejected. Default: `false`.
292
+ */
293
+ alpha?: boolean;
287
294
  }
288
295
 
289
296
  /**
290
297
  * Accepted input forms for color parameters. Internally normalized to canonical
291
- * lowercase 6-digit hex `#rrggbb`. See `viji.color()` for full documentation.
298
+ * lowercase hex: `#rrggbb` for an opaque parameter, `#rrggbbaa` for a parameter
299
+ * declared with `alpha: true`. See `viji.color()` for full documentation.
292
300
  *
293
301
  * - `string`: hex (`#rrggbb`, `#rgb`), CSS `rgb(r, g, b)`, CSS `hsl(h, s%, l%)`,
294
302
  * GLSL-style `vec3(r, g, b)` (0..1), or P5-style `hsb(h, s, b)` (0..360 / 0..100 / 0..100)
295
303
  * - `{ r, g, b }`: RGB object with components in 0..255
296
304
  * - `{ h, s, b }`: HSB object with `h` in 0..360, `s` and `b` in 0..100
305
+ *
306
+ * Alpha-bearing forms (`#rrggbbaa`, `#rgba`, `rgba()`, `hsla()`, `vec4()`, and the
307
+ * objects with an `a` field in 0..1) are accepted ONLY by a parameter declared with
308
+ * `alpha: true`; an opaque parameter rejects them even when the alpha is `1`.
297
309
  */
298
310
  type ColorInput = string | {
299
311
  /** Red component in 0..255. */
@@ -302,6 +314,8 @@ declare global {
302
314
  g: number;
303
315
  /** Blue component in 0..255. */
304
316
  b: number;
317
+ /** Alpha in 0..1. Only valid on a parameter declared with `alpha: true`. */
318
+ a?: number;
305
319
  } | {
306
320
  /** Hue in 0..360. */
307
321
  h: number;
@@ -309,16 +323,22 @@ declare global {
309
323
  s: number;
310
324
  /** Brightness in 0..100. */
311
325
  b: number;
326
+ /** Alpha in 0..1. Only valid on a parameter declared with `alpha: true`. */
327
+ a?: number;
312
328
  };
313
329
 
314
330
  /**
315
331
  * Reactive object returned by `viji.color()`. `value` is always a canonical
316
- * lowercase 6-digit hex string; `rgb` and `hsb` are derived accessors that are
317
- * recomputed (and frozen) every time the user changes the color.
332
+ * lowercase hex string whose width is fixed by the parameter's mode (`#rrggbb`,
333
+ * or `#rrggbbaa` when declared with `alpha: true`); `rgb`, `hsb` and `alpha` are
334
+ * derived accessors that are recomputed (and frozen) every time the user changes
335
+ * the color.
318
336
  */
319
337
  interface ColorParameter {
320
- /** Canonical hex color string `#rrggbb` (lowercase). Updates in real-time. */
338
+ /** Canonical lowercase hex color string: `#rrggbb`, or `#rrggbbaa` when `alpha: true`. Updates in real-time. */
321
339
  value: string;
340
+ /** Alpha in 0..1. Always present: `1` on an opaque parameter, the live alpha when `alpha: true`. */
341
+ alpha: number;
322
342
  /** RGB components as integers in 0..255 (frozen, recomputed when value changes). */
323
343
  rgb: {
324
344
  /** Red component, integer in 0..255. */
@@ -708,6 +728,101 @@ declare global {
708
728
  max: number;
709
729
  }
710
730
 
731
+ /**
732
+ * Configuration object passed to `viji.gradient()`. Defines the ramp editor's
733
+ * stop bounds, transparency mode, label and UI grouping/visibility.
734
+ */
735
+ interface GradientConfig {
736
+ /**
737
+ * Advanced: explicit parameter identity. Normally you do NOT set this —
738
+ * the parameter's name is inferred from the variable or object key you
739
+ * assign it to (`const ramp = viji.gradient(...)` → `ramp`). Set `name`
740
+ * only for parameters not assigned to a variable or key (created in an
741
+ * array, loop, or factory). Must be a valid identifier and scene-globally
742
+ * unique. When set, it overrides the inferred name.
743
+ */
744
+ name?: string;
745
+ /** Minimum number of stops the editor allows. Integer in `2..32`. Default: `2`. */
746
+ minStops?: number;
747
+ /** Maximum number of stops the editor allows. Integer in `2..32`; sizes the shader uniform arrays. Default: `8`. */
748
+ maxStops?: number;
749
+ /** Display name shown next to the ramp in the parameter UI. Optional — defaults to the parameter's name. */
750
+ label?: string;
751
+ /** Optional tooltip / help text shown next to the control. */
752
+ description?: string;
753
+ /** Group name for organizing related parameters under a shared heading. Default: `'general'`. */
754
+ group?: string;
755
+ /** Visibility category. The control hides when its capability is unavailable. Default: `'general'`. */
756
+ category?: ParameterCategory;
757
+ /**
758
+ * Enable per-stop transparency. When `true` every stop color is `#rrggbbaa`
759
+ * (opaque inputs padded `ff`) and the shader sampler returns a `vec4`. When
760
+ * `false` (default) stops are `#rrggbb` and alpha-bearing stop colors are rejected.
761
+ */
762
+ alpha?: boolean;
763
+ }
764
+
765
+ /**
766
+ * Stop list accepted by `viji.gradient()` and `setParameter()`. Any order;
767
+ * normalized to a sorted, canonical {@link GradientValue}.
768
+ */
769
+ type GradientInput = ReadonlyArray<GradientStopInput>;
770
+
771
+ /**
772
+ * Reactive object returned by `viji.gradient()`. `value` is the live, frozen,
773
+ * sorted stop list; `at(t)` samples the ramp with CSS `linear-gradient`
774
+ * semantics (premultiplied sRGB between stops, hard edges on duplicate
775
+ * positions) and returns a canonical hex string in the same width as the stops.
776
+ */
777
+ interface GradientParameter {
778
+ /** Current stops, frozen and sorted ascending by position. Updates in real-time. */
779
+ value: GradientValue;
780
+ /**
781
+ * Sample the ramp at `t` (clamped to `0..1`). Returns canonical hex in the
782
+ * gradient's width. The shader renderer exposes the same function as
783
+ * `<name>(float t)` in GLSL.
784
+ */
785
+ at(t: number): string;
786
+ /** Display name shown next to the ramp in the parameter UI. */
787
+ label?: string;
788
+ /** Tooltip / help text for the control (empty string when not configured). */
789
+ description?: string;
790
+ /** Group name under which the control appears in the UI. */
791
+ group: string;
792
+ /** Visibility category that controls when the parameter is shown. */
793
+ category: ParameterCategory;
794
+ }
795
+
796
+ /**
797
+ * One stop of a gradient value. `color` is canonical lowercase hex in the
798
+ * gradient's mode (`#rrggbb`, or `#rrggbbaa` when declared with `alpha: true`).
799
+ */
800
+ interface GradientStop {
801
+ /** Canonical hex color of this stop. */
802
+ color: string;
803
+ /** Position along the ramp in `0..1`. */
804
+ position: number;
805
+ }
806
+
807
+ /**
808
+ * One artist- or host-supplied gradient stop. `color` accepts every form a
809
+ * color parameter accepts, normalized per the gradient's `alpha` mode.
810
+ */
811
+ interface GradientStopInput {
812
+ /** Any accepted color form (hex, CSS functions, RGB / HSB objects). */
813
+ color: ColorInput;
814
+ /** Position along the ramp in `0..1`. */
815
+ position: number;
816
+ }
817
+
818
+ /**
819
+ * Value of a gradient parameter: a frozen list of stops sorted ascending by
820
+ * position. Duplicate positions are allowed and form a hard edge. The length is
821
+ * within the parameter's `minStops..maxStops`. No wrapper: geometry (linear,
822
+ * radial, angle) is the scene's concern.
823
+ */
824
+ type GradientValue = readonly GradientStop[];
825
+
711
826
  /**
712
827
  * One detected hand produced by the video CV pipeline. Carries 21 landmarks,
713
828
  * a palm shortcut, and ML-classified gesture confidence scores. Up to two
@@ -802,7 +917,12 @@ declare global {
802
917
  * the image works directly with `image()`, `texture()`, etc.
803
918
  */
804
919
  interface ImageParameter {
805
- /** Uploaded image as an `ImageBitmap`, or `null` until the user provides one. */
920
+ /**
921
+ * Uploaded image as an `ImageBitmap`, or `null` until the user provides one.
922
+ * Read it where you use it (inside `render()`): when the host replaces or
923
+ * clears the image, the previous bitmap is closed, so a reference kept from
924
+ * an earlier frame becomes unusable.
925
+ */
806
926
  value: ImageBitmap | null;
807
927
  /** P5-compatible image wrapper. Only available in the P5 renderer; added at runtime by the P5 adapter. */
808
928
  readonly p5?: any;
@@ -1339,7 +1459,7 @@ declare global {
1339
1459
  isEnding: boolean;
1340
1460
  }
1341
1461
 
1342
- const VERSION = "0.16.1";
1462
+ const VERSION = "0.18.0";
1343
1463
 
1344
1464
  /**
1345
1465
  * Real-time video API: drawable frame, dimensions, and the source-side
@@ -1583,12 +1703,17 @@ declare global {
1583
1703
  slider: (defaultValue: number, config: SliderConfig) => SliderParameter;
1584
1704
  /**
1585
1705
  * Declares a color parameter. Accepts hex strings, CSS color functions, or RGB / HSB objects;
1586
- * the value is always normalized to a canonical lowercase hex string and exposes derived `.rgb` / `.hsb` accessors.
1706
+ * the value is always normalized to a canonical lowercase hex string and exposes derived
1707
+ * `.rgb` / `.hsb` / `.alpha` accessors. Pass `alpha: true` to enable transparency: the value
1708
+ * becomes `#rrggbbaa` and alpha-bearing inputs (`rgba()`, `#rrggbbaa`, ...) are accepted.
1709
+ * Without it, alpha-bearing inputs are rejected.
1587
1710
  * Must be called at the top level of the scene, never inside `render()`.
1588
1711
  *
1589
1712
  * @example
1590
1713
  * const tint = viji.color('#ff6600', { label: 'Tint' });
1591
- * // tint.value -> '#ff6600', tint.rgb -> { r: 255, g: 102, b: 0 }, tint.hsb -> { h: 24, s: 100, b: 100 }
1714
+ * // tint.value -> '#ff6600', tint.rgb -> { r: 255, g: 102, b: 0 }, tint.hsb -> { h: 24, s: 100, b: 100 }, tint.alpha -> 1
1715
+ * const glow = viji.color('#ffffff80', { label: 'Glow', alpha: true });
1716
+ * // glow.value -> '#ffffff80', glow.alpha -> 0.5
1592
1717
  */
1593
1718
  color: (defaultValue: ColorInput, config: ColorConfig) => ColorParameter;
1594
1719
  /**
@@ -1654,6 +1779,27 @@ declare global {
1654
1779
  * const cx = viji.width / 2 + origin.value.x * viji.width * 0.4;
1655
1780
  */
1656
1781
  coordinate: (defaultValue: CoordinateValue, config: CoordinateConfig) => CoordinateParameter;
1782
+ /**
1783
+ * Declares a gradient parameter. The host renders a ramp editor; `value` is the live,
1784
+ * sorted stop list and `at(t)` samples the ramp (CSS `linear-gradient` semantics).
1785
+ * Stop colors accept every color form; pass `alpha: true` for per-stop transparency.
1786
+ * `default` is required (no evenly-spaced shorthand). Must be called at the top level
1787
+ * of the scene, never inside `render()`.
1788
+ *
1789
+ * @example
1790
+ * const ramp = viji.gradient(
1791
+ * [{ color: '#ff6b6b', position: 0 }, { color: '#4ecdc4', position: 1 }],
1792
+ * { label: 'Ramp' }
1793
+ * );
1794
+ * function render(viji) {
1795
+ * const fill = viji.ctx.createLinearGradient(0, 0, viji.width, 0);
1796
+ * for (const stop of ramp.value) fill.addColorStop(stop.position, stop.color);
1797
+ * viji.ctx.fillStyle = fill;
1798
+ * viji.ctx.fillRect(0, 0, viji.width, viji.height);
1799
+ * viji.ctx.fillStyle = ramp.at(0.5); // per-element color, same math as the fill
1800
+ * }
1801
+ */
1802
+ gradient: (defaultValue: GradientInput, config: GradientConfig) => GradientParameter;
1657
1803
  /**
1658
1804
  * Selects the 2D canvas rendering context. Returns the same instance on
1659
1805
  * subsequent calls and also stores it on `viji.ctx`. A canvas only supports
@@ -24,6 +24,7 @@
24
24
  * @property {string} [description] - Optional tooltip / help text shown next to the control.
25
25
  * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
26
26
  * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
27
+ * @property {boolean} [alpha] - Enable a transparency channel. When `true` the canonical value is always an 8-digit `#rrggbbaa` (opaque inputs are padded `ff`), the picker shows an alpha slider, and the shader uniform is a `vec4`. When `false` (default) the value is `#rrggbb` and any alpha-bearing input is rejected. Default: `false`.
27
28
  */
28
29
 
29
30
  /**
@@ -102,6 +103,19 @@
102
103
  * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
103
104
  */
104
105
 
106
+ /**
107
+ * Configuration object passed to `viji.gradient()`. Defines the ramp editor's stop bounds, transparency mode, label and UI grouping/visibility.
108
+ * @typedef {Object} GradientConfig
109
+ * @property {string} [name] - Advanced: explicit parameter identity. Normally you do NOT set this — the parameter's name is inferred from the variable or object key you assign it to (`const ramp = viji.gradient(...)` → `ramp`). Set `name` only for parameters not assigned to a variable or key (created in an array, loop, or factory). Must be a valid identifier and scene-globally unique. When set, it overrides the inferred name.
110
+ * @property {number} [minStops] - Minimum number of stops the editor allows. Integer in `2..32`. Default: `2`.
111
+ * @property {number} [maxStops] - Maximum number of stops the editor allows. Integer in `2..32`; sizes the shader uniform arrays. Default: `8`.
112
+ * @property {string} [label] - Display name shown next to the ramp in the parameter UI. Optional — defaults to the parameter's name.
113
+ * @property {string} [description] - Optional tooltip / help text shown next to the control.
114
+ * @property {string} [group] - Group name for organizing related parameters under a shared heading. Default: `'general'`.
115
+ * @property {ParameterCategory} [category] - Visibility category. The control hides when its capability is unavailable. Default: `'general'`.
116
+ * @property {boolean} [alpha] - Enable per-stop transparency. When `true` every stop color is `#rrggbbaa` (opaque inputs padded `ff`) and the shader sampler returns a `vec4`. When `false` (default) stops are `#rrggbb` and alpha-bearing stop colors are rejected.
117
+ */
118
+
105
119
  /**
106
120
  * Reactive object returned by `viji.slider()`. `value` updates in real-time as the user drags the control; the remaining fields mirror the configuration.
107
121
  * @typedef {Object} SliderParameter
@@ -116,9 +130,10 @@
116
130
  */
117
131
 
118
132
  /**
119
- * 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.
133
+ * Reactive object returned by `viji.color()`. `value` is always a canonical lowercase hex string whose width is fixed by the parameter's mode (`#rrggbb`, or `#rrggbbaa` when declared with `alpha: true`); `rgb`, `hsb` and `alpha` are derived accessors that are recomputed (and frozen) every time the user changes the color.
120
134
  * @typedef {Object} ColorParameter
121
- * @property {string} value - Canonical hex color string `#rrggbb` (lowercase). Updates in real-time.
135
+ * @property {string} value - Canonical lowercase hex color string: `#rrggbb`, or `#rrggbbaa` when `alpha: true`. Updates in real-time.
136
+ * @property {number} alpha - Alpha in 0..1. Always present: `1` on an opaque parameter, the live alpha when `alpha: true`.
122
137
  * @property {Object} rgb - RGB components as integers in 0..255 (frozen, recomputed when value changes).
123
138
  * @property {number} rgb.r - Red component, integer in 0..255.
124
139
  * @property {number} rgb.g - Green component, integer in 0..255.
@@ -181,7 +196,7 @@
181
196
  /**
182
197
  * 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.
183
198
  * @typedef {Object} ImageParameter
184
- * @property {ImageBitmap |null} value - Uploaded image as an `ImageBitmap`, or `null` until the user provides one.
199
+ * @property {ImageBitmap |null} value - Uploaded image as an `ImageBitmap`, or `null` until the user provides one. Read it where you use it (inside `render()`): when the host replaces or clears the image, the previous bitmap is closed, so a reference kept from an earlier frame becomes unusable.
185
200
  * @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.
186
201
  * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
187
202
  * @property {string} group - Group name under which the control appears in the UI.
@@ -209,6 +224,31 @@
209
224
  * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
210
225
  */
211
226
 
227
+ /**
228
+ * Reactive object returned by `viji.gradient()`. `value` is the live, frozen, sorted stop list; `at(t)` samples the ramp with CSS `linear-gradient` semantics (premultiplied sRGB between stops, hard edges on duplicate positions) and returns a canonical hex string in the same width as the stops.
229
+ * @typedef {Object} GradientParameter
230
+ * @property {GradientValue} value - Current stops, frozen and sorted ascending by position. Updates in real-time.
231
+ * @property {(t: number) => string} at - Sample the ramp at `t` (clamped to `0..1`). Returns canonical hex in the gradient's width. The shader renderer exposes the same function as `<name>(float t)` in GLSL.
232
+ * @property {string} [label] - Display name shown next to the ramp in the parameter UI.
233
+ * @property {string} [description] - Tooltip / help text for the control (empty string when not configured).
234
+ * @property {string} group - Group name under which the control appears in the UI.
235
+ * @property {ParameterCategory} category - Visibility category that controls when the parameter is shown.
236
+ */
237
+
238
+ /**
239
+ * One stop of a gradient value. `color` is canonical lowercase hex in the gradient's mode (`#rrggbb`, or `#rrggbbaa` when declared with `alpha: true`).
240
+ * @typedef {Object} GradientStop
241
+ * @property {string} color - Canonical hex color of this stop.
242
+ * @property {number} position - Position along the ramp in `0..1`.
243
+ */
244
+
245
+ /**
246
+ * One artist- or host-supplied gradient stop. `color` accepts every form a color parameter accepts, normalized per the gradient's `alpha` mode.
247
+ * @typedef {Object} GradientStopInput
248
+ * @property {ColorInput} color - Any accepted color form (hex, CSS functions, RGB / HSB objects).
249
+ * @property {number} position - Position along the ramp in `0..1`.
250
+ */
251
+
212
252
  /**
213
253
  * 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`.
214
254
  * @typedef {Object} AudioAPI
@@ -358,7 +398,7 @@
358
398
  * @property {DeviceSensorState} device - Internal device sensors (motion + orientation) reported by the device running the scene.
359
399
  * @property {DeviceState[]} devices - External connected devices reporting sensor / camera / audio. Each entry has its own `id`, `name`, and per-device API surface.
360
400
  * @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); }
361
- * @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 }
401
+ * @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` / `.alpha` accessors. Pass `alpha: true` to enable transparency: the value becomes `#rrggbbaa` and alpha-bearing inputs (`rgba()`, `#rrggbbaa`, ...) are accepted. Without it, alpha-bearing inputs are rejected. 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 }, tint.alpha -> 1 const glow = viji.color('#ffffff80', { label: 'Glow', alpha: true }); // glow.value -> '#ffffff80', glow.alpha -> 0.5
362
402
  * @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' });
363
403
  * @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' });
364
404
  * @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 });
@@ -366,6 +406,7 @@
366
406
  * @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);
367
407
  * @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; }
368
408
  * @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;
409
+ * @property {(defaultValue: GradientInput, config: GradientConfig) => GradientParameter} gradient - Declares a gradient parameter. The host renders a ramp editor; `value` is the live, sorted stop list and `at(t)` samples the ramp (CSS `linear-gradient` semantics). Stop colors accept every color form; pass `alpha: true` for per-stop transparency. `default` is required (no evenly-spaced shorthand). Must be called at the top level of the scene, never inside `render()`. @example const ramp = viji.gradient( [{ color: '#ff6b6b', position: 0 }, { color: '#4ecdc4', position: 1 }], { label: 'Ramp' } ); function render(viji) { const fill = viji.ctx.createLinearGradient(0, 0, viji.width, 0); for (const stop of ramp.value) fill.addColorStop(stop.position, stop.color); viji.ctx.fillStyle = fill; viji.ctx.fillRect(0, 0, viji.width, viji.height); viji.ctx.fillStyle = ramp.at(0.5); // per-element color, same math as the fill }
369
410
  * @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);
370
411
  * @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.
371
412
  * @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.