@lovo/matter 0.1.0 → 0.3.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.
- package/CHANGELOG.md +68 -0
- package/README.md +2 -2
- package/dist/index.cjs +35 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -20
- package/dist/index.d.ts +69 -20
- package/dist/index.js +25 -52
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
- package/dist/.tsbuildinfo +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { WebGPURenderer, Node } from 'three/webgpu';
|
|
2
2
|
import { Color } from 'three';
|
|
3
3
|
import { ShaderNodeObject } from 'three/tsl';
|
|
4
|
-
export { cos, dot, length, max, min, mix, mod, normalize, sin, smoothstep, uniform, uv, vec2, vec3, vec4 } from 'three/tsl';
|
|
5
4
|
|
|
6
5
|
type MatterBackend = 'webgpu' | 'webgl2';
|
|
7
6
|
interface CreateRendererOptions {
|
|
@@ -150,6 +149,17 @@ declare class CursorInput {
|
|
|
150
149
|
dispose(): void;
|
|
151
150
|
}
|
|
152
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Canonical TSL-node *input* shape used throughout `@lovo/matter`.
|
|
154
|
+
*
|
|
155
|
+
* Stays as the broad `Node | ShaderNodeObject<Node>` union so callers can
|
|
156
|
+
* pass uniform-typed nodes (e.g. `ShaderNodeObject<UniformNode<Vector2>>`)
|
|
157
|
+
* without casting at the call site — those are subtypes of `Node` but NOT
|
|
158
|
+
* subtypes of `ShaderNodeObject<Node>` due to invariant generic parameters.
|
|
159
|
+
*
|
|
160
|
+
* Wrappers should return the narrower `ShaderNodeObject<Node>` so the
|
|
161
|
+
* **output** is always chainable without casts.
|
|
162
|
+
*/
|
|
153
163
|
type TSLNode = Node | ShaderNodeObject<Node>;
|
|
154
164
|
interface ColorRampStop {
|
|
155
165
|
/** Color expressed as a TSL node (typically `vec3(r,g,b)`). */
|
|
@@ -163,7 +173,7 @@ interface ColorRampStop {
|
|
|
163
173
|
*
|
|
164
174
|
* Falls back to the first/last stop's color outside the bracketing positions.
|
|
165
175
|
*/
|
|
166
|
-
declare function colorRamp(t: TSLNode, stops: ColorRampStop[]):
|
|
176
|
+
declare function colorRamp(t: TSLNode, stops: ColorRampStop[]): ShaderNodeObject<Node>;
|
|
167
177
|
|
|
168
178
|
/**
|
|
169
179
|
* 2D simplex noise sampled at a point. Returns a scalar TSL node in
|
|
@@ -174,8 +184,11 @@ declare function colorRamp(t: TSLNode, stops: ColorRampStop[]): TSLNode;
|
|
|
174
184
|
* Built on top of three's `mx_noise_float`; we wrap it so consumers have a
|
|
175
185
|
* stable import path through `@lovo/matter` and we can swap the
|
|
176
186
|
* implementation if a different noise primitive proves better in practice.
|
|
187
|
+
*
|
|
188
|
+
* Returns `ShaderNodeObject<Node>` (chainable) rather than the broader
|
|
189
|
+
* `TSLNode` union, so callers can `.add(...)`/`.mul(...)` without casting.
|
|
177
190
|
*/
|
|
178
|
-
declare function noise(p: TSLNode):
|
|
191
|
+
declare function noise(p: TSLNode): ShaderNodeObject<Node>;
|
|
179
192
|
|
|
180
193
|
interface FBMOptions {
|
|
181
194
|
/** Number of octaves to sum. JS-side number — fixed at TSL build time, not a uniform. Default: 4. */
|
|
@@ -188,17 +201,27 @@ interface FBMOptions {
|
|
|
188
201
|
/**
|
|
189
202
|
* Fractal Brownian Motion — sum of N octaves of 2D simplex noise.
|
|
190
203
|
*
|
|
204
|
+
* Each octave samples noise at a higher frequency (× `lacunarity`) and lower
|
|
205
|
+
* amplitude (× `gain`) than the previous one, AND at a translated coordinate
|
|
206
|
+
* so the octaves sample uncorrelated regions of noise space. Without the
|
|
207
|
+
* per-octave translation, octaves at related frequencies tend to pile up
|
|
208
|
+
* peaks and troughs at the same input coordinates, producing visibly muddy
|
|
209
|
+
* "spotty" output. With it, the octaves look like independent noise patterns
|
|
210
|
+
* layered together — Inigo Quilez's classic FBM technique.
|
|
211
|
+
*
|
|
191
212
|
* `octaves`, `lacunarity`, and `gain` are JavaScript numbers (NOT TSL
|
|
192
213
|
* uniforms) because the loop must be unrolled at TSL-build time — TSL has
|
|
193
214
|
* no dynamic-length loop primitive that maps cleanly to all backends.
|
|
194
215
|
* Animatable parameters that *do* survive on the GPU are the input UV
|
|
195
216
|
* (which the caller can scale/translate per frame) and `time`.
|
|
196
217
|
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
218
|
+
* Returns `ShaderNodeObject<Node>` (chainable) for cast-free call sites.
|
|
219
|
+
*
|
|
220
|
+
* @param p — Vec2 or Vec3 TSL node (UV-space position).
|
|
221
|
+
* @returns scalar TSL node, normalized to roughly [-1..1] regardless of
|
|
222
|
+
* octave count thanks to the amplitude-sum division at the end.
|
|
200
223
|
*/
|
|
201
|
-
declare function fbm(p: TSLNode, opts?: FBMOptions):
|
|
224
|
+
declare function fbm(p: TSLNode, opts?: FBMOptions): ShaderNodeObject<Node>;
|
|
202
225
|
|
|
203
226
|
/**
|
|
204
227
|
* 2D voronoi (Worley) noise — distance to the nearest jittered cell point,
|
|
@@ -209,9 +232,11 @@ declare function fbm(p: TSLNode, opts?: FBMOptions): TSLNode;
|
|
|
209
232
|
* a multi-color cellular pattern; threshold via `step`/`smoothstep` for
|
|
210
233
|
* hard cell shapes.
|
|
211
234
|
*
|
|
235
|
+
* Returns `ShaderNodeObject<Node>` (chainable) for cast-free call sites.
|
|
236
|
+
*
|
|
212
237
|
* @param p — Vec2 TSL node, typically `uv() * scale`.
|
|
213
238
|
*/
|
|
214
|
-
declare function voronoi(p: TSLNode):
|
|
239
|
+
declare function voronoi(p: TSLNode): ShaderNodeObject<Node>;
|
|
215
240
|
|
|
216
241
|
/**
|
|
217
242
|
* Quantize a scalar TSL node to `steps` discrete levels.
|
|
@@ -221,7 +246,7 @@ declare function voronoi(p: TSLNode): TSLNode;
|
|
|
221
246
|
* `steps` is a JS-side number (loop-equivalent at TSL build time, baked in).
|
|
222
247
|
* If you need an animatable step count, rebuild the TSL fragment.
|
|
223
248
|
*/
|
|
224
|
-
declare function quantize(t:
|
|
249
|
+
declare function quantize(t: ShaderNodeObject<Node>, steps: number): ShaderNodeObject<Node>;
|
|
225
250
|
|
|
226
251
|
/**
|
|
227
252
|
* Signed distance field for a circle centered at the origin.
|
|
@@ -234,7 +259,7 @@ declare function quantize(t: TSLNode, steps: number): TSLNode;
|
|
|
234
259
|
* @param p — Vec2 TSL node (typically a UV-space offset from the center).
|
|
235
260
|
* @param radius — JS-side scalar OR a scalar TSL node.
|
|
236
261
|
*/
|
|
237
|
-
declare function sdfCircle(p: TSLNode, radius: TSLNode | number):
|
|
262
|
+
declare function sdfCircle(p: TSLNode, radius: TSLNode | number): ShaderNodeObject<Node>;
|
|
238
263
|
|
|
239
264
|
/**
|
|
240
265
|
* Naive vector addition: returns `p + by`.
|
|
@@ -252,7 +277,7 @@ declare function sdfCircle(p: TSLNode, radius: TSLNode | number): TSLNode;
|
|
|
252
277
|
* @param p — Vec2 TSL node (the position being displaced).
|
|
253
278
|
* @param by — Vec2 TSL node (the displacement vector).
|
|
254
279
|
*/
|
|
255
|
-
declare function displace(p: TSLNode, by: TSLNode):
|
|
280
|
+
declare function displace(p: TSLNode, by: TSLNode): ShaderNodeObject<Node>;
|
|
256
281
|
|
|
257
282
|
interface CursorRippleOptions {
|
|
258
283
|
/** Decay radius (UV space). Beyond this, the ripple is ~0. Default: 0.4. */
|
|
@@ -279,18 +304,42 @@ interface CursorRippleOptions {
|
|
|
279
304
|
* @param p — Vec2 TSL node (typically `uv()`).
|
|
280
305
|
* @param center — Vec2 TSL node (cursor uniform, in UV space).
|
|
281
306
|
*/
|
|
282
|
-
declare function cursorRipple(p: TSLNode, center: TSLNode, opts?: CursorRippleOptions):
|
|
307
|
+
declare function cursorRipple(p: TSLNode, center: TSLNode, opts?: CursorRippleOptions): ShaderNodeObject<Node>;
|
|
308
|
+
|
|
309
|
+
declare const time: ShaderNodeObject<Node>;
|
|
283
310
|
|
|
284
311
|
/**
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
312
|
+
* Hash-based film grain — chaotic, uncorrelated per-pixel noise sampled
|
|
313
|
+
* from `uvNode`. The output is *centered* around zero so it acts as a
|
|
314
|
+
* brightness-preserving texture overlay (half the pixels brighten by up
|
|
315
|
+
* to `intensity`, half darken, mean unchanged). ADD the result to a color.
|
|
316
|
+
*
|
|
317
|
+
* filmGrain(uv, k) → static grain
|
|
318
|
+
* filmGrain(uv, k, time) → twinkling grain. Pass a quantized time node
|
|
319
|
+
* (e.g. `time.mul(speed).mul(60).floor()`) so
|
|
320
|
+
* the grain re-randomizes at a controllable
|
|
321
|
+
* "shutter rate" instead of every frame.
|
|
322
|
+
*
|
|
323
|
+
* Recipe:
|
|
289
324
|
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
325
|
+
* base = vec2(uv·c1, uv·c2) + timeOffset
|
|
326
|
+
* hash = fract(sin(base) * 43758.5453)
|
|
327
|
+
* out = (length(hash) - 0.765) * intensity
|
|
328
|
+
*
|
|
329
|
+
* `c1 = (2127.1, 81.17)` and `c2 = (1269.5, 283.37)` are arbitrary
|
|
330
|
+
* near-prime constants that produce visually-uncorrelated noise. `0.765`
|
|
331
|
+
* is the empirical mean of `length(vec2(u, v))` for uniform u, v ∈ [0, 1),
|
|
332
|
+
* computed once so we don't have to subtract it at runtime per pixel.
|
|
333
|
+
*
|
|
334
|
+
* For a film-stock look (darkens as grain rises — silver-emulsion
|
|
335
|
+
* physics) subtract the result from the color instead of adding.
|
|
336
|
+
*
|
|
337
|
+
* @param uvNode vec2 TSL node, typically `uv()`.
|
|
338
|
+
* @param intensity number or TSL node in [0, 1]; scales the grain.
|
|
339
|
+
* @param timeOffset optional number or TSL node added to each sample
|
|
340
|
+
* before hashing. `0` (default) → static grain.
|
|
292
341
|
*/
|
|
293
|
-
declare
|
|
342
|
+
declare function filmGrain(uvNode: ShaderNodeObject<Node>, intensity: ShaderNodeObject<Node> | number, timeOffset?: ShaderNodeObject<Node> | number): ShaderNodeObject<Node>;
|
|
294
343
|
|
|
295
344
|
type ReducedMotionPolicy = 'auto' | 'off' | 'slow' | 'paused';
|
|
296
345
|
/**
|
|
@@ -358,4 +407,4 @@ interface IntersectionWatcher {
|
|
|
358
407
|
*/
|
|
359
408
|
declare function createIntersectionWatcher(canvas: HTMLCanvasElement): IntersectionWatcher;
|
|
360
409
|
|
|
361
|
-
export { type ColorRampStop, type CreateRendererOptions, CursorInput, type CursorInputOptions, type CursorRippleOptions, type FBMOptions, type IntersectionWatcher, type MatterBackend, type MatterRenderer, MatterScheduler, type ReducedMotionPolicy, type ReducedMotionWatcher, type SchedulerClient, type SchedulerTick, type TSLNode, type Vec2, type VisibilityWatcher, colorRamp, createIntersectionWatcher, createReducedMotionWatcher, createRenderer, createVisibilityWatcher, cursorRipple, displace, fbm, getReducedMotionPolicy, getReducedMotionTimeScale, noise, quantize, sdfCircle, setReducedMotionPolicy, time, voronoi };
|
|
410
|
+
export { type ColorRampStop, type CreateRendererOptions, CursorInput, type CursorInputOptions, type CursorRippleOptions, type FBMOptions, type IntersectionWatcher, type MatterBackend, type MatterRenderer, MatterScheduler, type ReducedMotionPolicy, type ReducedMotionWatcher, type SchedulerClient, type SchedulerTick, type TSLNode, type Vec2, type VisibilityWatcher, colorRamp, createIntersectionWatcher, createReducedMotionWatcher, createRenderer, createVisibilityWatcher, cursorRipple, displace, fbm, filmGrain, getReducedMotionPolicy, getReducedMotionTimeScale, noise, quantize, sdfCircle, setReducedMotionPolicy, time, voronoi };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { WebGPURenderer, Node } from 'three/webgpu';
|
|
2
2
|
import { Color } from 'three';
|
|
3
3
|
import { ShaderNodeObject } from 'three/tsl';
|
|
4
|
-
export { cos, dot, length, max, min, mix, mod, normalize, sin, smoothstep, uniform, uv, vec2, vec3, vec4 } from 'three/tsl';
|
|
5
4
|
|
|
6
5
|
type MatterBackend = 'webgpu' | 'webgl2';
|
|
7
6
|
interface CreateRendererOptions {
|
|
@@ -150,6 +149,17 @@ declare class CursorInput {
|
|
|
150
149
|
dispose(): void;
|
|
151
150
|
}
|
|
152
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Canonical TSL-node *input* shape used throughout `@lovo/matter`.
|
|
154
|
+
*
|
|
155
|
+
* Stays as the broad `Node | ShaderNodeObject<Node>` union so callers can
|
|
156
|
+
* pass uniform-typed nodes (e.g. `ShaderNodeObject<UniformNode<Vector2>>`)
|
|
157
|
+
* without casting at the call site — those are subtypes of `Node` but NOT
|
|
158
|
+
* subtypes of `ShaderNodeObject<Node>` due to invariant generic parameters.
|
|
159
|
+
*
|
|
160
|
+
* Wrappers should return the narrower `ShaderNodeObject<Node>` so the
|
|
161
|
+
* **output** is always chainable without casts.
|
|
162
|
+
*/
|
|
153
163
|
type TSLNode = Node | ShaderNodeObject<Node>;
|
|
154
164
|
interface ColorRampStop {
|
|
155
165
|
/** Color expressed as a TSL node (typically `vec3(r,g,b)`). */
|
|
@@ -163,7 +173,7 @@ interface ColorRampStop {
|
|
|
163
173
|
*
|
|
164
174
|
* Falls back to the first/last stop's color outside the bracketing positions.
|
|
165
175
|
*/
|
|
166
|
-
declare function colorRamp(t: TSLNode, stops: ColorRampStop[]):
|
|
176
|
+
declare function colorRamp(t: TSLNode, stops: ColorRampStop[]): ShaderNodeObject<Node>;
|
|
167
177
|
|
|
168
178
|
/**
|
|
169
179
|
* 2D simplex noise sampled at a point. Returns a scalar TSL node in
|
|
@@ -174,8 +184,11 @@ declare function colorRamp(t: TSLNode, stops: ColorRampStop[]): TSLNode;
|
|
|
174
184
|
* Built on top of three's `mx_noise_float`; we wrap it so consumers have a
|
|
175
185
|
* stable import path through `@lovo/matter` and we can swap the
|
|
176
186
|
* implementation if a different noise primitive proves better in practice.
|
|
187
|
+
*
|
|
188
|
+
* Returns `ShaderNodeObject<Node>` (chainable) rather than the broader
|
|
189
|
+
* `TSLNode` union, so callers can `.add(...)`/`.mul(...)` without casting.
|
|
177
190
|
*/
|
|
178
|
-
declare function noise(p: TSLNode):
|
|
191
|
+
declare function noise(p: TSLNode): ShaderNodeObject<Node>;
|
|
179
192
|
|
|
180
193
|
interface FBMOptions {
|
|
181
194
|
/** Number of octaves to sum. JS-side number — fixed at TSL build time, not a uniform. Default: 4. */
|
|
@@ -188,17 +201,27 @@ interface FBMOptions {
|
|
|
188
201
|
/**
|
|
189
202
|
* Fractal Brownian Motion — sum of N octaves of 2D simplex noise.
|
|
190
203
|
*
|
|
204
|
+
* Each octave samples noise at a higher frequency (× `lacunarity`) and lower
|
|
205
|
+
* amplitude (× `gain`) than the previous one, AND at a translated coordinate
|
|
206
|
+
* so the octaves sample uncorrelated regions of noise space. Without the
|
|
207
|
+
* per-octave translation, octaves at related frequencies tend to pile up
|
|
208
|
+
* peaks and troughs at the same input coordinates, producing visibly muddy
|
|
209
|
+
* "spotty" output. With it, the octaves look like independent noise patterns
|
|
210
|
+
* layered together — Inigo Quilez's classic FBM technique.
|
|
211
|
+
*
|
|
191
212
|
* `octaves`, `lacunarity`, and `gain` are JavaScript numbers (NOT TSL
|
|
192
213
|
* uniforms) because the loop must be unrolled at TSL-build time — TSL has
|
|
193
214
|
* no dynamic-length loop primitive that maps cleanly to all backends.
|
|
194
215
|
* Animatable parameters that *do* survive on the GPU are the input UV
|
|
195
216
|
* (which the caller can scale/translate per frame) and `time`.
|
|
196
217
|
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
218
|
+
* Returns `ShaderNodeObject<Node>` (chainable) for cast-free call sites.
|
|
219
|
+
*
|
|
220
|
+
* @param p — Vec2 or Vec3 TSL node (UV-space position).
|
|
221
|
+
* @returns scalar TSL node, normalized to roughly [-1..1] regardless of
|
|
222
|
+
* octave count thanks to the amplitude-sum division at the end.
|
|
200
223
|
*/
|
|
201
|
-
declare function fbm(p: TSLNode, opts?: FBMOptions):
|
|
224
|
+
declare function fbm(p: TSLNode, opts?: FBMOptions): ShaderNodeObject<Node>;
|
|
202
225
|
|
|
203
226
|
/**
|
|
204
227
|
* 2D voronoi (Worley) noise — distance to the nearest jittered cell point,
|
|
@@ -209,9 +232,11 @@ declare function fbm(p: TSLNode, opts?: FBMOptions): TSLNode;
|
|
|
209
232
|
* a multi-color cellular pattern; threshold via `step`/`smoothstep` for
|
|
210
233
|
* hard cell shapes.
|
|
211
234
|
*
|
|
235
|
+
* Returns `ShaderNodeObject<Node>` (chainable) for cast-free call sites.
|
|
236
|
+
*
|
|
212
237
|
* @param p — Vec2 TSL node, typically `uv() * scale`.
|
|
213
238
|
*/
|
|
214
|
-
declare function voronoi(p: TSLNode):
|
|
239
|
+
declare function voronoi(p: TSLNode): ShaderNodeObject<Node>;
|
|
215
240
|
|
|
216
241
|
/**
|
|
217
242
|
* Quantize a scalar TSL node to `steps` discrete levels.
|
|
@@ -221,7 +246,7 @@ declare function voronoi(p: TSLNode): TSLNode;
|
|
|
221
246
|
* `steps` is a JS-side number (loop-equivalent at TSL build time, baked in).
|
|
222
247
|
* If you need an animatable step count, rebuild the TSL fragment.
|
|
223
248
|
*/
|
|
224
|
-
declare function quantize(t:
|
|
249
|
+
declare function quantize(t: ShaderNodeObject<Node>, steps: number): ShaderNodeObject<Node>;
|
|
225
250
|
|
|
226
251
|
/**
|
|
227
252
|
* Signed distance field for a circle centered at the origin.
|
|
@@ -234,7 +259,7 @@ declare function quantize(t: TSLNode, steps: number): TSLNode;
|
|
|
234
259
|
* @param p — Vec2 TSL node (typically a UV-space offset from the center).
|
|
235
260
|
* @param radius — JS-side scalar OR a scalar TSL node.
|
|
236
261
|
*/
|
|
237
|
-
declare function sdfCircle(p: TSLNode, radius: TSLNode | number):
|
|
262
|
+
declare function sdfCircle(p: TSLNode, radius: TSLNode | number): ShaderNodeObject<Node>;
|
|
238
263
|
|
|
239
264
|
/**
|
|
240
265
|
* Naive vector addition: returns `p + by`.
|
|
@@ -252,7 +277,7 @@ declare function sdfCircle(p: TSLNode, radius: TSLNode | number): TSLNode;
|
|
|
252
277
|
* @param p — Vec2 TSL node (the position being displaced).
|
|
253
278
|
* @param by — Vec2 TSL node (the displacement vector).
|
|
254
279
|
*/
|
|
255
|
-
declare function displace(p: TSLNode, by: TSLNode):
|
|
280
|
+
declare function displace(p: TSLNode, by: TSLNode): ShaderNodeObject<Node>;
|
|
256
281
|
|
|
257
282
|
interface CursorRippleOptions {
|
|
258
283
|
/** Decay radius (UV space). Beyond this, the ripple is ~0. Default: 0.4. */
|
|
@@ -279,18 +304,42 @@ interface CursorRippleOptions {
|
|
|
279
304
|
* @param p — Vec2 TSL node (typically `uv()`).
|
|
280
305
|
* @param center — Vec2 TSL node (cursor uniform, in UV space).
|
|
281
306
|
*/
|
|
282
|
-
declare function cursorRipple(p: TSLNode, center: TSLNode, opts?: CursorRippleOptions):
|
|
307
|
+
declare function cursorRipple(p: TSLNode, center: TSLNode, opts?: CursorRippleOptions): ShaderNodeObject<Node>;
|
|
308
|
+
|
|
309
|
+
declare const time: ShaderNodeObject<Node>;
|
|
283
310
|
|
|
284
311
|
/**
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
312
|
+
* Hash-based film grain — chaotic, uncorrelated per-pixel noise sampled
|
|
313
|
+
* from `uvNode`. The output is *centered* around zero so it acts as a
|
|
314
|
+
* brightness-preserving texture overlay (half the pixels brighten by up
|
|
315
|
+
* to `intensity`, half darken, mean unchanged). ADD the result to a color.
|
|
316
|
+
*
|
|
317
|
+
* filmGrain(uv, k) → static grain
|
|
318
|
+
* filmGrain(uv, k, time) → twinkling grain. Pass a quantized time node
|
|
319
|
+
* (e.g. `time.mul(speed).mul(60).floor()`) so
|
|
320
|
+
* the grain re-randomizes at a controllable
|
|
321
|
+
* "shutter rate" instead of every frame.
|
|
322
|
+
*
|
|
323
|
+
* Recipe:
|
|
289
324
|
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
325
|
+
* base = vec2(uv·c1, uv·c2) + timeOffset
|
|
326
|
+
* hash = fract(sin(base) * 43758.5453)
|
|
327
|
+
* out = (length(hash) - 0.765) * intensity
|
|
328
|
+
*
|
|
329
|
+
* `c1 = (2127.1, 81.17)` and `c2 = (1269.5, 283.37)` are arbitrary
|
|
330
|
+
* near-prime constants that produce visually-uncorrelated noise. `0.765`
|
|
331
|
+
* is the empirical mean of `length(vec2(u, v))` for uniform u, v ∈ [0, 1),
|
|
332
|
+
* computed once so we don't have to subtract it at runtime per pixel.
|
|
333
|
+
*
|
|
334
|
+
* For a film-stock look (darkens as grain rises — silver-emulsion
|
|
335
|
+
* physics) subtract the result from the color instead of adding.
|
|
336
|
+
*
|
|
337
|
+
* @param uvNode vec2 TSL node, typically `uv()`.
|
|
338
|
+
* @param intensity number or TSL node in [0, 1]; scales the grain.
|
|
339
|
+
* @param timeOffset optional number or TSL node added to each sample
|
|
340
|
+
* before hashing. `0` (default) → static grain.
|
|
292
341
|
*/
|
|
293
|
-
declare
|
|
342
|
+
declare function filmGrain(uvNode: ShaderNodeObject<Node>, intensity: ShaderNodeObject<Node> | number, timeOffset?: ShaderNodeObject<Node> | number): ShaderNodeObject<Node>;
|
|
294
343
|
|
|
295
344
|
type ReducedMotionPolicy = 'auto' | 'off' | 'slow' | 'paused';
|
|
296
345
|
/**
|
|
@@ -358,4 +407,4 @@ interface IntersectionWatcher {
|
|
|
358
407
|
*/
|
|
359
408
|
declare function createIntersectionWatcher(canvas: HTMLCanvasElement): IntersectionWatcher;
|
|
360
409
|
|
|
361
|
-
export { type ColorRampStop, type CreateRendererOptions, CursorInput, type CursorInputOptions, type CursorRippleOptions, type FBMOptions, type IntersectionWatcher, type MatterBackend, type MatterRenderer, MatterScheduler, type ReducedMotionPolicy, type ReducedMotionWatcher, type SchedulerClient, type SchedulerTick, type TSLNode, type Vec2, type VisibilityWatcher, colorRamp, createIntersectionWatcher, createReducedMotionWatcher, createRenderer, createVisibilityWatcher, cursorRipple, displace, fbm, getReducedMotionPolicy, getReducedMotionTimeScale, noise, quantize, sdfCircle, setReducedMotionPolicy, time, voronoi };
|
|
410
|
+
export { type ColorRampStop, type CreateRendererOptions, CursorInput, type CursorInputOptions, type CursorRippleOptions, type FBMOptions, type IntersectionWatcher, type MatterBackend, type MatterRenderer, MatterScheduler, type ReducedMotionPolicy, type ReducedMotionWatcher, type SchedulerClient, type SchedulerTick, type TSLNode, type Vec2, type VisibilityWatcher, colorRamp, createIntersectionWatcher, createReducedMotionWatcher, createRenderer, createVisibilityWatcher, cursorRipple, displace, fbm, filmGrain, getReducedMotionPolicy, getReducedMotionTimeScale, noise, quantize, sdfCircle, setReducedMotionPolicy, time, voronoi };
|
package/dist/index.js
CHANGED
|
@@ -208,6 +208,7 @@ var lerp = (a, b, t) => a + (b - a) * t;
|
|
|
208
208
|
|
|
209
209
|
// src/primitives/colorRamp.ts
|
|
210
210
|
import { mix, vec3 } from "three/tsl";
|
|
211
|
+
import { clamp, div, sub } from "three/tsl";
|
|
211
212
|
function colorRamp(t, stops) {
|
|
212
213
|
if (stops.length === 0) return vec3(0, 0, 0);
|
|
213
214
|
if (stops.length === 1) return stops[0].color;
|
|
@@ -217,8 +218,7 @@ function colorRamp(t, stops) {
|
|
|
217
218
|
const next = stops[i];
|
|
218
219
|
const span = next.position - prev.position;
|
|
219
220
|
if (span <= 0) continue;
|
|
220
|
-
const
|
|
221
|
-
const localT = tNode.sub(prev.position).div(span).clamp(0, 1);
|
|
221
|
+
const localT = clamp(div(sub(t, prev.position), span), 0, 1);
|
|
222
222
|
result = mix(result, next.color, localT);
|
|
223
223
|
}
|
|
224
224
|
return result;
|
|
@@ -231,6 +231,7 @@ function noise(p) {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
// src/primitives/fbm.ts
|
|
234
|
+
import { add, mul } from "three/tsl";
|
|
234
235
|
function fbm(p, opts = {}) {
|
|
235
236
|
const octaves = opts.octaves ?? 4;
|
|
236
237
|
const lacunarity = opts.lacunarity ?? 2;
|
|
@@ -243,7 +244,7 @@ function fbm(p, opts = {}) {
|
|
|
243
244
|
freq *= lacunarity;
|
|
244
245
|
amp *= gain;
|
|
245
246
|
total += amp;
|
|
246
|
-
const pAtFreq =
|
|
247
|
+
const pAtFreq = add(mul(p, freq), i * 100);
|
|
247
248
|
const layer = noise(pAtFreq).mul(amp);
|
|
248
249
|
sum = sum.add(layer);
|
|
249
250
|
}
|
|
@@ -268,39 +269,19 @@ function quantize(t, steps) {
|
|
|
268
269
|
// src/primitives/sdfCircle.ts
|
|
269
270
|
import { length } from "three/tsl";
|
|
270
271
|
function sdfCircle(p, radius) {
|
|
271
|
-
|
|
272
|
-
if (typeof radius === "number") {
|
|
273
|
-
return lp.sub(radius);
|
|
274
|
-
}
|
|
275
|
-
return lp.sub(radius);
|
|
272
|
+
return length(p).sub(radius);
|
|
276
273
|
}
|
|
277
274
|
|
|
278
275
|
// src/primitives/displace.ts
|
|
276
|
+
import { add as add2 } from "three/tsl";
|
|
279
277
|
function displace(p, by) {
|
|
280
|
-
return p
|
|
278
|
+
return add2(p, by);
|
|
281
279
|
}
|
|
282
280
|
|
|
283
281
|
// src/primitives/cursorRipple.ts
|
|
284
|
-
import { sin
|
|
282
|
+
import { sin, length as length2, smoothstep, sub as sub2 } from "three/tsl";
|
|
285
283
|
|
|
286
|
-
// src/primitives/
|
|
287
|
-
import {
|
|
288
|
-
uniform as uniform2,
|
|
289
|
-
vec2,
|
|
290
|
-
vec3 as vec32,
|
|
291
|
-
vec4,
|
|
292
|
-
mix as mix2,
|
|
293
|
-
smoothstep,
|
|
294
|
-
mod,
|
|
295
|
-
sin,
|
|
296
|
-
cos,
|
|
297
|
-
length as length2,
|
|
298
|
-
dot,
|
|
299
|
-
normalize,
|
|
300
|
-
uv,
|
|
301
|
-
max,
|
|
302
|
-
min
|
|
303
|
-
} from "three/tsl";
|
|
284
|
+
// src/primitives/time.ts
|
|
304
285
|
import { time as _builtinTime } from "three/tsl";
|
|
305
286
|
|
|
306
287
|
// src/runtime/reducedMotion.ts
|
|
@@ -390,10 +371,8 @@ function getReducedMotionTimeScale() {
|
|
|
390
371
|
return globalScaleUniform;
|
|
391
372
|
}
|
|
392
373
|
|
|
393
|
-
// src/primitives/
|
|
394
|
-
var time = _builtinTime.mul(
|
|
395
|
-
getReducedMotionTimeScale()
|
|
396
|
-
);
|
|
374
|
+
// src/primitives/time.ts
|
|
375
|
+
var time = _builtinTime.mul(getReducedMotionTimeScale());
|
|
397
376
|
|
|
398
377
|
// src/primitives/cursorRipple.ts
|
|
399
378
|
function cursorRipple(p, center, opts = {}) {
|
|
@@ -401,14 +380,22 @@ function cursorRipple(p, center, opts = {}) {
|
|
|
401
380
|
const frequency = opts.frequency ?? 30;
|
|
402
381
|
const speed = opts.speed ?? 6;
|
|
403
382
|
const amplitude = opts.amplitude ?? 0.5;
|
|
404
|
-
const d =
|
|
405
|
-
|
|
406
|
-
);
|
|
407
|
-
const wave = sin2(d.mul(frequency).sub(time.mul(speed)));
|
|
408
|
-
const decay = smoothstep2(reach, 0, d);
|
|
383
|
+
const d = length2(sub2(p, center));
|
|
384
|
+
const wave = sin(d.mul(frequency).sub(time.mul(speed)));
|
|
385
|
+
const decay = smoothstep(reach, 0, d);
|
|
409
386
|
return wave.mul(amplitude).mul(decay);
|
|
410
387
|
}
|
|
411
388
|
|
|
389
|
+
// src/primitives/filmGrain.ts
|
|
390
|
+
import { vec2, sin as sin2, fract, length as length3 } from "three/tsl";
|
|
391
|
+
function filmGrain(uvNode, intensity, timeOffset = 0) {
|
|
392
|
+
const HASH_C1 = vec2(2127.1, 81.17);
|
|
393
|
+
const HASH_C2 = vec2(1269.5, 283.37);
|
|
394
|
+
const base = vec2(uvNode.dot(HASH_C1).add(timeOffset), uvNode.dot(HASH_C2).add(timeOffset));
|
|
395
|
+
const hash = fract(sin2(base).mul(43758.5453));
|
|
396
|
+
return length3(hash).sub(0.765).mul(intensity);
|
|
397
|
+
}
|
|
398
|
+
|
|
412
399
|
// src/runtime/visibility.ts
|
|
413
400
|
function createVisibilityWatcher() {
|
|
414
401
|
if (typeof document === "undefined") {
|
|
@@ -478,35 +465,21 @@ export {
|
|
|
478
465
|
CursorInput,
|
|
479
466
|
MatterScheduler,
|
|
480
467
|
colorRamp,
|
|
481
|
-
cos,
|
|
482
468
|
createIntersectionWatcher,
|
|
483
469
|
createReducedMotionWatcher,
|
|
484
470
|
createRenderer,
|
|
485
471
|
createVisibilityWatcher,
|
|
486
472
|
cursorRipple,
|
|
487
473
|
displace,
|
|
488
|
-
dot,
|
|
489
474
|
fbm,
|
|
475
|
+
filmGrain,
|
|
490
476
|
getReducedMotionPolicy,
|
|
491
477
|
getReducedMotionTimeScale,
|
|
492
|
-
length2 as length,
|
|
493
|
-
max,
|
|
494
|
-
min,
|
|
495
|
-
mix2 as mix,
|
|
496
|
-
mod,
|
|
497
478
|
noise,
|
|
498
|
-
normalize,
|
|
499
479
|
quantize,
|
|
500
480
|
sdfCircle,
|
|
501
481
|
setReducedMotionPolicy,
|
|
502
|
-
sin,
|
|
503
|
-
smoothstep,
|
|
504
482
|
time,
|
|
505
|
-
uniform2 as uniform,
|
|
506
|
-
uv,
|
|
507
|
-
vec2,
|
|
508
|
-
vec32 as vec3,
|
|
509
|
-
vec4,
|
|
510
483
|
voronoi
|
|
511
484
|
};
|
|
512
485
|
//# sourceMappingURL=index.js.map
|