wgsl-play 0.0.38 → 0.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,11 +29,94 @@ import env::u;
29
29
  }
30
30
  ```
31
31
 
32
- | Uniform | Type | Description |
33
- |---------|------|-------------|
34
- | `resolution` | `vec2f` | Canvas dimensions in pixels |
32
+ When no `@uniforms` struct is declared, a default is provided with `resolution` and `time`.
33
+
34
+ ### Custom Uniforms
35
+
36
+ Declare a struct with `@uniforms` to add your own fields with UI controls:
37
+
38
+ ```wgsl
39
+ import env::u;
40
+
41
+ @uniforms struct Params {
42
+ @auto resolution: vec2f,
43
+ @auto time: f32,
44
+ @range(1.0, 20.0, 5.0, 6.0) frequency: f32,
45
+ @color(0.2, 0.5, 1.0) tint: vec3f,
46
+ @toggle(0) invert: u32,
47
+ }
48
+
49
+ @fragment fn main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
50
+ let wave = sin(pos.x * u.frequency + u.time);
51
+ var color = wave * u.tint;
52
+ if u.invert == 1u { color = 1.0 - color; }
53
+ return vec4f(color, 1.0);
54
+ }
55
+ ```
56
+
57
+ ### `@auto` -- Runtime Fields
58
+
59
+ The player fills these automatically each frame. The field name determines
60
+ which value is bound (or use `@auto(name)` when the field name differs):
61
+
62
+ | Name | Type | Description |
63
+ |------|------|-------------|
64
+ | `resolution` | `vec2f` | Canvas size in pixels |
35
65
  | `time` | `f32` | Elapsed time in seconds |
36
- | `mouse` | `vec2f` | Mouse position (normalized 0-1) |
66
+ | `delta_time` | `f32` | Delta time since last frame |
67
+ | `frame` | `u32` | Frame count |
68
+ | `mouse_pos` | `vec2f` | Pointer position in pixels |
69
+ | `mouse_delta` | `vec2f` | Pointer movement since last frame |
70
+ | `mouse_button` | `i32` | Active button: 0=none, 1=left, 2=middle, 3=right |
71
+
72
+ ### UI Annotations
73
+
74
+ These generate interactive controls in the player.
75
+
76
+ #### `@range(min, max [, step [, initial]])`
77
+
78
+ Slider for `f32` or `i32`. Step defaults to `0.01` for `f32`, `1` for `i32`.
79
+ Initial defaults to `min`.
80
+
81
+ ```wgsl
82
+ @range(1.0, 20.0) frequency: f32,
83
+ @range(1.0, 20.0, 5.0) frequency: f32, // step=5
84
+ @range(1.0, 20.0, 0.5, 5.0) frequency: f32, // step=0.5, initial=5
85
+ ```
86
+
87
+ #### `@color(r, g, b)`
88
+
89
+ Color picker for `vec3f`:
90
+
91
+ ```wgsl
92
+ @color(0.2, 0.5, 1.0) tint: vec3f,
93
+ ```
94
+
95
+ #### `@toggle([initial])`
96
+
97
+ Boolean toggle for `u32` (0 or 1). WGSL forbids `bool` in uniform buffers.
98
+
99
+ ```wgsl
100
+ @toggle invert: u32, // default=0
101
+ @toggle(1) invert: u32, // default=1
102
+ ```
103
+
104
+ ### Plain Fields
105
+
106
+ Fields without annotations are zero-initialized and settable from JavaScript
107
+ via `setUniform()`. This works before or after compilation.
108
+
109
+ ```wgsl
110
+ @uniforms struct Params {
111
+ @auto resolution: vec2f,
112
+ brightness: f32, // no annotation — set from JS
113
+ }
114
+ ```
115
+
116
+ ```javascript
117
+ const player = document.querySelector("wgsl-play");
118
+ player.setUniform("brightness", 0.8);
119
+ ```
37
120
 
38
121
  ### Inline source
39
122
 
@@ -81,6 +164,11 @@ The `?raw` suffix imports the file as a string. This keeps shaders alongside you
81
164
  - `autoplay` - Start animating on load (default: `true`). Set `autoplay="false"` to start paused
82
165
  - `transparent` - Use premultiplied alpha for transparent backgrounds (default: opaque)
83
166
  - `from` - Element ID of a source provider (e.g., wgsl-edit) to connect to
167
+ - `no-controls` - Hide playback controls (play/pause, rewind, fullscreen)
168
+ - `no-settings` - Hide the uniform controls panel
169
+ - `width` / `height` - Fixed canvas resolution in pixels, independent of display size. When set, the canvas is not resized by the CSS layout
170
+ - `pixel-ratio` - Scale factor from CSS pixels to canvas pixels (default: `devicePixelRatio`). Set `pixel-ratio="1"` for 1:1 CSS pixels (no HiDPI scaling)
171
+ - `resizable` - Show a drag handle to let users resize the element interactively
84
172
  - `fetch-libs` - Auto-fetch missing libraries from npm (default: `true`). Set `fetch-libs="false"` to disable
85
173
  - `fetch-sources` - Auto-fetch local .wesl source files via HTTP (default: `true`). Set `fetch-sources="false"` to disable
86
174
 
@@ -88,6 +176,7 @@ The `?raw` suffix imports the file as a string. This keeps shaders alongside you
88
176
  - `shader: string` - Get/set shader source (single-file convenience)
89
177
  - `conditions: Record<string, boolean>` - Get/set conditions for conditional compilation (`@if`/`@elif`/`@else`)
90
178
  - `project: WeslProject` - Get/set full project config (weslSrc, libs, conditions, constants)
179
+ - `pixelRatio: number` - Get/set canvas-to-CSS pixel ratio (default: `devicePixelRatio`)
91
180
  - `isPlaying: boolean` - Playback state (readonly)
92
181
  - `time: number` - Animation time in seconds (readonly)
93
182
  - `hasError: boolean` - Compilation error state (readonly)
@@ -97,12 +186,29 @@ The `?raw` suffix imports the file as a string. This keeps shaders alongside you
97
186
  - `play()` - Start/resume animation
98
187
  - `pause()` - Pause animation
99
188
  - `rewind()` - Reset to t=0
189
+ - `setUniform(name, value)` - Set a uniform value programmatically
100
190
  - `showError(message)` - Display error (empty string clears)
101
191
 
102
192
  ### Events
103
193
  - `compile-error` - `{ message: string }`
104
194
  - `init-error` - `{ message: string }` (WebGPU init failed)
105
195
  - `playback-change` - `{ isPlaying: boolean }`
196
+ - `uniforms-layout` - `{ detail: AnnotatedLayout }` (fired after each compile)
197
+
198
+ ## Canvas Sizing
199
+
200
+ By default the canvas resolution tracks CSS size at `devicePixelRatio`.
201
+ Use `pixel-ratio` or `width`/`height` to decouple:
202
+
203
+ ```html
204
+ <!-- 1:1 CSS pixels (blocky on HiDPI, great for pixel art) -->
205
+ <wgsl-play pixel-ratio="1" style="width:512px; height:512px"></wgsl-play>
206
+
207
+ <!-- Fixed 64x64 canvas, stretched to whatever CSS size -->
208
+ <wgsl-play width="64" height="64" style="width:512px; height:512px"></wgsl-play>
209
+ ```
210
+
211
+ For crisp upscaling of low-res canvases, add `image-rendering: pixelated`:
106
212
 
107
213
  ## Styling
108
214
 
@@ -35,9 +35,11 @@ declare class WgslPlay extends HTMLElement {
35
35
  private canvas;
36
36
  private errorOverlay;
37
37
  private controls;
38
+ private settings;
38
39
  private resizeObserver;
39
40
  private stopRenderLoop?;
40
41
  private renderState?;
42
+ private pendingUniforms;
41
43
  private playback;
42
44
  private _weslSrc;
43
45
  private _rootModuleName;
@@ -53,6 +55,8 @@ declare class WgslPlay extends HTMLElement {
53
55
  private _theme;
54
56
  private _mediaQuery;
55
57
  private _onFullscreenChange;
58
+ private _pointerCleanup?;
59
+ private _resizeCleanup?;
56
60
  /** Get config overrides from element attributes. */
57
61
  private getConfigOverrides;
58
62
  constructor();
@@ -77,6 +81,9 @@ declare class WgslPlay extends HTMLElement {
77
81
  /** Whether autoplay is enabled (default: true). Set autoplay="false" to start paused. */
78
82
  get autoplay(): boolean;
79
83
  set autoplay(value: boolean | string);
84
+ /** Scale factor from CSS pixels to canvas pixels (default: devicePixelRatio). */
85
+ get pixelRatio(): number;
86
+ set pixelRatio(value: number);
80
87
  /** Whether the shader is currently playing. */
81
88
  get isPlaying(): boolean;
82
89
  /** Current animation time in seconds. */
@@ -96,8 +103,19 @@ declare class WgslPlay extends HTMLElement {
96
103
  rewind(): void;
97
104
  /** Display error message in overlay. Pass empty string to clear. */
98
105
  showError(message: string): void;
106
+ /** Set a uniform value by name. Works before or after compilation. */
107
+ setUniform(name: string, value: number | number[]): void;
108
+ private flushPendingUniforms;
109
+ /** Current uniform control values (readable). */
110
+ get uniforms(): Record<string, number | number[]>;
99
111
  /** Toggle fullscreen on this element. */
100
112
  toggleFullscreen(): void;
113
+ /** Track pointer events on canvas for mouse_pos @auto fields. */
114
+ private setupMouseTracking;
115
+ /** Drag-to-resize via a custom handle (works on touch + mouse). */
116
+ private setupResizeHandle;
117
+ /** Recompute canvas resolution from attributes or CSS size. */
118
+ private updateCanvasSize;
101
119
  private updateTheme;
102
120
  /** Set up WebGPU and load initial shader. Returns true if successful. */
103
121
  private initialize;
@@ -112,6 +130,10 @@ declare class WgslPlay extends HTMLElement {
112
130
  private requestBuild;
113
131
  /** Run builds until no longer dirty. Only one instance runs at a time. */
114
132
  private runBuild;
133
+ /** Fetch deps if needed and create the render pipeline. */
134
+ private buildPipeline;
135
+ /** Apply a successful build: flush uniforms, update controls, render. */
136
+ private applyBuild;
115
137
  private handleCompileError;
116
138
  /** Extract source locations from a WESL parse error or GPU compilation error. */
117
139
  private extractLocations;