chroma-noise 0.0.4 → 0.0.6

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.
@@ -1,9 +1,8 @@
1
1
  <script lang="ts">
2
2
  import frag from './fragment.txt?raw';
3
3
  import { onMount, onDestroy } from 'svelte';
4
+ import { hexToRgb, isBrowser, createGradientWorker, getTargetSize } from './index.js';
4
5
  import type { Warp, Grain, GradientOptions } from './index.js';
5
- import { hexToRgb, isBrowser } from './utils.js';
6
- import gradientWorker from './gradient.worker.js?url';
7
6
 
8
7
  let {
9
8
  points = [],
@@ -16,6 +15,8 @@
16
15
  seed = Math.random(),
17
16
  currentState = $bindable('loading'),
18
17
  class: c = '',
18
+ resolution = {},
19
+ blendMode = 'legacy',
19
20
  ...rest
20
21
  }: GradientOptions = $props();
21
22
 
@@ -27,11 +28,13 @@
27
28
 
28
29
  let canvas: HTMLCanvasElement | undefined = $state();
29
30
  let worker: Worker | undefined = $state();
30
- let frame: number;
31
- let running = true;
31
+ let running = $state(false);
32
32
  let lastTime = 0;
33
33
  let animTime = 0;
34
+ let frame: number | null = null;
35
+ let currentCanvasSize = $state({ width: 0, height: 0 });
34
36
 
37
+ let lastUniforms = $state<Record<string, any>>({});
35
38
 
36
39
  function updateUniforms() {
37
40
  if (!worker) return;
@@ -45,55 +48,80 @@
45
48
  posArr.set([points[i].x, points[i].y], i * 2);
46
49
  }
47
50
 
48
- worker.postMessage({
49
- type: 'updateUniforms',
50
- uniforms: {
51
- u_colors: colorsArr,
52
- u_positions: posArr,
53
- u_count: Math.min(points.length, maxPoints),
54
- u_radius: radius,
55
- u_intensity: intensity,
56
- u_warpMode: warp.mode,
57
- u_warpSize: warp.size,
58
- u_warpAmount: warp.amount,
59
- u_grainAmount: grain.amount,
60
- u_grainSize: grain.size,
61
- u_seed: seed
51
+ const newUniforms = {
52
+ u_colors: colorsArr,
53
+ u_positions: posArr,
54
+ u_count: Math.min(points.length, maxPoints),
55
+ u_radius: radius,
56
+ u_intensity: intensity,
57
+ u_warpMode: Number(warp.mode),
58
+ u_warpSize: warp.size,
59
+ u_warpAmount: warp.amount,
60
+ u_grainAmount: grain.amount,
61
+ u_grainSize: grain.size,
62
+ u_seed: seed,
63
+ u_blendMode: blendMode === 'new' ? 0 : 1
64
+ };
65
+
66
+ const changedUniforms: Record<string, any> = {};
67
+ for (const [key, value] of Object.entries(newUniforms)) {
68
+ if (JSON.stringify(lastUniforms[key]) !== JSON.stringify(value)) {
69
+ changedUniforms[key] = value;
62
70
  }
63
- });
64
- }
71
+ }
65
72
 
66
- function updateResolution() {
67
- if (!worker || !canvas) return;
68
- const dpr = Math.max(1, window.devicePixelRatio || 1);
69
- const width = Math.floor(canvas.clientWidth * dpr);
70
- const height = Math.floor(canvas.clientHeight * dpr);
71
- worker.postMessage({
72
- type: 'updateUniforms',
73
- uniforms: {
74
- u_resolution: [width, height]
75
- }
76
- });
73
+ if (Object.keys(changedUniforms).length > 0) {
74
+ worker.postMessage({
75
+ type: 'updateUniforms',
76
+ uniforms: changedUniforms
77
+ });
78
+ lastUniforms = { ...newUniforms };
79
+ }
77
80
  }
78
81
 
79
- function render(time: number) {
80
- if (worker) {
81
- if (lastTime === 0) lastTime = time;
82
- const dt = (time - lastTime) * 0.001;
83
- lastTime = time;
84
- animTime += dt * speed;
82
+ function resizeCanvasToDisplaySize() {
83
+ if (!canvas || !worker) return;
84
+
85
+ const { width, height } = getTargetSize(canvas, resolution);
85
86
 
87
+ if (currentCanvasSize.width !== width || currentCanvasSize.height !== height) {
88
+ currentCanvasSize = { width, height };
86
89
  worker.postMessage({
87
- type: 'render',
88
- time: animTime
90
+ type: 'resize',
91
+ width,
92
+ height
89
93
  });
94
+ }
95
+ }
90
96
 
91
- if (running) {
92
- currentState = 'playing';
93
- frame = requestAnimationFrame(render);
94
- } else {
95
- currentState = 'paused';
96
- }
97
+ $effect(() => {
98
+ if (worker) {
99
+ updateUniforms();
100
+ }
101
+ });
102
+
103
+ $effect(() => {
104
+ if (worker) {
105
+ resizeCanvasToDisplaySize();
106
+ }
107
+ });
108
+
109
+ function render(time: number) {
110
+ if (!worker) return;
111
+
112
+ if (lastTime === 0) lastTime = time;
113
+ const dt = (time - lastTime) * 0.001;
114
+ lastTime = time;
115
+ animTime += dt * speed;
116
+
117
+ worker.postMessage({
118
+ type: 'render',
119
+ time: animTime
120
+ });
121
+
122
+ if (running) {
123
+ currentState = 'playing';
124
+ frame = requestAnimationFrame(render);
97
125
  }
98
126
  }
99
127
 
@@ -101,54 +129,45 @@
101
129
  if (!canvas || !isBrowser()) return;
102
130
  currentState = 'loading';
103
131
 
104
- worker = new Worker(gradientWorker, {
105
- type: 'module'
106
- });
107
-
108
- worker.onmessage = (event: MessageEvent) => {
109
- const { type } = event.data;
110
- if (type === 'ready') {
111
- updateUniforms();
112
- currentState = 'playing';
113
- } else if (type === 'rendering') {
114
- currentState = 'playing';
115
- } else if (type === 'paused') {
116
- currentState = 'paused';
117
- } else if (type === 'error') {
118
- console.error('Worker error:', event.data.error);
119
- currentState = 'paused';
120
- }
121
- };
122
-
123
- const dpr = Math.max(1, window.devicePixelRatio || 1);
124
- const width = Math.floor(canvas.clientWidth * dpr);
125
- const height = Math.floor(canvas.clientHeight * dpr);
126
- canvas.width = width;
127
- canvas.height = height;
128
-
129
- try {
130
- const offscreenCanvas = canvas.transferControlToOffscreen();
131
- worker.postMessage({
132
- type: 'init',
133
- offscreenCanvas,
134
- fragShader: frag,
135
- speed
136
- }, [offscreenCanvas]);
132
+ worker = createGradientWorker();
137
133
 
138
- const resizeObserver = new ResizeObserver(() => {
139
- updateResolution();
140
- });
141
- resizeObserver.observe(canvas);
142
- frame = requestAnimationFrame(render);
143
- } catch (error) {
144
- console.error('Could not transfer canvas to worker: ', error);
134
+ worker.onmessage = (event: MessageEvent) => {
135
+ const { type } = event.data;
136
+ if (type === 'ready') {
137
+ updateUniforms();
138
+ currentState = 'playing';
139
+ frame = requestAnimationFrame(render);
140
+ } else if (type === 'error') {
141
+ console.error('Worker error:', event.data.error);
142
+ currentState = 'paused';
145
143
  }
144
+ };
145
+
146
+ const { width, height } = getTargetSize(canvas, resolution);
147
+ currentCanvasSize = { width, height };
148
+
149
+ try {
150
+ const offscreenCanvas = canvas.transferControlToOffscreen();
151
+ worker.postMessage(
152
+ {
153
+ type: 'init',
154
+ offscreenCanvas,
155
+ fragShader: frag
156
+ },
157
+ [offscreenCanvas]
158
+ );
159
+ worker.postMessage({ type: 'resize', width, height });
160
+ running = true;
161
+ } catch (error) {
162
+ console.error('Could not transfer canvas to worker: ', error);
163
+ }
146
164
  });
147
165
 
148
166
  onDestroy(() => {
149
167
  running = false;
150
168
  if (!isBrowser()) return;
151
-
169
+
170
+ if (frame) cancelAnimationFrame(frame);
152
171
  if (worker) {
153
172
  worker.postMessage({ type: 'destroy' });
154
173
  worker.terminate();
@@ -156,16 +175,25 @@
156
175
  });
157
176
 
158
177
  $effect(() => {
159
- if(worker && (points.length || radius || intensity || warp || grain || seed)) {
178
+ if (worker && (points.length || radius || intensity || warp || grain || seed)) {
160
179
  updateUniforms();
161
180
  }
162
181
  });
163
182
  </script>
164
183
 
165
- <canvas bind:this={canvas} {...rest} class="{c} {currentState}"></canvas>
184
+ <canvas bind:this={canvas} {...rest} class="{currentState} {c}"></canvas>
166
185
 
167
186
  <style>
168
- canvas { width: 100%; height: 100%; display: block; transition: opacity 1s ease-out }
169
- canvas.loading { opacity: 0; }
170
- canvas.playing { opacity: 1; }
187
+ canvas {
188
+ width: 100%;
189
+ height: 100%;
190
+ display: block;
191
+ transition: opacity 1s ease-out;
192
+ }
193
+ canvas.loading {
194
+ opacity: 0;
195
+ }
196
+ canvas.playing {
197
+ opacity: 1;
198
+ }
171
199
  </style>
package/dist/fragment.txt CHANGED
@@ -17,6 +17,7 @@ uniform int u_warpMode;
17
17
  uniform float u_warpSize;
18
18
  uniform float u_warpAmount;
19
19
  uniform float u_seed;
20
+ uniform int u_blendMode;
20
21
 
21
22
  vec3 permute(vec3 x) {
22
23
  return mod(((x * 34.0) + 1.0) * x, 289.0);
@@ -136,6 +137,10 @@ void main() {
136
137
 
137
138
  float g = grain(gl_FragCoord.xy / u_resolution.xy);
138
139
 
140
+ float radiusToUse = (u_blendMode == 0)
141
+ ? u_radius * min(u_resolution.x / u_resolution.y, 1.0)
142
+ : u_radius;
143
+
139
144
  vec3 accum = vec3(0.0);
140
145
  float totalWeight = 0.0;
141
146
  for (int i = 0; i < MAX_POINTS; ++i) {
@@ -143,7 +148,7 @@ void main() {
143
148
  vec2 diff = uv - u_positions[i];
144
149
  diff.x *= u_resolution.x / u_resolution.y;
145
150
  float d = length(diff);
146
- float w = exp(- (d * d) / (u_radius * u_radius));
151
+ float w = exp(- (d * d) / (radiusToUse * radiusToUse));
147
152
  w = pow(w, max(0.001, u_intensity));
148
153
  accum += u_colors[i] * w;
149
154
  totalWeight += w;
@@ -57,13 +57,18 @@ self.onmessage = (event) => {
57
57
  case 'updateUniforms': {
58
58
  const { uniforms: newUniforms } = event.data;
59
59
  if (newUniforms) {
60
- currentUniforms = newUniforms;
60
+ console.log('Worker received uniforms:', newUniforms);
61
+ currentUniforms = {
62
+ ...currentUniforms,
63
+ ...newUniforms
64
+ };
65
+ console.log('Current uniforms after update:', currentUniforms);
61
66
  }
62
67
  break;
63
68
  }
64
69
  case 'resize': {
65
- const { width, height, dpr } = event.data;
66
- if (gl && width && height && dpr) {
70
+ const { width, height } = event.data;
71
+ if (gl && width && height) {
67
72
  const scaledWidth = Math.floor(width);
68
73
  const scaledHeight = Math.floor(height);
69
74
  gl.canvas.width = scaledWidth;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export { default as Gradient } from './Gradient.svelte';
2
2
  export type * from './types.js';
3
3
  export * from './utils.js';
4
+ export { createGradientWorker } from './workerFactory.js';
5
+ export type { Resolution, BlendMode } from './types.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as Gradient } from './Gradient.svelte';
2
2
  export * from './utils.js';
3
+ export { createGradientWorker } from './workerFactory.js';
package/dist/types.d.ts CHANGED
@@ -30,6 +30,21 @@ export interface Grain {
30
30
  size?: number;
31
31
  }
32
32
  export type shaderState = 'loading' | 'playing' | 'paused';
33
+ /**
34
+ * Blend modes for gradient rendering
35
+ */
36
+ export type BlendMode = 'new' | 'legacy';
37
+ /** Configuration for resolution. */
38
+ export interface Resolution {
39
+ /** Canvas resolution width, default: canvas.clientWidth */
40
+ width?: number;
41
+ /** Canvas resolution height, default: canvas.clientHeight */
42
+ height?: number;
43
+ /** Canvas resolution modifier, default: 1, min: 0.01, max: 2 */
44
+ modifier?: number;
45
+ /** Determines whether to use DPR, default: false */
46
+ useDPR?: boolean;
47
+ }
33
48
  /**
34
49
  * Configuration for the gradient.
35
50
  */
@@ -54,6 +69,10 @@ export interface GradientOptions {
54
69
  currentState?: shaderState;
55
70
  /** Class applied to the canvas element **/
56
71
  class?: string;
72
+ /** Resolution settings */
73
+ resolution?: Resolution;
74
+ /** Blend mode for gradient rendering */
75
+ blendMode?: BlendMode;
57
76
  }
58
77
  export interface RenderMessage {
59
78
  type: 'init' | 'render' | 'resize' | 'updateUniforms' | 'destroy';
package/dist/utils.d.ts CHANGED
@@ -1,15 +1,17 @@
1
1
  export declare function hexToRgb(hex: string): [number, number, number];
2
- export declare const SHADER_UNIFORMS: readonly ["u_resolution", "u_time", "u_count", "u_colors", "u_positions", "u_radius", "u_intensity", "u_warpMode", "u_warpSize", "u_warpAmount", "u_grainAmount", "u_grainSize", "u_seed"];
2
+ export declare const SHADER_UNIFORMS: readonly ["u_resolution", "u_time", "u_count", "u_colors", "u_positions", "u_radius", "u_intensity", "u_warpMode", "u_warpSize", "u_warpAmount", "u_grainAmount", "u_grainSize", "u_seed", "u_blendMode"];
3
3
  export declare const VERTEX_SHADER = "attribute vec2 a_pos;void main() {gl_Position = vec4(a_pos, 0.0, 1.0);}";
4
4
  export declare const FULLSCREEN_QUAD: Float32Array<ArrayBuffer>;
5
5
  export declare function createShader(gl: WebGL2RenderingContext | WebGLRenderingContext, type: number, src: string): WebGLShader;
6
6
  export declare function createProgram(gl: WebGL2RenderingContext | WebGLRenderingContext, vsSrc: string, fsSrc: string): WebGLProgram;
7
7
  export declare function getUniform(gl: WebGL2RenderingContext | WebGLRenderingContext, program: WebGLProgram, name: string): WebGLUniformLocation;
8
8
  export declare function setupQuadBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext, program: WebGLProgram): void;
9
- export declare function getCanvasSize(canvas: HTMLCanvasElement): {
9
+ /**
10
+ * Calculate target canvas size based on resolution settings
11
+ */
12
+ export declare function getTargetSize(canvas: HTMLCanvasElement, resolution: import('./types.js').Resolution): {
10
13
  width: number;
11
14
  height: number;
12
- dpr: number;
13
15
  };
14
16
  export declare const isBrowser: () => boolean;
15
17
  /**
package/dist/utils.js CHANGED
@@ -21,7 +21,8 @@ export const SHADER_UNIFORMS = [
21
21
  'u_warpAmount',
22
22
  'u_grainAmount',
23
23
  'u_grainSize',
24
- 'u_seed'
24
+ 'u_seed',
25
+ 'u_blendMode'
25
26
  ];
26
27
  export const VERTEX_SHADER = `attribute vec2 a_pos;void main() {gl_Position = vec4(a_pos, 0.0, 1.0);}`;
27
28
  export const FULLSCREEN_QUAD = new Float32Array([-1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1]);
@@ -64,11 +65,34 @@ export function setupQuadBuffer(gl, program) {
64
65
  gl.enableVertexAttribArray(a_pos);
65
66
  gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0);
66
67
  }
67
- export function getCanvasSize(canvas) {
68
+ /**
69
+ * Calculate target canvas size based on resolution settings
70
+ */
71
+ export function getTargetSize(canvas, resolution) {
68
72
  const dpr = Math.max(1, window.devicePixelRatio || 1);
69
- const width = Math.floor(canvas.clientWidth * dpr);
70
- const height = Math.floor(canvas.clientHeight * dpr);
71
- return { width, height, dpr };
73
+ const clientWidth = canvas.clientWidth;
74
+ const clientHeight = canvas.clientHeight;
75
+ let width = clientWidth;
76
+ let height = clientHeight;
77
+ if (resolution.width !== undefined) {
78
+ width = resolution.width;
79
+ }
80
+ if (resolution.height !== undefined) {
81
+ height = resolution.height;
82
+ }
83
+ if (resolution.modifier !== undefined) {
84
+ const modifier = Math.max(0.01, Math.min(2.0, resolution.modifier));
85
+ width = width * modifier;
86
+ height = height * modifier;
87
+ }
88
+ if (resolution.useDPR !== false) {
89
+ width = width * dpr;
90
+ height = height * dpr;
91
+ }
92
+ return {
93
+ width: Math.floor(width),
94
+ height: Math.floor(height)
95
+ };
72
96
  }
73
97
  export const isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined';
74
98
  /**
@@ -86,7 +110,8 @@ export const UNIFORM_TYPES = {
86
110
  u_warpAmount: 'f32',
87
111
  u_grainAmount: 'f32',
88
112
  u_grainSize: 'f32',
89
- u_seed: 'f32'
113
+ u_seed: 'f32',
114
+ u_blendMode: 'i32'
90
115
  };
91
116
  /**
92
117
  * Set a WebGL uniform based on its type
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Worker factory that creates a gradient rendering worker as a Blob
3
+ * This approach ensures the worker works correctly
4
+ */
5
+ export declare function createGradientWorker(): Worker;
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Worker factory that creates a gradient rendering worker as a Blob
3
+ * This approach ensures the worker works correctly
4
+ */
5
+ export function createGradientWorker() {
6
+ const workerCode = `
7
+ const SHADER_UNIFORMS = [
8
+ 'u_resolution',
9
+ 'u_time',
10
+ 'u_count',
11
+ 'u_colors',
12
+ 'u_positions',
13
+ 'u_radius',
14
+ 'u_intensity',
15
+ 'u_warpMode',
16
+ 'u_warpSize',
17
+ 'u_warpAmount',
18
+ 'u_grainAmount',
19
+ 'u_grainSize',
20
+ 'u_seed'
21
+ ];
22
+
23
+ const VERTEX_SHADER = 'attribute vec2 a_pos;void main() {gl_Position = vec4(a_pos, 0.0, 1.0);}';
24
+ const FULLSCREEN_QUAD = new Float32Array([-1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1]);
25
+
26
+ const UNIFORM_TYPES = {
27
+ u_resolution: 'vec2',
28
+ u_colors: 'vec3f',
29
+ u_positions: 'vec2f',
30
+ u_count: 'i32',
31
+ u_warpMode: 'i32',
32
+ u_radius: 'f32',
33
+ u_intensity: 'f32',
34
+ u_warpSize: 'f32',
35
+ u_warpAmount: 'f32',
36
+ u_grainAmount: 'f32',
37
+ u_grainSize: 'f32',
38
+ u_seed: 'f32'
39
+ };
40
+
41
+ let gl = null;
42
+ let program = null;
43
+ let uniforms = {};
44
+ let currentUniforms = {};
45
+
46
+ function createShader(gl, type, src) {
47
+ const s = gl.createShader(type);
48
+ gl.shaderSource(s, src);
49
+ gl.compileShader(s);
50
+ if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
51
+ const error = gl.getShaderInfoLog(s);
52
+ gl.deleteShader(s);
53
+ throw new Error(\`Shader compile error: \${error}\`);
54
+ }
55
+ return s;
56
+ }
57
+
58
+ function createProgram(gl, vsSrc, fsSrc) {
59
+ const vs = createShader(gl, gl.VERTEX_SHADER, vsSrc);
60
+ const fs = createShader(gl, gl.FRAGMENT_SHADER, fsSrc);
61
+ const p = gl.createProgram();
62
+ gl.attachShader(p, vs);
63
+ gl.attachShader(p, fs);
64
+ gl.linkProgram(p);
65
+ if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
66
+ const error = gl.getProgramInfoLog(p);
67
+ gl.deleteProgram(p);
68
+ throw new Error(\`Program link error: \${error}\`);
69
+ }
70
+ return p;
71
+ }
72
+
73
+ function getUniform(gl, program, name) {
74
+ const loc = gl.getUniformLocation(program, name);
75
+ if (!loc) throw new Error(\`Uniform \${name} not found\`);
76
+ return loc;
77
+ }
78
+
79
+ function setupQuadBuffer(gl, program) {
80
+ const vbo = gl.createBuffer();
81
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
82
+ gl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_QUAD, gl.STATIC_DRAW);
83
+ const a_pos = gl.getAttribLocation(program, 'a_pos');
84
+ gl.enableVertexAttribArray(a_pos);
85
+ gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0);
86
+ }
87
+
88
+ function setUniform(gl, uniform, key, value) {
89
+ const type = UNIFORM_TYPES[key];
90
+ if (!type) return;
91
+
92
+ switch (type) {
93
+ case 'vec2':
94
+ gl.uniform2f(uniform, value[0], value[1]);
95
+ break;
96
+ case 'vec3f':
97
+ gl.uniform3fv(uniform, value);
98
+ break;
99
+ case 'vec2f':
100
+ gl.uniform2fv(uniform, value);
101
+ break;
102
+ case 'i32':
103
+ gl.uniform1i(uniform, value);
104
+ break;
105
+ case 'f32':
106
+ gl.uniform1f(uniform, value);
107
+ break;
108
+ }
109
+ }
110
+
111
+ function initWorker(offscreenCanvas, fragShader) {
112
+ try {
113
+ gl = offscreenCanvas.getContext('webgl2', { antialias: true });
114
+ if (!gl) {
115
+ throw new Error('WebGL2 not supported');
116
+ }
117
+
118
+ program = createProgram(gl, VERTEX_SHADER, fragShader);
119
+ gl.useProgram(program);
120
+
121
+ setupQuadBuffer(gl, program);
122
+
123
+ for (const name of SHADER_UNIFORMS) {
124
+ uniforms[name] = getUniform(gl, program, name);
125
+ }
126
+
127
+ self.postMessage({ type: 'ready' });
128
+ } catch (error) {
129
+ self.postMessage({ type: 'error', error: error.message });
130
+ }
131
+ }
132
+
133
+ function performRender(time) {
134
+ if (!gl || !program) {
135
+ return;
136
+ }
137
+
138
+ gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
139
+ gl.clearColor(0, 0, 0, 0);
140
+ gl.clear(gl.COLOR_BUFFER_BIT);
141
+
142
+ gl.useProgram(program);
143
+ gl.uniform1f(uniforms.u_time, time);
144
+ gl.uniform2f(uniforms.u_resolution, gl.canvas.width, gl.canvas.height);
145
+
146
+ for (const [key, value] of Object.entries(currentUniforms)) {
147
+ const uniform = uniforms[key];
148
+ if (uniform && key !== 'u_resolution') setUniform(gl, uniform, key, value);
149
+ }
150
+
151
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
152
+ }
153
+
154
+ self.onmessage = (event) => {
155
+ const { type } = event.data;
156
+
157
+ switch (type) {
158
+ case 'init': {
159
+ const { offscreenCanvas, fragShader } = event.data;
160
+ if (offscreenCanvas && fragShader) {
161
+ initWorker(offscreenCanvas, fragShader);
162
+ }
163
+ break;
164
+ }
165
+ case 'render': {
166
+ const { time } = event.data;
167
+ if (time !== undefined) {
168
+ performRender(time);
169
+ }
170
+ break;
171
+ }
172
+ case 'updateUniforms': {
173
+ const { uniforms: newUniforms } = event.data;
174
+ if (newUniforms) {
175
+ currentUniforms = { ...currentUniforms, ...newUniforms };
176
+ }
177
+ break;
178
+ }
179
+ case 'resize': {
180
+ const { width, height } = event.data;
181
+ if (gl && width && height) {
182
+ gl.canvas.width = width;
183
+ gl.canvas.height = height;
184
+ }
185
+ break;
186
+ }
187
+ case 'destroy': {
188
+ break;
189
+ }
190
+ }
191
+ };
192
+ `;
193
+ const blob = new Blob([workerCode], { type: 'application/javascript' });
194
+ const workerUrl = URL.createObjectURL(blob);
195
+ return new Worker(workerUrl);
196
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chroma-noise",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -38,6 +38,7 @@
38
38
  "@sveltejs/kit": "^2.43.2",
39
39
  "@sveltejs/package": "^2.5.4",
40
40
  "@sveltejs/vite-plugin-svelte": "^6.2.0",
41
+ "patch-package": "^8.0.1",
41
42
  "prettier": "^3.6.2",
42
43
  "prettier-plugin-svelte": "^3.4.0",
43
44
  "publint": "^0.3.13",