@paper-design/shaders 0.0.27 → 0.0.28
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/dist/shader-mount.js +21 -21
- package/dist/shader-mount.js.map +1 -1
- package/dist/shaders/dot-grid.d.ts +7 -7
- package/dist/shaders/dot-grid.js +5 -5
- package/dist/shaders/dot-grid.js.map +1 -1
- package/dist/shaders/dot-orbit.d.ts +6 -6
- package/dist/shaders/dot-orbit.js +3 -3
- package/dist/shaders/dot-orbit.js.map +1 -1
- package/dist/shaders/metaballs.js +2 -1
- package/dist/shaders/metaballs.js.map +2 -2
- package/dist/shaders/spiral.d.ts +9 -9
- package/dist/shaders/spiral.js +7 -7
- package/dist/shaders/spiral.js.map +1 -1
- package/dist/shaders/swirl.d.ts +2 -2
- package/dist/shaders/swirl.js +2 -2
- package/dist/shaders/swirl.js.map +1 -1
- package/dist/shaders/waves.d.ts +3 -3
- package/dist/shaders/waves.js +2 -2
- package/dist/shaders/waves.js.map +1 -1
- package/package.json +1 -1
package/dist/shader-mount.js
CHANGED
|
@@ -393,8 +393,8 @@ vec3 getBoxSize(float boxRatio, vec2 givenBoxSize, vec2 maxBoxSize) {
|
|
|
393
393
|
|
|
394
394
|
void main() {
|
|
395
395
|
gl_Position = a_position;
|
|
396
|
-
|
|
397
|
-
vec2 uv = gl_Position.xy * .5;
|
|
396
|
+
|
|
397
|
+
vec2 uv = gl_Position.xy * .5;
|
|
398
398
|
vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
|
|
399
399
|
vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
|
|
400
400
|
givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
|
|
@@ -402,12 +402,12 @@ void main() {
|
|
|
402
402
|
float r = u_rotation * 3.14159265358979323846 / 180.;
|
|
403
403
|
mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
|
|
404
404
|
vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
|
|
406
|
+
|
|
407
407
|
// ===================================================
|
|
408
408
|
// Sizing api for graphic objects with fixed ratio
|
|
409
409
|
// (currently supports only ratio = 1)
|
|
410
|
-
|
|
410
|
+
|
|
411
411
|
float fixedRatio = 1.;
|
|
412
412
|
vec2 fixedRatioBoxGivenSize = vec2(
|
|
413
413
|
(u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
|
|
@@ -422,22 +422,22 @@ void main() {
|
|
|
422
422
|
v_objectHelperBox *= objectWorldScale;
|
|
423
423
|
v_objectHelperBox += boxOrigin * (objectWorldScale - 1.);
|
|
424
424
|
#endif
|
|
425
|
-
|
|
425
|
+
|
|
426
426
|
v_objectUV = uv;
|
|
427
427
|
v_objectUV *= objectWorldScale;
|
|
428
428
|
v_objectUV += boxOrigin * (objectWorldScale - 1.);
|
|
429
429
|
v_objectUV += graphicOffset;
|
|
430
430
|
v_objectUV /= u_scale;
|
|
431
431
|
v_objectUV = graphicRotation * v_objectUV;
|
|
432
|
-
|
|
432
|
+
|
|
433
433
|
|
|
434
434
|
// ===================================================
|
|
435
|
-
|
|
436
|
-
|
|
435
|
+
|
|
436
|
+
|
|
437
437
|
// ===================================================
|
|
438
438
|
// Sizing api for graphic objects with either givenBoxSize ratio or canvas ratio.
|
|
439
439
|
// Full-screen mode available with u_worldWidth = u_worldHeight = 0
|
|
440
|
-
|
|
440
|
+
|
|
441
441
|
v_responsiveBoxGivenSize = vec2(
|
|
442
442
|
(u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
|
|
443
443
|
(u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
|
|
@@ -445,13 +445,13 @@ void main() {
|
|
|
445
445
|
float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
|
|
446
446
|
v_responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize, maxBoxSize).xy;
|
|
447
447
|
vec2 responsiveBoxScale = u_resolution.xy / v_responsiveBoxSize;
|
|
448
|
-
|
|
448
|
+
|
|
449
449
|
#ifdef ADD_HELPERS
|
|
450
450
|
v_responsiveHelperBox = uv;
|
|
451
451
|
v_responsiveHelperBox *= responsiveBoxScale;
|
|
452
452
|
v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.);
|
|
453
453
|
#endif
|
|
454
|
-
|
|
454
|
+
|
|
455
455
|
v_responsiveUV = uv;
|
|
456
456
|
v_responsiveUV *= responsiveBoxScale;
|
|
457
457
|
v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.);
|
|
@@ -463,29 +463,29 @@ void main() {
|
|
|
463
463
|
|
|
464
464
|
// ===================================================
|
|
465
465
|
|
|
466
|
-
|
|
466
|
+
|
|
467
467
|
// ===================================================
|
|
468
|
-
// Sizing api for patterns
|
|
468
|
+
// Sizing api for patterns
|
|
469
469
|
// (treating graphics as a image u_worldWidth x u_worldHeight size)
|
|
470
|
-
|
|
471
|
-
float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;
|
|
470
|
+
|
|
471
|
+
float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;
|
|
472
472
|
vec2 patternBoxGivenSize = vec2(
|
|
473
473
|
(u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
|
|
474
474
|
(u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
|
|
475
475
|
);
|
|
476
476
|
patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;
|
|
477
|
-
|
|
477
|
+
|
|
478
478
|
vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize, maxBoxSize);
|
|
479
479
|
v_patternBoxSize = boxSizeData.xy;
|
|
480
480
|
float patternBoxNoFitBoxWidth = boxSizeData.z;
|
|
481
481
|
vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;
|
|
482
|
-
|
|
482
|
+
|
|
483
483
|
#ifdef ADD_HELPERS
|
|
484
484
|
v_patternHelperBox = uv;
|
|
485
485
|
v_patternHelperBox *= patternBoxScale;
|
|
486
486
|
v_patternHelperBox += boxOrigin * (patternBoxScale - 1.);
|
|
487
487
|
#endif
|
|
488
|
-
|
|
488
|
+
|
|
489
489
|
v_patternUV = uv;
|
|
490
490
|
v_patternUV += graphicOffset / patternBoxScale;
|
|
491
491
|
v_patternUV += boxOrigin;
|
|
@@ -500,7 +500,7 @@ void main() {
|
|
|
500
500
|
v_patternUV += boxOrigin / patternBoxScale;
|
|
501
501
|
v_patternUV -= boxOrigin;
|
|
502
502
|
v_patternUV += .5;
|
|
503
|
-
|
|
503
|
+
|
|
504
504
|
// ===================================================
|
|
505
505
|
|
|
506
506
|
}`;
|
|
@@ -538,7 +538,7 @@ function createProgram(gl, vertexShaderSource2, fragmentShaderSource) {
|
|
|
538
538
|
gl.deleteShader(fragmentShader);
|
|
539
539
|
return program;
|
|
540
540
|
}
|
|
541
|
-
const defaultStyle = `@layer
|
|
541
|
+
const defaultStyle = `@layer paper-shaders {
|
|
542
542
|
:where([data-paper-shaders]) {
|
|
543
543
|
isolation: isolate;
|
|
544
544
|
position: relative;
|
package/dist/shader-mount.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/shader-mount.ts"],
|
|
4
|
-
"sourcesContent": ["export class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGLRenderingContext;\n private program: WebGLProgram | null = null;\n private uniformLocations: Record<string, WebGLUniformLocation | null> = {};\n /** The fragment shader that we are using */\n private fragmentShader: string;\n /** Stores the RAF for the render loop */\n private rafId: number | null = null;\n /** Time of the last rendered frame */\n private lastRenderTime = 0;\n /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */\n private totalFrameTime = 0;\n /** The current speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */\n private speed = 0;\n /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */\n private providedUniforms: ShaderMountUniforms;\n /** Just a sanity check to make sure frames don't run after we're disposed */\n private hasBeenDisposed = false;\n /** If the resolution of the canvas has changed since the last render */\n private resolutionChanged = true;\n /** Store textures that are provided by the user */\n private textures: Map<string, WebGLTexture> = new Map();\n private minPixelRatio;\n private maxPixelCount;\n private isSafari = isSafari();\n\n constructor(\n /** The div you'd like to mount the shader to. The shader will match its size. */\n parentElement: HTMLElement,\n fragmentShader: string,\n uniforms: ShaderMountUniforms,\n webGlContextAttributes?: WebGLContextAttributes,\n /** The speed of the animation, or 0 to stop it. Supports negative values to play in reverse. */\n speed = 0,\n /** Pass a frame to offset the starting u_time value and give deterministic results*/\n frame = 0,\n /**\n * The minimum pixel ratio to render at, defaults to 2.\n * May be reduced to improve performance or increased together with `maxPixelCount` to improve antialiasing.\n */\n minPixelRatio = 2,\n /**\n * The maximum amount of physical device pixels to render for the shader,\n * by default it's 1920 * 1080 * 2x dpi (per each side) = 8,294,400 pixels of a 4K screen.\n * Actual DOM size of the canvas can be larger, it will just lose quality after this.\n *\n * May be reduced to improve performance or increased to improve quality on high-resolution screens.\n */\n maxPixelCount: number = 1920 * 1080 * 4\n ) {\n if (parentElement instanceof HTMLElement) {\n this.parentElement = parentElement as PaperShaderElement;\n } else {\n throw new Error('Paper Shaders: parent element must be an HTMLElement');\n }\n\n if (!document.querySelector('style[data-paper-shaders]')) {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shaders', '');\n document.head.prepend(styleElement);\n }\n\n // Create the canvas element and mount it into the provided element\n const canvasElement = document.createElement('canvas');\n this.canvasElement = canvasElement;\n this.parentElement.prepend(canvasElement);\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n // Base our starting animation time on the provided frame value\n this.totalFrameTime = frame;\n this.minPixelRatio = minPixelRatio;\n this.maxPixelCount = maxPixelCount;\n\n const gl = canvasElement.getContext('webgl2', webGlContextAttributes);\n if (!gl) {\n throw new Error('Paper Shaders: WebGL is not supported in this browser');\n }\n this.gl = gl;\n\n this.initProgram();\n this.setupPositionAttribute();\n // Grab the locations of the uniforms in the fragment shader\n this.setupUniforms();\n // Put the user provided values into the uniforms\n this.setUniformValues(this.providedUniforms);\n // Set up the resize observer to handle window resizing and set u_resolution\n this.setupResizeObserver();\n\n // Set the animation speed after everything is ready to go\n this.setSpeed(speed);\n\n // Mark parent element as paper shader mount\n this.parentElement.setAttribute('data-paper-shaders', '');\n\n // Add the shaderMount instance to the div mount element to make it easily accessible\n this.parentElement.paperShaderMount = this;\n }\n\n private initProgram = () => {\n const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);\n if (!program) return;\n this.program = program;\n };\n\n private setupPositionAttribute = () => {\n const positionAttributeLocation = this.gl.getAttribLocation(this.program!, 'a_position');\n const positionBuffer = this.gl.createBuffer();\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);\n const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];\n this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW);\n this.gl.enableVertexAttribArray(positionAttributeLocation);\n this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);\n };\n\n private setupUniforms = () => {\n // Create a map to store all uniform locations\n const uniformLocations: Record<string, WebGLUniformLocation | null> = {\n u_time: this.gl.getUniformLocation(this.program!, 'u_time'),\n u_pixelRatio: this.gl.getUniformLocation(this.program!, 'u_pixelRatio'),\n u_resolution: this.gl.getUniformLocation(this.program!, 'u_resolution'),\n };\n\n // Add locations for all provided uniforms\n Object.entries(this.providedUniforms).forEach(([key, value]) => {\n uniformLocations[key] = this.gl.getUniformLocation(this.program!, key);\n\n // For texture uniforms, also look for the aspect ratio uniform\n if (value instanceof HTMLImageElement) {\n const aspectRatioUniformName = `${key}_aspect_ratio`;\n uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program!, aspectRatioUniformName);\n }\n });\n\n this.uniformLocations = uniformLocations;\n };\n\n /**\n * The scale that we should render at.\n * - Used to target 2x rendering even on 1x screens for better antialiasing\n * - Prevents the virtual resolution from going beyond the maximum resolution\n * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels\n */\n private renderScale = 1;\n private parentWidth = 0;\n private parentHeight = 0;\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(([entry]) => {\n if (entry?.borderBoxSize[0]) {\n this.parentWidth = entry.borderBoxSize[0].inlineSize;\n this.parentHeight = entry.borderBoxSize[0].blockSize;\n }\n\n this.handleResize();\n });\n\n this.resizeObserver.observe(this.parentElement);\n visualViewport?.addEventListener('resize', this.handleVisualViewportChange);\n\n const rect = this.parentElement.getBoundingClientRect();\n this.parentWidth = rect.width;\n this.parentHeight = rect.height;\n this.handleResize();\n };\n\n // Visual viewport resize handler, mainly used to react to browser zoom changes.\n // Wait 2 frames to align with when the resize observer callback is done (in case it might follow):\n // - Frame 1: a paint after the visual viewport resize\n // - Frame 2: a paint after the resize observer has been handled, if it was ever triggered\n //\n // Both resize observer and visual viewport will react to classic browser zoom changes,\n // so we dedupe the callbacks, but pinch zoom only triggers the visual viewport handler.\n private resizeRafId: number | null = null;\n private handleVisualViewportChange = () => {\n if (this.resizeRafId !== null) {\n cancelAnimationFrame(this.resizeRafId);\n }\n\n this.resizeRafId = requestAnimationFrame(() => {\n this.resizeRafId = requestAnimationFrame(() => {\n this.handleResize();\n });\n });\n };\n\n /** Resize handler for when the container div changes size and we want to resize our canvas to match */\n private handleResize = () => {\n // Cancel any scheduled resize handlers\n if (this.resizeRafId !== null) {\n cancelAnimationFrame(this.resizeRafId);\n }\n\n const pinchZoom = visualViewport?.scale ?? 1;\n\n // Zoom level can be calculated comparing the browser's outerWidth and the viewport width.\n // Note: avoid innerWidth, use visualViewport.width instead.\n // - innerWidth is affected by pinch zoom in Safari, but not other browsers.\n // visualViewport.width works consistently in all browsers.\n // - innerWidth is rounded to integer, but not visualViewport.width.\n const innerWidth = visualViewport ? visualViewport.width * visualViewport.scale : window.innerWidth;\n\n // Slight rounding here helps the <canvas> maintain a consistent computed size as the zoom level changes\n const classicZoom = Math.round((10000 * window.outerWidth) / innerWidth) / 10000;\n\n // As of 2025, Safari reports physical devicePixelRatio, but other browsers add the current zoom level\n // https://bugs.webkit.org/show_bug.cgi?id=124862\n const realPixelRatio = this.isSafari ? devicePixelRatio : devicePixelRatio / classicZoom;\n const targetPixelRatio = Math.max(realPixelRatio, this.minPixelRatio);\n const targetRenderScale = targetPixelRatio * classicZoom * pinchZoom;\n const targetPixelWidth = this.parentWidth * targetRenderScale;\n const targetPixelHeight = this.parentHeight * targetRenderScale;\n\n // Prevent the total rendered pixel count from exceeding maxPixelCount\n const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);\n\n const newRenderScale = targetRenderScale * Math.min(1, maxPixelCountHeadroom);\n const newWidth = Math.round(this.parentWidth * newRenderScale);\n const newHeight = Math.round(this.parentHeight * newRenderScale);\n\n if (\n this.canvasElement.width !== newWidth ||\n this.canvasElement.height !== newHeight ||\n this.renderScale !== newRenderScale // Usually, only render scale change when the user zooms in/out\n ) {\n this.renderScale = newRenderScale;\n this.canvasElement.width = newWidth;\n this.canvasElement.height = newHeight;\n this.resolutionChanged = true;\n this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);\n\n // this is necessary to avoid flashes while resizing (the next scheduled render will set uniforms)\n this.render(performance.now());\n }\n };\n\n private render = (currentTime: number) => {\n if (this.hasBeenDisposed) return;\n\n if (this.program === null) {\n console.warn('Tried to render before program or gl was initialized');\n return;\n }\n\n // Calculate the delta time\n const dt = currentTime - this.lastRenderTime;\n this.lastRenderTime = currentTime;\n // Increase the total animation time by dt * animationSpeed\n if (this.speed !== 0) {\n this.totalFrameTime += dt * this.speed;\n }\n\n // Clear the canvas\n this.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n // Update uniforms\n this.gl.useProgram(this.program);\n\n // Update the time uniform\n this.gl.uniform1f(this.uniformLocations.u_time!, this.totalFrameTime * 0.001);\n\n // If the resolution has changed, we need to update the uniform\n if (this.resolutionChanged) {\n this.gl.uniform2f(this.uniformLocations.u_resolution!, this.gl.canvas.width, this.gl.canvas.height);\n this.gl.uniform1f(this.uniformLocations.u_pixelRatio!, this.renderScale);\n this.resolutionChanged = false;\n }\n\n this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n // Loop if we're animating\n if (this.speed !== 0) {\n this.requestRender();\n } else {\n this.rafId = null;\n }\n };\n\n private requestRender = () => {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n }\n this.rafId = requestAnimationFrame(this.render);\n };\n\n /** Creates a texture from an image and sets it into a uniform value */\n private setTextureUniform = (uniformName: string, image: HTMLImageElement): void => {\n if (!image.complete || image.naturalWidth === 0) {\n throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);\n }\n\n // Clean up existing texture if present\n const existingTexture = this.textures.get(uniformName);\n if (existingTexture) {\n this.gl.deleteTexture(existingTexture);\n }\n\n // Create and set up the new texture\n const texture = this.gl.createTexture();\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n // Set texture parameters\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.REPEAT);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.REPEAT);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n // Upload image to texture\n this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);\n const error = this.gl.getError();\n if (error !== this.gl.NO_ERROR || texture === null) {\n console.error('Paper Shaders: WebGL error when uploading texture:', error);\n return;\n }\n\n // Store the texture\n this.textures.set(uniformName, texture);\n\n // Set up texture unit and uniform\n const location = this.uniformLocations[uniformName];\n if (location) {\n // Use texture unit based on the order textures were added\n const textureUnit = this.textures.size - 1;\n this.gl.useProgram(this.program);\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}_aspect_ratio`;\n const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName];\n if (aspectRatioLocation) {\n const aspectRatio = image.naturalWidth / image.naturalHeight;\n this.gl.uniform1f(aspectRatioLocation, aspectRatio);\n }\n }\n };\n\n /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */\n private setUniformValues = (updatedUniforms: ShaderMountUniforms) => {\n this.gl.useProgram(this.program);\n Object.entries(updatedUniforms).forEach(([key, value]) => {\n const location = this.uniformLocations[key];\n if (!location) {\n console.warn(`Uniform location for ${key} not found`);\n return;\n }\n\n if (value instanceof HTMLImageElement) {\n // Texture case, requires a good amount of code so it gets its own function:\n this.setTextureUniform(key, value);\n } else if (Array.isArray(value)) {\n // Array case\n let flatArray: number[] | null = null;\n let valueLength: number | null = null;\n\n // If it's an array of same-sized arrays, flatten it down so we can set the uniform\n if (value[0] !== undefined && Array.isArray(value[0])) {\n const firstChildLength = value[0].length;\n if (value.every((arr) => (arr as number[]).length === firstChildLength)) {\n // Array of same-sized arrays case, flattens the array sets it\n flatArray = value.flat();\n valueLength = firstChildLength;\n } else {\n console.warn(`All child arrays must be the same length for ${key}`);\n return;\n }\n } else {\n // Array of primitive values case, supports 2, 3, 4, 9, 16 length arrays\n flatArray = value as number[];\n valueLength = flatArray.length;\n }\n\n // Set the uniform based on array length... supports 2, 3, 4, 9, 16 length arrays of primitive values\n // or arbitrary length arrays of arrays\n switch (valueLength) {\n case 2:\n this.gl.uniform2fv(location, flatArray);\n break;\n case 3:\n this.gl.uniform3fv(location, flatArray);\n break;\n case 4:\n this.gl.uniform4fv(location, flatArray);\n break;\n case 9:\n this.gl.uniformMatrix3fv(location, false, flatArray);\n break;\n case 16:\n this.gl.uniformMatrix4fv(location, false, flatArray);\n break;\n default:\n console.warn(`Unsupported uniform array length: ${valueLength}`);\n }\n } else if (typeof value === 'number') {\n // Number case, supports floats and ints\n this.gl.uniform1f(location, value);\n } else if (typeof value === 'boolean') {\n // Boolean case, supports true and false\n this.gl.uniform1i(location, value ? 1 : 0);\n } else {\n console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);\n }\n });\n };\n\n /** Gets the current total animation time from 0ms */\n public getCurrentFrameTime = (): number => {\n return this.totalFrameTime;\n };\n\n /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */\n public setFrame = (newFrame: number): void => {\n this.totalFrameTime = newFrame;\n this.lastRenderTime = performance.now();\n this.render(performance.now());\n };\n\n /** Set an animation speed (or 0 to stop animation) */\n public setSpeed = (newSpeed: number = 1): void => {\n // Set the new animation speed\n this.speed = newSpeed;\n\n if (this.rafId === null && newSpeed !== 0) {\n // Moving from 0 to animating, kick off a new rAF loop\n this.lastRenderTime = performance.now();\n this.rafId = requestAnimationFrame(this.render);\n }\n\n if (this.rafId !== null && newSpeed === 0) {\n // Moving from animating to not animating, cancel the rAF loop\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n };\n\n /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */\n public setUniforms = (newUniforms: ShaderMountUniforms): void => {\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\n // If we need to allow users to add uniforms after the shader has been created, we can do that here\n // But right now we're expecting the uniform list to be predictable and static\n // this.setupUniforms();\n\n this.setUniformValues(newUniforms);\n this.render(performance.now());\n };\n\n /** Dispose of the shader mount, cleaning up all of the WebGL resources */\n public dispose = (): void => {\n // Immediately mark as disposed to prevent future renders from leaking in\n this.hasBeenDisposed = true;\n\n // Cancel the rAF loop\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n if (this.gl && this.program) {\n // Clean up all textures\n this.textures.forEach((texture) => {\n this.gl.deleteTexture(texture);\n });\n this.textures.clear();\n\n this.gl.deleteProgram(this.program);\n this.program = null;\n\n // Reset the WebGL context\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);\n this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);\n this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);\n\n // Clear any errors\n this.gl.getError();\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n visualViewport?.removeEventListener('resize', this.handleVisualViewportChange);\n\n this.uniformLocations = {};\n\n // Remove the shader mount from the div wrapper element to avoid any GC issues\n this.parentElement.paperShaderMount = undefined;\n };\n}\n\n/** Vertex shader for the shader mount */\nconst vertexShaderSource = `#version 300 es\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\n\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform float u_pxSize;\n\nout vec2 v_objectUV;\nout vec2 v_objectBoxSize;\nout vec2 v_objectHelperBox;\n\nout vec2 v_responsiveUV;\nout vec2 v_responsiveBoxSize;\nout vec2 v_responsiveHelperBox;\nout vec2 v_responsiveBoxGivenSize;\n\nout vec2 v_patternUV;\nout vec2 v_patternBoxSize;\nout vec2 v_patternHelperBox;\n\n// #define ADD_HELPERS\n\nvec3 getBoxSize(float boxRatio, vec2 givenBoxSize, vec2 maxBoxSize) {\n vec2 box = vec2(0.);\n // fit = none\n box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);\n float noFitBoxWidth = box.x;\n if (u_fit == 1.) { // fit = contain\n box.x = boxRatio * min(maxBoxSize[0] / boxRatio, maxBoxSize[1]);\n } else if (u_fit == 2.) { // fit = cover\n box.x = boxRatio * max(maxBoxSize[0] / boxRatio, maxBoxSize[1]);\n }\n box.y = box.x / boxRatio;\n return vec3(box, noFitBoxWidth);\n}\n\nvoid main() {\n gl_Position = a_position;\n \n vec2 uv = gl_Position.xy * .5; \n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n vec2 maxBoxSize = vec2(max(u_resolution.x, givenBoxSize.x), max(u_resolution.y, givenBoxSize.y));\n float r = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n \n \n // ===================================================\n // Sizing api for graphic objects with fixed ratio\n // (currently supports only ratio = 1)\n \n float fixedRatio = 1.;\n vec2 fixedRatioBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n\n v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize, maxBoxSize).xy;\n vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;\n\n #ifdef ADD_HELPERS\n v_objectHelperBox = uv;\n v_objectHelperBox *= objectWorldScale;\n v_objectHelperBox += boxOrigin * (objectWorldScale - 1.);\n #endif\n \n v_objectUV = uv;\n v_objectUV *= objectWorldScale;\n v_objectUV += boxOrigin * (objectWorldScale - 1.);\n v_objectUV += graphicOffset;\n v_objectUV /= u_scale;\n v_objectUV = graphicRotation * v_objectUV;\n \n\n // ===================================================\n \n \n // ===================================================\n // Sizing api for graphic objects with either givenBoxSize ratio or canvas ratio.\n // Full-screen mode available with u_worldWidth = u_worldHeight = 0\n \n v_responsiveBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n v_responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize, maxBoxSize).xy;\n vec2 responsiveBoxScale = u_resolution.xy / v_responsiveBoxSize;\n \n #ifdef ADD_HELPERS\n v_responsiveHelperBox = uv;\n v_responsiveHelperBox *= responsiveBoxScale;\n v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.);\n #endif\n \n v_responsiveUV = uv;\n v_responsiveUV *= responsiveBoxScale;\n v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.);\n v_responsiveUV += graphicOffset;\n v_responsiveUV /= u_scale;\n v_responsiveUV.x *= responsiveRatio;\n v_responsiveUV = graphicRotation * v_responsiveUV;\n v_responsiveUV.x /= responsiveRatio;\n\n // ===================================================\n\n \n // ===================================================\n // Sizing api for patterns \n // (treating graphics as a image u_worldWidth x u_worldHeight size)\n \n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y; \n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n \n vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize, maxBoxSize);\n v_patternBoxSize = boxSizeData.xy;\n float patternBoxNoFitBoxWidth = boxSizeData.z;\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n \n #ifdef ADD_HELPERS\n v_patternHelperBox = uv;\n v_patternHelperBox *= patternBoxScale;\n v_patternHelperBox += boxOrigin * (patternBoxScale - 1.);\n #endif\n \n v_patternUV = uv;\n v_patternUV += graphicOffset / patternBoxScale;\n v_patternUV += boxOrigin;\n v_patternUV -= boxOrigin / patternBoxScale;\n v_patternUV *= u_resolution.xy;\n v_patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n v_patternUV /= u_scale;\n v_patternUV = graphicRotation * v_patternUV;\n v_patternUV += boxOrigin / patternBoxScale;\n v_patternUV -= boxOrigin;\n v_patternUV += .5;\n \n // ===================================================\n\n}`;\n\nfunction createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\nfunction createProgram(\n gl: WebGLRenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);\n\n if (!vertexShader || !fragmentShader) return null;\n\n const program = gl.createProgram();\n if (!program) return null;\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));\n gl.deleteProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return null;\n }\n\n // Clean up shaders after successful linking\n gl.detachShader(program, vertexShader);\n gl.detachShader(program, fragmentShader);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n return program;\n}\n\nconst defaultStyle = `@layer base {\n :where([data-paper-shaders]) {\n isolation: isolate;\n position: relative;\n\n & canvas {\n contain: strict;\n display: block;\n position: absolute;\n inset: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n }\n }\n}`;\n\n/** A canvas element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if a canvas element is a ShaderCanvas */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/** Uniform types that we support to be auto-mapped into the fragment shader */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement;\n}\n\nexport interface ShaderMotionParams {\n speed?: number;\n frame?: number;\n}\n\nexport type ShaderPreset<T> = {\n name: string;\n params: Required<T>;\n};\n\nfunction isSafari() {\n const ua = navigator.userAgent.toLowerCase();\n return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('android');\n}\n"],
|
|
4
|
+
"sourcesContent": ["export class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGLRenderingContext;\n private program: WebGLProgram | null = null;\n private uniformLocations: Record<string, WebGLUniformLocation | null> = {};\n /** The fragment shader that we are using */\n private fragmentShader: string;\n /** Stores the RAF for the render loop */\n private rafId: number | null = null;\n /** Time of the last rendered frame */\n private lastRenderTime = 0;\n /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */\n private totalFrameTime = 0;\n /** The current speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */\n private speed = 0;\n /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */\n private providedUniforms: ShaderMountUniforms;\n /** Just a sanity check to make sure frames don't run after we're disposed */\n private hasBeenDisposed = false;\n /** If the resolution of the canvas has changed since the last render */\n private resolutionChanged = true;\n /** Store textures that are provided by the user */\n private textures: Map<string, WebGLTexture> = new Map();\n private minPixelRatio;\n private maxPixelCount;\n private isSafari = isSafari();\n\n constructor(\n /** The div you'd like to mount the shader to. The shader will match its size. */\n parentElement: HTMLElement,\n fragmentShader: string,\n uniforms: ShaderMountUniforms,\n webGlContextAttributes?: WebGLContextAttributes,\n /** The speed of the animation, or 0 to stop it. Supports negative values to play in reverse. */\n speed = 0,\n /** Pass a frame to offset the starting u_time value and give deterministic results*/\n frame = 0,\n /**\n * The minimum pixel ratio to render at, defaults to 2.\n * May be reduced to improve performance or increased together with `maxPixelCount` to improve antialiasing.\n */\n minPixelRatio = 2,\n /**\n * The maximum amount of physical device pixels to render for the shader,\n * by default it's 1920 * 1080 * 2x dpi (per each side) = 8,294,400 pixels of a 4K screen.\n * Actual DOM size of the canvas can be larger, it will just lose quality after this.\n *\n * May be reduced to improve performance or increased to improve quality on high-resolution screens.\n */\n maxPixelCount: number = 1920 * 1080 * 4\n ) {\n if (parentElement instanceof HTMLElement) {\n this.parentElement = parentElement as PaperShaderElement;\n } else {\n throw new Error('Paper Shaders: parent element must be an HTMLElement');\n }\n\n if (!document.querySelector('style[data-paper-shaders]')) {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shaders', '');\n document.head.prepend(styleElement);\n }\n\n // Create the canvas element and mount it into the provided element\n const canvasElement = document.createElement('canvas');\n this.canvasElement = canvasElement;\n this.parentElement.prepend(canvasElement);\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n // Base our starting animation time on the provided frame value\n this.totalFrameTime = frame;\n this.minPixelRatio = minPixelRatio;\n this.maxPixelCount = maxPixelCount;\n\n const gl = canvasElement.getContext('webgl2', webGlContextAttributes);\n if (!gl) {\n throw new Error('Paper Shaders: WebGL is not supported in this browser');\n }\n this.gl = gl;\n\n this.initProgram();\n this.setupPositionAttribute();\n // Grab the locations of the uniforms in the fragment shader\n this.setupUniforms();\n // Put the user provided values into the uniforms\n this.setUniformValues(this.providedUniforms);\n // Set up the resize observer to handle window resizing and set u_resolution\n this.setupResizeObserver();\n\n // Set the animation speed after everything is ready to go\n this.setSpeed(speed);\n\n // Mark parent element as paper shader mount\n this.parentElement.setAttribute('data-paper-shaders', '');\n\n // Add the shaderMount instance to the div mount element to make it easily accessible\n this.parentElement.paperShaderMount = this;\n }\n\n private initProgram = () => {\n const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);\n if (!program) return;\n this.program = program;\n };\n\n private setupPositionAttribute = () => {\n const positionAttributeLocation = this.gl.getAttribLocation(this.program!, 'a_position');\n const positionBuffer = this.gl.createBuffer();\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);\n const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];\n this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW);\n this.gl.enableVertexAttribArray(positionAttributeLocation);\n this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);\n };\n\n private setupUniforms = () => {\n // Create a map to store all uniform locations\n const uniformLocations: Record<string, WebGLUniformLocation | null> = {\n u_time: this.gl.getUniformLocation(this.program!, 'u_time'),\n u_pixelRatio: this.gl.getUniformLocation(this.program!, 'u_pixelRatio'),\n u_resolution: this.gl.getUniformLocation(this.program!, 'u_resolution'),\n };\n\n // Add locations for all provided uniforms\n Object.entries(this.providedUniforms).forEach(([key, value]) => {\n uniformLocations[key] = this.gl.getUniformLocation(this.program!, key);\n\n // For texture uniforms, also look for the aspect ratio uniform\n if (value instanceof HTMLImageElement) {\n const aspectRatioUniformName = `${key}_aspect_ratio`;\n uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program!, aspectRatioUniformName);\n }\n });\n\n this.uniformLocations = uniformLocations;\n };\n\n /**\n * The scale that we should render at.\n * - Used to target 2x rendering even on 1x screens for better antialiasing\n * - Prevents the virtual resolution from going beyond the maximum resolution\n * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels\n */\n private renderScale = 1;\n private parentWidth = 0;\n private parentHeight = 0;\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(([entry]) => {\n if (entry?.borderBoxSize[0]) {\n this.parentWidth = entry.borderBoxSize[0].inlineSize;\n this.parentHeight = entry.borderBoxSize[0].blockSize;\n }\n\n this.handleResize();\n });\n\n this.resizeObserver.observe(this.parentElement);\n visualViewport?.addEventListener('resize', this.handleVisualViewportChange);\n\n const rect = this.parentElement.getBoundingClientRect();\n this.parentWidth = rect.width;\n this.parentHeight = rect.height;\n this.handleResize();\n };\n\n // Visual viewport resize handler, mainly used to react to browser zoom changes.\n // Wait 2 frames to align with when the resize observer callback is done (in case it might follow):\n // - Frame 1: a paint after the visual viewport resize\n // - Frame 2: a paint after the resize observer has been handled, if it was ever triggered\n //\n // Both resize observer and visual viewport will react to classic browser zoom changes,\n // so we dedupe the callbacks, but pinch zoom only triggers the visual viewport handler.\n private resizeRafId: number | null = null;\n private handleVisualViewportChange = () => {\n if (this.resizeRafId !== null) {\n cancelAnimationFrame(this.resizeRafId);\n }\n\n this.resizeRafId = requestAnimationFrame(() => {\n this.resizeRafId = requestAnimationFrame(() => {\n this.handleResize();\n });\n });\n };\n\n /** Resize handler for when the container div changes size and we want to resize our canvas to match */\n private handleResize = () => {\n // Cancel any scheduled resize handlers\n if (this.resizeRafId !== null) {\n cancelAnimationFrame(this.resizeRafId);\n }\n\n const pinchZoom = visualViewport?.scale ?? 1;\n\n // Zoom level can be calculated comparing the browser's outerWidth and the viewport width.\n // Note: avoid innerWidth, use visualViewport.width instead.\n // - innerWidth is affected by pinch zoom in Safari, but not other browsers.\n // visualViewport.width works consistently in all browsers.\n // - innerWidth is rounded to integer, but not visualViewport.width.\n const innerWidth = visualViewport ? visualViewport.width * visualViewport.scale : window.innerWidth;\n\n // Slight rounding here helps the <canvas> maintain a consistent computed size as the zoom level changes\n const classicZoom = Math.round((10000 * window.outerWidth) / innerWidth) / 10000;\n\n // As of 2025, Safari reports physical devicePixelRatio, but other browsers add the current zoom level\n // https://bugs.webkit.org/show_bug.cgi?id=124862\n const realPixelRatio = this.isSafari ? devicePixelRatio : devicePixelRatio / classicZoom;\n const targetPixelRatio = Math.max(realPixelRatio, this.minPixelRatio);\n const targetRenderScale = targetPixelRatio * classicZoom * pinchZoom;\n const targetPixelWidth = this.parentWidth * targetRenderScale;\n const targetPixelHeight = this.parentHeight * targetRenderScale;\n\n // Prevent the total rendered pixel count from exceeding maxPixelCount\n const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);\n\n const newRenderScale = targetRenderScale * Math.min(1, maxPixelCountHeadroom);\n const newWidth = Math.round(this.parentWidth * newRenderScale);\n const newHeight = Math.round(this.parentHeight * newRenderScale);\n\n if (\n this.canvasElement.width !== newWidth ||\n this.canvasElement.height !== newHeight ||\n this.renderScale !== newRenderScale // Usually, only render scale change when the user zooms in/out\n ) {\n this.renderScale = newRenderScale;\n this.canvasElement.width = newWidth;\n this.canvasElement.height = newHeight;\n this.resolutionChanged = true;\n this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);\n\n // this is necessary to avoid flashes while resizing (the next scheduled render will set uniforms)\n this.render(performance.now());\n }\n };\n\n private render = (currentTime: number) => {\n if (this.hasBeenDisposed) return;\n\n if (this.program === null) {\n console.warn('Tried to render before program or gl was initialized');\n return;\n }\n\n // Calculate the delta time\n const dt = currentTime - this.lastRenderTime;\n this.lastRenderTime = currentTime;\n // Increase the total animation time by dt * animationSpeed\n if (this.speed !== 0) {\n this.totalFrameTime += dt * this.speed;\n }\n\n // Clear the canvas\n this.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n // Update uniforms\n this.gl.useProgram(this.program);\n\n // Update the time uniform\n this.gl.uniform1f(this.uniformLocations.u_time!, this.totalFrameTime * 0.001);\n\n // If the resolution has changed, we need to update the uniform\n if (this.resolutionChanged) {\n this.gl.uniform2f(this.uniformLocations.u_resolution!, this.gl.canvas.width, this.gl.canvas.height);\n this.gl.uniform1f(this.uniformLocations.u_pixelRatio!, this.renderScale);\n this.resolutionChanged = false;\n }\n\n this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n // Loop if we're animating\n if (this.speed !== 0) {\n this.requestRender();\n } else {\n this.rafId = null;\n }\n };\n\n private requestRender = () => {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n }\n this.rafId = requestAnimationFrame(this.render);\n };\n\n /** Creates a texture from an image and sets it into a uniform value */\n private setTextureUniform = (uniformName: string, image: HTMLImageElement): void => {\n if (!image.complete || image.naturalWidth === 0) {\n throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);\n }\n\n // Clean up existing texture if present\n const existingTexture = this.textures.get(uniformName);\n if (existingTexture) {\n this.gl.deleteTexture(existingTexture);\n }\n\n // Create and set up the new texture\n const texture = this.gl.createTexture();\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n // Set texture parameters\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.REPEAT);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.REPEAT);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n // Upload image to texture\n this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);\n const error = this.gl.getError();\n if (error !== this.gl.NO_ERROR || texture === null) {\n console.error('Paper Shaders: WebGL error when uploading texture:', error);\n return;\n }\n\n // Store the texture\n this.textures.set(uniformName, texture);\n\n // Set up texture unit and uniform\n const location = this.uniformLocations[uniformName];\n if (location) {\n // Use texture unit based on the order textures were added\n const textureUnit = this.textures.size - 1;\n this.gl.useProgram(this.program);\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}_aspect_ratio`;\n const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName];\n if (aspectRatioLocation) {\n const aspectRatio = image.naturalWidth / image.naturalHeight;\n this.gl.uniform1f(aspectRatioLocation, aspectRatio);\n }\n }\n };\n\n /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */\n private setUniformValues = (updatedUniforms: ShaderMountUniforms) => {\n this.gl.useProgram(this.program);\n Object.entries(updatedUniforms).forEach(([key, value]) => {\n const location = this.uniformLocations[key];\n if (!location) {\n console.warn(`Uniform location for ${key} not found`);\n return;\n }\n\n if (value instanceof HTMLImageElement) {\n // Texture case, requires a good amount of code so it gets its own function:\n this.setTextureUniform(key, value);\n } else if (Array.isArray(value)) {\n // Array case\n let flatArray: number[] | null = null;\n let valueLength: number | null = null;\n\n // If it's an array of same-sized arrays, flatten it down so we can set the uniform\n if (value[0] !== undefined && Array.isArray(value[0])) {\n const firstChildLength = value[0].length;\n if (value.every((arr) => (arr as number[]).length === firstChildLength)) {\n // Array of same-sized arrays case, flattens the array sets it\n flatArray = value.flat();\n valueLength = firstChildLength;\n } else {\n console.warn(`All child arrays must be the same length for ${key}`);\n return;\n }\n } else {\n // Array of primitive values case, supports 2, 3, 4, 9, 16 length arrays\n flatArray = value as number[];\n valueLength = flatArray.length;\n }\n\n // Set the uniform based on array length... supports 2, 3, 4, 9, 16 length arrays of primitive values\n // or arbitrary length arrays of arrays\n switch (valueLength) {\n case 2:\n this.gl.uniform2fv(location, flatArray);\n break;\n case 3:\n this.gl.uniform3fv(location, flatArray);\n break;\n case 4:\n this.gl.uniform4fv(location, flatArray);\n break;\n case 9:\n this.gl.uniformMatrix3fv(location, false, flatArray);\n break;\n case 16:\n this.gl.uniformMatrix4fv(location, false, flatArray);\n break;\n default:\n console.warn(`Unsupported uniform array length: ${valueLength}`);\n }\n } else if (typeof value === 'number') {\n // Number case, supports floats and ints\n this.gl.uniform1f(location, value);\n } else if (typeof value === 'boolean') {\n // Boolean case, supports true and false\n this.gl.uniform1i(location, value ? 1 : 0);\n } else {\n console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);\n }\n });\n };\n\n /** Gets the current total animation time from 0ms */\n public getCurrentFrameTime = (): number => {\n return this.totalFrameTime;\n };\n\n /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */\n public setFrame = (newFrame: number): void => {\n this.totalFrameTime = newFrame;\n this.lastRenderTime = performance.now();\n this.render(performance.now());\n };\n\n /** Set an animation speed (or 0 to stop animation) */\n public setSpeed = (newSpeed: number = 1): void => {\n // Set the new animation speed\n this.speed = newSpeed;\n\n if (this.rafId === null && newSpeed !== 0) {\n // Moving from 0 to animating, kick off a new rAF loop\n this.lastRenderTime = performance.now();\n this.rafId = requestAnimationFrame(this.render);\n }\n\n if (this.rafId !== null && newSpeed === 0) {\n // Moving from animating to not animating, cancel the rAF loop\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n };\n\n /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */\n public setUniforms = (newUniforms: ShaderMountUniforms): void => {\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\n // If we need to allow users to add uniforms after the shader has been created, we can do that here\n // But right now we're expecting the uniform list to be predictable and static\n // this.setupUniforms();\n\n this.setUniformValues(newUniforms);\n this.render(performance.now());\n };\n\n /** Dispose of the shader mount, cleaning up all of the WebGL resources */\n public dispose = (): void => {\n // Immediately mark as disposed to prevent future renders from leaking in\n this.hasBeenDisposed = true;\n\n // Cancel the rAF loop\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n if (this.gl && this.program) {\n // Clean up all textures\n this.textures.forEach((texture) => {\n this.gl.deleteTexture(texture);\n });\n this.textures.clear();\n\n this.gl.deleteProgram(this.program);\n this.program = null;\n\n // Reset the WebGL context\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);\n this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);\n this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);\n\n // Clear any errors\n this.gl.getError();\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n visualViewport?.removeEventListener('resize', this.handleVisualViewportChange);\n\n this.uniformLocations = {};\n\n // Remove the shader mount from the div wrapper element to avoid any GC issues\n this.parentElement.paperShaderMount = undefined;\n };\n}\n\n/** Vertex shader for the shader mount */\nconst vertexShaderSource = `#version 300 es\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\n\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform float u_pxSize;\n\nout vec2 v_objectUV;\nout vec2 v_objectBoxSize;\nout vec2 v_objectHelperBox;\n\nout vec2 v_responsiveUV;\nout vec2 v_responsiveBoxSize;\nout vec2 v_responsiveHelperBox;\nout vec2 v_responsiveBoxGivenSize;\n\nout vec2 v_patternUV;\nout vec2 v_patternBoxSize;\nout vec2 v_patternHelperBox;\n\n// #define ADD_HELPERS\n\nvec3 getBoxSize(float boxRatio, vec2 givenBoxSize, vec2 maxBoxSize) {\n vec2 box = vec2(0.);\n // fit = none\n box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);\n float noFitBoxWidth = box.x;\n if (u_fit == 1.) { // fit = contain\n box.x = boxRatio * min(maxBoxSize[0] / boxRatio, maxBoxSize[1]);\n } else if (u_fit == 2.) { // fit = cover\n box.x = boxRatio * max(maxBoxSize[0] / boxRatio, maxBoxSize[1]);\n }\n box.y = box.x / boxRatio;\n return vec3(box, noFitBoxWidth);\n}\n\nvoid main() {\n gl_Position = a_position;\n\n vec2 uv = gl_Position.xy * .5;\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n vec2 maxBoxSize = vec2(max(u_resolution.x, givenBoxSize.x), max(u_resolution.y, givenBoxSize.y));\n float r = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n\n // ===================================================\n // Sizing api for graphic objects with fixed ratio\n // (currently supports only ratio = 1)\n\n float fixedRatio = 1.;\n vec2 fixedRatioBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n\n v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize, maxBoxSize).xy;\n vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;\n\n #ifdef ADD_HELPERS\n v_objectHelperBox = uv;\n v_objectHelperBox *= objectWorldScale;\n v_objectHelperBox += boxOrigin * (objectWorldScale - 1.);\n #endif\n\n v_objectUV = uv;\n v_objectUV *= objectWorldScale;\n v_objectUV += boxOrigin * (objectWorldScale - 1.);\n v_objectUV += graphicOffset;\n v_objectUV /= u_scale;\n v_objectUV = graphicRotation * v_objectUV;\n\n\n // ===================================================\n\n\n // ===================================================\n // Sizing api for graphic objects with either givenBoxSize ratio or canvas ratio.\n // Full-screen mode available with u_worldWidth = u_worldHeight = 0\n\n v_responsiveBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n v_responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize, maxBoxSize).xy;\n vec2 responsiveBoxScale = u_resolution.xy / v_responsiveBoxSize;\n\n #ifdef ADD_HELPERS\n v_responsiveHelperBox = uv;\n v_responsiveHelperBox *= responsiveBoxScale;\n v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.);\n #endif\n\n v_responsiveUV = uv;\n v_responsiveUV *= responsiveBoxScale;\n v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.);\n v_responsiveUV += graphicOffset;\n v_responsiveUV /= u_scale;\n v_responsiveUV.x *= responsiveRatio;\n v_responsiveUV = graphicRotation * v_responsiveUV;\n v_responsiveUV.x /= responsiveRatio;\n\n // ===================================================\n\n\n // ===================================================\n // Sizing api for patterns\n // (treating graphics as a image u_worldWidth x u_worldHeight size)\n\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n\n vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize, maxBoxSize);\n v_patternBoxSize = boxSizeData.xy;\n float patternBoxNoFitBoxWidth = boxSizeData.z;\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n\n #ifdef ADD_HELPERS\n v_patternHelperBox = uv;\n v_patternHelperBox *= patternBoxScale;\n v_patternHelperBox += boxOrigin * (patternBoxScale - 1.);\n #endif\n\n v_patternUV = uv;\n v_patternUV += graphicOffset / patternBoxScale;\n v_patternUV += boxOrigin;\n v_patternUV -= boxOrigin / patternBoxScale;\n v_patternUV *= u_resolution.xy;\n v_patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n v_patternUV /= u_scale;\n v_patternUV = graphicRotation * v_patternUV;\n v_patternUV += boxOrigin / patternBoxScale;\n v_patternUV -= boxOrigin;\n v_patternUV += .5;\n\n // ===================================================\n\n}`;\n\nfunction createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\nfunction createProgram(\n gl: WebGLRenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);\n\n if (!vertexShader || !fragmentShader) return null;\n\n const program = gl.createProgram();\n if (!program) return null;\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));\n gl.deleteProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return null;\n }\n\n // Clean up shaders after successful linking\n gl.detachShader(program, vertexShader);\n gl.detachShader(program, fragmentShader);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n return program;\n}\n\nconst defaultStyle = `@layer paper-shaders {\n :where([data-paper-shaders]) {\n isolation: isolate;\n position: relative;\n\n & canvas {\n contain: strict;\n display: block;\n position: absolute;\n inset: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n }\n }\n}`;\n\n/** A canvas element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if a canvas element is a ShaderCanvas */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/** Uniform types that we support to be auto-mapped into the fragment shader */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement;\n}\n\nexport interface ShaderMotionParams {\n speed?: number;\n frame?: number;\n}\n\nexport type ShaderPreset<T> = {\n name: string;\n params: Required<T>;\n};\n\nfunction isSafari() {\n const ua = navigator.userAgent.toLowerCase();\n return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('android');\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["vertexShaderSource"]
|
|
7
7
|
}
|
|
@@ -9,8 +9,8 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
9
9
|
* u_colorStroke - the stroke color
|
|
10
10
|
* u_dotSize (px) - the base dot radius
|
|
11
11
|
* u_strokeWidth (px) - the stroke (to be subtracted from u_dotSize)
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* u_gapX (px) - horizontal grid spacing
|
|
13
|
+
* u_gapY (px) - vertical grid spacing
|
|
14
14
|
* u_sizeRange (0 .. 1) - variety of dot size
|
|
15
15
|
* u_opacityRange(0 .. 1) - variety of dot opacity to be applied equally to fill and stroke
|
|
16
16
|
* u_shape - shape code (0 - circle, 1 - diamond, 2 - square, 3 - triangle)
|
|
@@ -21,8 +21,8 @@ export interface DotGridUniforms extends ShaderSizingUniforms {
|
|
|
21
21
|
u_colorFill: [number, number, number, number];
|
|
22
22
|
u_colorStroke: [number, number, number, number];
|
|
23
23
|
u_dotSize: number;
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
u_gapX: number;
|
|
25
|
+
u_gapY: number;
|
|
26
26
|
u_strokeWidth: number;
|
|
27
27
|
u_sizeRange: number;
|
|
28
28
|
u_opacityRange: number;
|
|
@@ -32,9 +32,9 @@ export interface DotGridParams extends ShaderSizingParams {
|
|
|
32
32
|
colorBack?: string;
|
|
33
33
|
colorFill?: string;
|
|
34
34
|
colorStroke?: string;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
size?: number;
|
|
36
|
+
gapX?: number;
|
|
37
|
+
gapY?: number;
|
|
38
38
|
strokeWidth?: number;
|
|
39
39
|
sizeRange?: number;
|
|
40
40
|
opacityRange?: number;
|
package/dist/shaders/dot-grid.js
CHANGED
|
@@ -12,8 +12,8 @@ uniform vec4 u_colorBack;
|
|
|
12
12
|
uniform vec4 u_colorFill;
|
|
13
13
|
uniform vec4 u_colorStroke;
|
|
14
14
|
uniform float u_dotSize;
|
|
15
|
-
uniform float
|
|
16
|
-
uniform float
|
|
15
|
+
uniform float u_gapX;
|
|
16
|
+
uniform float u_gapY;
|
|
17
17
|
uniform float u_strokeWidth;
|
|
18
18
|
uniform float u_sizeRange;
|
|
19
19
|
uniform float u_opacityRange;
|
|
@@ -38,13 +38,13 @@ void main() {
|
|
|
38
38
|
vec2 shape_uv = v_patternUV;
|
|
39
39
|
shape_uv += .5;
|
|
40
40
|
|
|
41
|
-
vec2 grid = fract(shape_uv / vec2(
|
|
42
|
-
vec2 grid_idx = floor(shape_uv / vec2(
|
|
41
|
+
vec2 grid = fract(shape_uv / vec2(u_gapX, u_gapY)) + 1e-4;
|
|
42
|
+
vec2 grid_idx = floor(shape_uv / vec2(u_gapX, u_gapY));
|
|
43
43
|
float sizeRandomizer = .5 + .8 * snoise(2. * vec2(grid_idx.x * 100., grid_idx.y));
|
|
44
44
|
float opacity_randomizer = .5 + .7 * snoise(2. * vec2(grid_idx.y, grid_idx.x));
|
|
45
45
|
|
|
46
46
|
vec2 center = vec2(0.5) - 1e-3;
|
|
47
|
-
vec2 p = (grid - center) * vec2(
|
|
47
|
+
vec2 p = (grid - center) * vec2(u_gapX, u_gapY);
|
|
48
48
|
|
|
49
49
|
float baseSize = u_dotSize * (1. - sizeRandomizer * u_sizeRange);
|
|
50
50
|
float strokeWidth = u_strokeWidth * (1. - sizeRandomizer * u_sizeRange);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/dot-grid.ts"],
|
|
4
|
-
"sourcesContent": ["import { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, declareSimplexNoise } from '../shader-utils';\n\n/**\n * Dot Grid Pattern\n * (the size parameters are set in pixels)\n *\n * Uniforms include:\n * u_colorBack - the background color\n * u_colorFill - the fill color\n * u_colorStroke - the stroke color\n * u_dotSize (px) - the base dot radius\n * u_strokeWidth (px) - the stroke (to be subtracted from u_dotSize)\n *
|
|
4
|
+
"sourcesContent": ["import { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, declareSimplexNoise } from '../shader-utils';\n\n/**\n * Dot Grid Pattern\n * (the size parameters are set in pixels)\n *\n * Uniforms include:\n * u_colorBack - the background color\n * u_colorFill - the fill color\n * u_colorStroke - the stroke color\n * u_dotSize (px) - the base dot radius\n * u_strokeWidth (px) - the stroke (to be subtracted from u_dotSize)\n * u_gapX (px) - horizontal grid spacing\n * u_gapY (px) - vertical grid spacing\n * u_sizeRange (0 .. 1) - variety of dot size\n * u_opacityRange(0 .. 1) - variety of dot opacity to be applied equally to fill and stroke\n * u_shape - shape code (0 - circle, 1 - diamond, 2 - square, 3 - triangle)\n */\nexport const dotGridFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFill;\nuniform vec4 u_colorStroke;\nuniform float u_dotSize;\nuniform float u_gapX;\nuniform float u_gapY;\nuniform float u_strokeWidth;\nuniform float u_sizeRange;\nuniform float u_opacityRange;\nuniform float u_shape;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareSimplexNoise}\n\nfloat polygon(vec2 p, float N, float rot) {\n float a = atan(p.x, p.y) + rot;\n float r = TWO_PI / float(N);\n\n return cos(floor(.5 + a / r) * r - a) * length(p);\n}\n\nvoid main() {\n \n vec2 shape_uv = v_patternUV;\n shape_uv += .5;\n\n vec2 grid = fract(shape_uv / vec2(u_gapX, u_gapY)) + 1e-4;\n vec2 grid_idx = floor(shape_uv / vec2(u_gapX, u_gapY));\n float sizeRandomizer = .5 + .8 * snoise(2. * vec2(grid_idx.x * 100., grid_idx.y));\n float opacity_randomizer = .5 + .7 * snoise(2. * vec2(grid_idx.y, grid_idx.x));\n\n vec2 center = vec2(0.5) - 1e-3;\n vec2 p = (grid - center) * vec2(u_gapX, u_gapY);\n\n float baseSize = u_dotSize * (1. - sizeRandomizer * u_sizeRange);\n float strokeWidth = u_strokeWidth * (1. - sizeRandomizer * u_sizeRange);\n\n float dist;\n if (u_shape < 0.5) {\n // Circle\n dist = length(p);\n } else if (u_shape < 1.5) {\n // Diamond\n strokeWidth *= 1.5;\n dist = polygon(1.5 * p, 4., .25 * PI);\n } else if (u_shape < 2.5) {\n // Square\n dist = polygon(1.03 * p, 4., 1e-3);\n } else {\n // Triangle\n strokeWidth *= 1.5;\n p = p * 2. - 1.;\n p *= .9;\n p.y -= .75 * baseSize;\n dist = polygon(p, 3., 1e-3);\n }\n\n float edgeWidth = fwidth(dist);\n float shapeOuter = smoothstep(baseSize + edgeWidth + strokeWidth, baseSize - edgeWidth + strokeWidth, dist);\n float shapeInner = smoothstep(baseSize + edgeWidth, baseSize - edgeWidth, dist);\n float stroke = clamp(shapeOuter - shapeInner, 0., 1.);\n\n float dot_opacity = max(0., 1. - opacity_randomizer * u_opacityRange);\n\n vec3 color = u_colorBack.rgb * u_colorBack.a;\n color = mix(color, u_colorFill.rgb, u_colorFill.a * dot_opacity * shapeInner);\n color = mix(color, u_colorStroke.rgb, u_colorStroke.a * dot_opacity * stroke);\n\n float opacity = u_colorBack.a;\n opacity += u_colorFill.a * shapeInner * dot_opacity;\n opacity += u_colorStroke.a * stroke * dot_opacity;\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DotGridUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFill: [number, number, number, number];\n u_colorStroke: [number, number, number, number];\n u_dotSize: number;\n u_gapX: number;\n u_gapY: number;\n u_strokeWidth: number;\n u_sizeRange: number;\n u_opacityRange: number;\n u_shape: (typeof DotGridShapes)[DotGridShape];\n}\n\nexport interface DotGridParams extends ShaderSizingParams {\n colorBack?: string;\n colorFill?: string;\n colorStroke?: string;\n size?: number;\n gapX?: number;\n gapY?: number;\n strokeWidth?: number;\n sizeRange?: number;\n opacityRange?: number;\n shape?: DotGridShape;\n}\n\nexport const DotGridShapes = {\n circle: 0,\n diamond: 1,\n square: 2,\n triangle: 3,\n} as const;\n\nexport type DotGridShape = keyof typeof DotGridShapes;\n"],
|
|
5
5
|
"mappings": ";;;;;AAAA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,2BAA2B;AAkBxC,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc3C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0Fd,MAAM,gBAAgB;AAAA,EAC3B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AACZ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -13,23 +13,23 @@ export declare const dotOrbitMeta: {
|
|
|
13
13
|
* - u_colors (vec4[]): Input RGBA colors
|
|
14
14
|
* - u_colorsCount (float): Number of active colors (`u_colors` length)
|
|
15
15
|
* - u_stepsPerColor (float): Discretization of the color transition
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
16
|
+
* - u_size (float, 0 .. 1): Base dot radius (relative to cell size)
|
|
17
|
+
* - u_sizeRange (float, 0 .. 1): Dot radius to vary between the cells
|
|
18
18
|
* - u_spreading (float, 0 .. 1): the distance each dot can move around the regular grid
|
|
19
19
|
*/
|
|
20
20
|
export declare const dotOrbitFragmentShader: string;
|
|
21
21
|
export interface DotOrbitUniforms extends ShaderSizingUniforms {
|
|
22
22
|
u_colors: vec4[];
|
|
23
23
|
u_colorsCount: number;
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
u_size: number;
|
|
25
|
+
u_sizeRange: number;
|
|
26
26
|
u_spreading: number;
|
|
27
27
|
u_stepsPerColor: number;
|
|
28
28
|
}
|
|
29
29
|
export interface DotOrbitParams extends ShaderSizingParams, ShaderMotionParams {
|
|
30
30
|
colors?: string[];
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
size?: number;
|
|
32
|
+
sizeRange?: number;
|
|
33
33
|
spreading?: number;
|
|
34
34
|
stepsPerColor?: number;
|
|
35
35
|
}
|
|
@@ -16,8 +16,8 @@ uniform float u_time;
|
|
|
16
16
|
uniform vec4 u_colors[${dotOrbitMeta.maxColorCount}];
|
|
17
17
|
uniform float u_colorsCount;
|
|
18
18
|
uniform float u_stepsPerColor;
|
|
19
|
-
uniform float
|
|
20
|
-
uniform float
|
|
19
|
+
uniform float u_size;
|
|
20
|
+
uniform float u_sizeRange;
|
|
21
21
|
uniform float u_spreading;
|
|
22
22
|
|
|
23
23
|
${sizingVariablesDeclaration}
|
|
@@ -71,7 +71,7 @@ void main() {
|
|
|
71
71
|
|
|
72
72
|
vec3 voronoi = voronoiShape(shape_uv, t) + 1e-4;
|
|
73
73
|
|
|
74
|
-
float radius = .25 * clamp(
|
|
74
|
+
float radius = .25 * clamp(u_size, 0., 1.) - .5 * clamp(u_sizeRange, 0., 1.) * voronoi[2];
|
|
75
75
|
float dist = voronoi[0];
|
|
76
76
|
float edgeWidth = fwidth(dist);
|
|
77
77
|
float dots = smoothstep(radius + edgeWidth, radius - edgeWidth, dist);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/dot-orbit.ts"],
|
|
4
|
-
"sourcesContent": ["import type { vec4 } from '../types';\nimport type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, declareRandom, declareRotate } from '../shader-utils';\n\nexport const dotOrbitMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Dot Pattern with dot moving around their grid position\n * The artwork by Ksenia Kondrashova\n * Renders a dot pattern with dot placed in the center of each cell of animated Voronoi diagram\n *\n * Uniforms include:\n * - u_colors (vec4[]): Input RGBA colors\n * - u_colorsCount (float): Number of active colors (`u_colors` length)\n * - u_stepsPerColor (float): Discretization of the color transition\n * -
|
|
4
|
+
"sourcesContent": ["import type { vec4 } from '../types';\nimport type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, declareRandom, declareRotate } from '../shader-utils';\n\nexport const dotOrbitMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Dot Pattern with dot moving around their grid position\n * The artwork by Ksenia Kondrashova\n * Renders a dot pattern with dot placed in the center of each cell of animated Voronoi diagram\n *\n * Uniforms include:\n * - u_colors (vec4[]): Input RGBA colors\n * - u_colorsCount (float): Number of active colors (`u_colors` length)\n * - u_stepsPerColor (float): Discretization of the color transition\n * - u_size (float, 0 .. 1): Base dot radius (relative to cell size)\n * - u_sizeRange (float, 0 .. 1): Dot radius to vary between the cells\n * - u_spreading (float, 0 .. 1): the distance each dot can move around the regular grid\n */\nexport const dotOrbitFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${dotOrbitMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_spreading;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareRandom}\n${declareRotate}\n\nvec2 random2(vec2 p) {\n return vec2(random(p), random(200. * p));\n}\n\nvec3 voronoiShape(vec2 uv, float time) {\n vec2 i_uv = floor(uv);\n vec2 f_uv = fract(uv);\n \n float spreading = .25 * clamp(u_spreading, 0., 1.);\n\n float minDist = 1.;\n vec2 randomizer = vec2(0.);\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 tileOffset = vec2(float(x), float(y));\n vec2 rand = random2(i_uv + tileOffset);\n vec2 cellCenter = vec2(.5 + 1e-4);\n cellCenter += spreading * cos(time + TWO_PI * rand);\n cellCenter -= .5;\n cellCenter = rotate(cellCenter, random(vec2(rand.x, rand.y)) + .1 * time);\n cellCenter += .5;\n float dist = length(tileOffset + cellCenter - f_uv);\n if (dist < minDist) {\n minDist = dist;\n randomizer = rand;\n }\n minDist = min(minDist, dist);\n }\n }\n\n return vec3(minDist, randomizer);\n}\n\nvoid main() {\n \n vec2 shape_uv = v_patternUV;\n shape_uv += .5;\n shape_uv *= .015;\n \n float t = u_time;\n\n vec3 voronoi = voronoiShape(shape_uv, t) + 1e-4;\n\n float radius = .25 * clamp(u_size, 0., 1.) - .5 * clamp(u_sizeRange, 0., 1.) * voronoi[2];\n float dist = voronoi[0];\n float edgeWidth = fwidth(dist);\n float dots = smoothstep(radius + edgeWidth, radius - edgeWidth, dist);\n\n float shape = voronoi[1];\n \n float mixer = shape * (u_colorsCount - 1.);\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n float steps = max(1., u_stepsPerColor);\n \n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${dotOrbitMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0.0, 1.0);\n localT = round(localT * steps) / steps;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localT = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localT = mixer - (u_colorsCount - 1.);\n }\n localT = round(localT * steps) / steps;\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localT);\n }\n\n gradient *= dots;\n vec3 color = gradient.rgb;\n float opacity = gradient.a;\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DotOrbitUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_size: number;\n u_sizeRange: number;\n u_spreading: number;\n u_stepsPerColor: number;\n}\n\nexport interface DotOrbitParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n size?: number;\n sizeRange?: number;\n spreading?: number;\n stepsPerColor?: number;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,eAAe,qBAAqB;AAEjD,MAAM,eAAe;AAAA,EAC1B,eAAe;AACjB;AAeO,MAAM,yBAAiC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAKtB,aAAa,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA0DS,aAAa,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -75,7 +75,8 @@ void main() {
|
|
|
75
75
|
sizeFrac *= fract(u_count);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
float shape = getBallShape(shape_uv, pos,
|
|
78
|
+
float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);
|
|
79
|
+
shape *= pow(u_size, .2);
|
|
79
80
|
shape = smoothstep(0., 1., shape);
|
|
80
81
|
|
|
81
82
|
totalColor += ballColor.rgb * shape;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/metaballs.ts"],
|
|
4
|
-
"sourcesContent": ["import type { vec4 } from '../types';\nimport type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, colorBandingFix } from '../shader-utils';\n\nexport const metaballsMeta = {\n maxColorCount: 8,\n maxBallsCount: 20,\n} as const;\n\n/**\n * Metaballs (circular shapes with gooey effect applied)\n * The artwork by Ksenia Kondrashova\n *\n * Uniforms include:\n * - uColors (vec4[]): Input RGBA colors\n * - uColorsCount (float): Number of active colors (`uColors` length)\n * - u_count (float)\n * - u_size (float)\n */\nexport const metaballsFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${metaballsMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_count;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat hash(float x) {\n return fract(sin(x) * 43758.5453123);\n}\nfloat noise(float x) {\n float i = floor(x);\n float f = fract(x);\n float u = f * f * (3.0 - 2.0 * f);\n return mix(hash(i), hash(i + 1.0), u);\n}\n\nfloat getBallShape(vec2 uv, vec2 c, float p) {\n float s = .5 * length(uv - c);\n s = 1. - clamp(s, 0., 1.);\n s = pow(s, p);\n return s;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n shape_uv += .5;\n\n float t = .2 * u_time + 1.;\n\n vec3 totalColor = vec3(0.);\n float totalShape = 0.;\n float totalOpacity = 0.;\n \n for (int i = 0; i < ${metaballsMeta.maxBallsCount}; i++) {\n if (i >= int(ceil(u_count))) break;\n \n float idxFract = float(i) / float(${metaballsMeta.maxBallsCount});\n float angle = TWO_PI * idxFract;\n \n float speed = 1. - .2 * idxFract;\n float noiseX = noise(angle * 10. + float(i) + t * speed);\n float noiseY = noise(angle * 20. + float(i) - t * speed);\n \n vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noiseX, noiseY) - .5);\n \n int safeIndex = i % int(u_colorsCount + 0.5);\n vec4 ballColor = u_colors[safeIndex];\n ballColor.rgb *= ballColor.a;\n\n float sizeFrac = 1.;\n if (float(i) > floor(u_count - 1.)) {\n sizeFrac *= fract(u_count);\n }\n\n float shape = getBallShape(shape_uv, pos,
|
|
5
|
-
"mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,uBAAuB;AAEpC,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,eAAe;AACjB;AAYO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAKvB,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA8Ba,cAAc,aAAa;AAAA;AAAA;AAAA,wCAGX,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { vec4 } from '../types';\nimport type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, colorBandingFix } from '../shader-utils';\n\nexport const metaballsMeta = {\n maxColorCount: 8,\n maxBallsCount: 20,\n} as const;\n\n/**\n * Metaballs (circular shapes with gooey effect applied)\n * The artwork by Ksenia Kondrashova\n *\n * Uniforms include:\n * - uColors (vec4[]): Input RGBA colors\n * - uColorsCount (float): Number of active colors (`uColors` length)\n * - u_count (float)\n * - u_size (float)\n */\nexport const metaballsFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${metaballsMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_count;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat hash(float x) {\n return fract(sin(x) * 43758.5453123);\n}\nfloat noise(float x) {\n float i = floor(x);\n float f = fract(x);\n float u = f * f * (3.0 - 2.0 * f);\n return mix(hash(i), hash(i + 1.0), u);\n}\n\nfloat getBallShape(vec2 uv, vec2 c, float p) {\n float s = .5 * length(uv - c);\n s = 1. - clamp(s, 0., 1.);\n s = pow(s, p);\n return s;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n shape_uv += .5;\n\n float t = .2 * u_time + 1.;\n\n vec3 totalColor = vec3(0.);\n float totalShape = 0.;\n float totalOpacity = 0.;\n \n for (int i = 0; i < ${metaballsMeta.maxBallsCount}; i++) {\n if (i >= int(ceil(u_count))) break;\n \n float idxFract = float(i) / float(${metaballsMeta.maxBallsCount});\n float angle = TWO_PI * idxFract;\n \n float speed = 1. - .2 * idxFract;\n float noiseX = noise(angle * 10. + float(i) + t * speed);\n float noiseY = noise(angle * 20. + float(i) - t * speed);\n \n vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noiseX, noiseY) - .5);\n \n int safeIndex = i % int(u_colorsCount + 0.5);\n vec4 ballColor = u_colors[safeIndex];\n ballColor.rgb *= ballColor.a;\n\n float sizeFrac = 1.;\n if (float(i) > floor(u_count - 1.)) {\n sizeFrac *= fract(u_count);\n }\n\n float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);\n shape *= pow(u_size, .2);\n shape = smoothstep(0., 1., shape);\n\n totalColor += ballColor.rgb * shape;\n totalShape += shape;\n totalOpacity += ballColor.a * shape;\n }\n\n totalColor /= max(totalShape, 1e-4);\n totalOpacity /= max(totalShape, 1e-4);\n\n float edge_width = fwidth(totalShape);\n float finalShape = smoothstep(.4, .4 + edge_width, totalShape);\n\n vec3 color = totalColor * finalShape;\n float opacity = totalOpacity * finalShape;\n\n if (opacity < .005) {\n discard;\n }\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface MetaballsUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_count: number;\n u_size: number;\n}\n\nexport interface MetaballsParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n count?: number;\n size?: number;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,uBAAuB;AAEpC,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,eAAe;AACjB;AAYO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAKvB,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA8Ba,cAAc,aAAa;AAAA;AAAA;AAAA,wCAGX,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwC/D,eAAe;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/shaders/spiral.d.ts
CHANGED
|
@@ -11,12 +11,12 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
11
11
|
* u_offsetY - up / down pan
|
|
12
12
|
* u_color1 - the first color used in the spiral (stroke)
|
|
13
13
|
* u_color2 - the second color used in the spiral (back)
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* u_density (0 .. 1) - the spacing of the spiral arms
|
|
15
|
+
* u_distortion (0 .. 1) - adds a wavy distortion effect to the spiral arms
|
|
16
16
|
* u_strokeWidth (0 .. 1) - defines the thickness of the spiral lines.
|
|
17
17
|
* u_strokeCap (0 .. 1) - adjusts the fading of the spiral edges.
|
|
18
18
|
* u_strokeTaper (0 .. 1) - controls the tapering effect along the spiral arms.
|
|
19
|
-
*
|
|
19
|
+
* u_noiseFrequency - frequency of the noise applied to the spiral.
|
|
20
20
|
* u_noisePower (0 .. 1) - strength of the noise effect.
|
|
21
21
|
* u_softness - softens the edges of the spiral for a smoother appearance.
|
|
22
22
|
*/
|
|
@@ -24,24 +24,24 @@ export declare const spiralFragmentShader: string;
|
|
|
24
24
|
export interface SpiralUniforms extends ShaderSizingUniforms {
|
|
25
25
|
u_color1: [number, number, number, number];
|
|
26
26
|
u_color2: [number, number, number, number];
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
u_density: number;
|
|
28
|
+
u_distortion: number;
|
|
29
29
|
u_strokeWidth: number;
|
|
30
30
|
u_strokeTaper: number;
|
|
31
31
|
u_strokeCap: number;
|
|
32
|
-
|
|
32
|
+
u_noiseFrequency: number;
|
|
33
33
|
u_noisePower: number;
|
|
34
34
|
u_softness: number;
|
|
35
35
|
}
|
|
36
36
|
export interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {
|
|
37
37
|
color1?: string;
|
|
38
38
|
color2?: string;
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
density?: number;
|
|
40
|
+
distortion?: number;
|
|
41
41
|
strokeWidth?: number;
|
|
42
42
|
strokeTaper?: number;
|
|
43
43
|
strokeCap?: number;
|
|
44
|
-
|
|
44
|
+
noiseFrequency?: number;
|
|
45
45
|
noisePower?: number;
|
|
46
46
|
softness?: number;
|
|
47
47
|
}
|
package/dist/shaders/spiral.js
CHANGED
|
@@ -12,13 +12,13 @@ uniform float u_time;
|
|
|
12
12
|
|
|
13
13
|
uniform vec4 u_color1;
|
|
14
14
|
uniform vec4 u_color2;
|
|
15
|
-
uniform float
|
|
16
|
-
uniform float
|
|
15
|
+
uniform float u_density;
|
|
16
|
+
uniform float u_distortion;
|
|
17
17
|
uniform float u_strokeWidth;
|
|
18
18
|
uniform float u_strokeCap;
|
|
19
19
|
uniform float u_strokeTaper;
|
|
20
20
|
|
|
21
|
-
uniform float
|
|
21
|
+
uniform float u_noiseFrequency;
|
|
22
22
|
uniform float u_noisePower;
|
|
23
23
|
uniform float u_softness;
|
|
24
24
|
|
|
@@ -38,18 +38,18 @@ void main() {
|
|
|
38
38
|
float angle = atan(shape_uv.y, shape_uv.x) - 2. * t;
|
|
39
39
|
float angle_norm = angle / TWO_PI;
|
|
40
40
|
|
|
41
|
-
angle_norm += .125 * u_noisePower * snoise(.5 *
|
|
41
|
+
angle_norm += .125 * u_noisePower * snoise(.5 * u_noiseFrequency * shape_uv);
|
|
42
42
|
|
|
43
|
-
float offset = pow(l, 1. - clamp(
|
|
43
|
+
float offset = pow(l, 1. - clamp(u_density, 0., 1.)) + angle_norm;
|
|
44
44
|
|
|
45
45
|
float stripe_map = fract(offset);
|
|
46
46
|
stripe_map -= .5 * u_strokeTaper * l;
|
|
47
47
|
|
|
48
|
-
stripe_map += .25 * u_noisePower * snoise(
|
|
48
|
+
stripe_map += .25 * u_noisePower * snoise(u_noiseFrequency * shape_uv);
|
|
49
49
|
|
|
50
50
|
float shape = 2. * abs(stripe_map - .5);
|
|
51
51
|
|
|
52
|
-
shape *= (1. +
|
|
52
|
+
shape *= (1. + u_distortion * sin(4. * l - t) * cos(PI + l + t));
|
|
53
53
|
|
|
54
54
|
float stroke_width = clamp(u_strokeWidth, fwidth(l), 1. - fwidth(l));
|
|
55
55
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/spiral.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declareSimplexNoise, declarePI, colorBandingFix } from '../shader-utils';\n\n/**\n * Spiral shape by Ksenia Kondrashova\n * Generates a dynamic spiral shape with configurable parameters\n *\n * Uniforms include:\n *\n * u_scale - controls the overall scale of the spiral (u_scale = 1 makes it fit the viewport height)\n * u_offsetX - left / right pan\n * u_offsetY - up / down pan\n * u_color1 - the first color used in the spiral (stroke)\n * u_color2 - the second color used in the spiral (back)\n *
|
|
4
|
+
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declareSimplexNoise, declarePI, colorBandingFix } from '../shader-utils';\n\n/**\n * Spiral shape by Ksenia Kondrashova\n * Generates a dynamic spiral shape with configurable parameters\n *\n * Uniforms include:\n *\n * u_scale - controls the overall scale of the spiral (u_scale = 1 makes it fit the viewport height)\n * u_offsetX - left / right pan\n * u_offsetY - up / down pan\n * u_color1 - the first color used in the spiral (stroke)\n * u_color2 - the second color used in the spiral (back)\n * u_density (0 .. 1) - the spacing of the spiral arms\n * u_distortion (0 .. 1) - adds a wavy distortion effect to the spiral arms\n * u_strokeWidth (0 .. 1) - defines the thickness of the spiral lines.\n * u_strokeCap (0 .. 1) - adjusts the fading of the spiral edges.\n * u_strokeTaper (0 .. 1) - controls the tapering effect along the spiral arms.\n * u_noiseFrequency - frequency of the noise applied to the spiral.\n * u_noisePower (0 .. 1) - strength of the noise effect.\n * u_softness - softens the edges of the spiral for a smoother appearance.\n */\nexport const spiralFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_time;\n\nuniform vec4 u_color1;\nuniform vec4 u_color2;\nuniform float u_density;\nuniform float u_distortion;\nuniform float u_strokeWidth;\nuniform float u_strokeCap;\nuniform float u_strokeTaper;\n\nuniform float u_noiseFrequency;\nuniform float u_noisePower;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareSimplexNoise}\n\nvoid main() {\n vec2 shape_uv = v_patternUV * .02;\n\n float t = u_time;\n\n float l = length(shape_uv);\n float angle = atan(shape_uv.y, shape_uv.x) - 2. * t;\n float angle_norm = angle / TWO_PI;\n\n angle_norm += .125 * u_noisePower * snoise(.5 * u_noiseFrequency * shape_uv);\n\n float offset = pow(l, 1. - clamp(u_density, 0., 1.)) + angle_norm;\n\n float stripe_map = fract(offset);\n stripe_map -= .5 * u_strokeTaper * l;\n\n stripe_map += .25 * u_noisePower * snoise(u_noiseFrequency * shape_uv);\n\n float shape = 2. * abs(stripe_map - .5);\n\n shape *= (1. + u_distortion * sin(4. * l - t) * cos(PI + l + t));\n\n float stroke_width = clamp(u_strokeWidth, fwidth(l), 1. - fwidth(l));\n\n float edge_width = min(fwidth(l), fwidth(offset));\n\n float mid = 1. - smoothstep(.0, .9, l);\n mid = pow(mid, 2.);\n shape -= .5 * u_strokeCap * mid;\n\n shape = smoothstep(stroke_width - edge_width - u_softness, stroke_width + edge_width + u_softness, shape);\n\n vec3 color = mix(u_color1.rgb * u_color1.a, u_color2.rgb * u_color2.a, shape);\n float opacity = mix(u_color1.a, u_color2.a, shape);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SpiralUniforms extends ShaderSizingUniforms {\n u_color1: [number, number, number, number];\n u_color2: [number, number, number, number];\n u_density: number;\n u_distortion: number;\n u_strokeWidth: number;\n u_strokeTaper: number;\n u_strokeCap: number;\n u_noiseFrequency: number;\n u_noisePower: number;\n u_softness: number;\n}\n\nexport interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {\n color1?: string;\n color2?: string;\n density?: number;\n distortion?: number;\n strokeWidth?: number;\n strokeTaper?: number;\n strokeCap?: number;\n noiseFrequency?: number;\n noisePower?: number;\n softness?: number;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,qBAAqB,WAAW,uBAAuB;AAsBzD,MAAM,uBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB1C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqCjB,eAAe;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/shaders/swirl.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface SwirlUniforms extends ShaderSizingUniforms {
|
|
|
13
13
|
u_bandCount: number;
|
|
14
14
|
u_twist: number;
|
|
15
15
|
u_softness: number;
|
|
16
|
-
|
|
16
|
+
u_noiseFrequency: number;
|
|
17
17
|
u_noisePower: number;
|
|
18
18
|
}
|
|
19
19
|
export interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {
|
|
@@ -21,6 +21,6 @@ export interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {
|
|
|
21
21
|
bandCount?: number;
|
|
22
22
|
twist?: number;
|
|
23
23
|
softness?: number;
|
|
24
|
-
|
|
24
|
+
noiseFrequency?: number;
|
|
25
25
|
noisePower?: number;
|
|
26
26
|
}
|
package/dist/shaders/swirl.js
CHANGED
|
@@ -19,7 +19,7 @@ uniform float u_bandCount;
|
|
|
19
19
|
uniform float u_twist;
|
|
20
20
|
uniform float u_softness;
|
|
21
21
|
uniform float u_noisePower;
|
|
22
|
-
uniform float
|
|
22
|
+
uniform float u_noiseFrequency;
|
|
23
23
|
|
|
24
24
|
${sizingVariablesDeclaration}
|
|
25
25
|
|
|
@@ -44,7 +44,7 @@ void main() {
|
|
|
44
44
|
|
|
45
45
|
float shape = fract(offset);
|
|
46
46
|
shape = 1. - abs(2. * shape - 1.);
|
|
47
|
-
shape += u_noisePower * snoise(pow(
|
|
47
|
+
shape += u_noisePower * snoise(pow(u_noiseFrequency, 2.) * shape_uv);
|
|
48
48
|
|
|
49
49
|
float mid = smoothstep(.2, .4, pow(l, twist));
|
|
50
50
|
shape = mix(0., shape, mid);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/swirl.ts"],
|
|
4
|
-
"sourcesContent": ["import type { vec4 } from '../types';\nimport type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declareSimplexNoise, declarePI, declareRotate, colorBandingFix } from '../shader-utils';\n\nexport const swirlMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n */\nexport const swirlFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${swirlMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_bandCount;\nuniform float u_twist;\nuniform float u_softness;\nuniform float u_noisePower;\nuniform float
|
|
4
|
+
"sourcesContent": ["import type { vec4 } from '../types';\nimport type { ShaderMotionParams } from '../shader-mount';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declareSimplexNoise, declarePI, declareRotate, colorBandingFix } from '../shader-utils';\n\nexport const swirlMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n */\nexport const swirlFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${swirlMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_bandCount;\nuniform float u_twist;\nuniform float u_softness;\nuniform float u_noisePower;\nuniform float u_noiseFrequency;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareSimplexNoise}\n${declareRotate}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n \n float l = length(shape_uv);\n\n float t = u_time;\n\n float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t;\n float angle_norm = angle / TWO_PI; \n \n float twist = 3. * clamp(u_twist, 0., 1.);\n float offset = pow(l, -twist) + angle_norm;\n \n float shape = fract(offset);\n shape = 1. - abs(2. * shape - 1.);\n shape += u_noisePower * snoise(pow(u_noiseFrequency, 2.) * shape_uv);\n\n float mid = smoothstep(.2, .4, pow(l, twist));\n shape = mix(0., shape, mid);\n \n float mixer = shape * (u_colorsCount - 1.);\n float softness = u_softness + (.1 + .012 * u_colorsCount) * smoothstep(.6, .2, pow(l, twist));\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${swirlMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n \n float localT = clamp(mixer - float(i - 1), 0., 1.); \n localT = smoothstep(.5 - .5 * u_softness, .5 + .5 * u_softness, localT);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n \n vec3 color = gradient.rgb;\n float opacity = gradient.a;\n \n ${colorBandingFix}\n \n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SwirlUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_bandCount: number;\n u_twist: number;\n u_softness: number;\n u_noiseFrequency: number;\n u_noisePower: number;\n}\n\nexport interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n bandCount?: number;\n twist?: number;\n softness?: number;\n noiseFrequency?: number;\n noisePower?: number;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,qBAAqB,WAAW,eAAe,uBAAuB;AAExE,MAAM,YAAY;AAAA,EACvB,eAAe;AACjB;AAIO,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA,wBAKnB,UAAU,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA2BS,UAAU,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAc3C,eAAe;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/shaders/waves.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
14
14
|
* u_frequency - the wave frequency
|
|
15
15
|
* u_amplitude - the wave amplitude
|
|
16
16
|
* u_spacing - the density of pattern lines
|
|
17
|
-
*
|
|
17
|
+
* u_proportion (0 ... 1) - the proportion of stroke width to the pattern step
|
|
18
18
|
* u_softness (0 ... 1) - the blur applied to the lines edges
|
|
19
19
|
*/
|
|
20
20
|
export declare const wavesFragmentShader: string;
|
|
@@ -25,7 +25,7 @@ export interface WavesUniforms extends ShaderSizingUniforms {
|
|
|
25
25
|
u_frequency: number;
|
|
26
26
|
u_amplitude: number;
|
|
27
27
|
u_spacing: number;
|
|
28
|
-
|
|
28
|
+
u_proportion: number;
|
|
29
29
|
u_softness: number;
|
|
30
30
|
}
|
|
31
31
|
export interface WavesParams extends ShaderSizingParams {
|
|
@@ -36,6 +36,6 @@ export interface WavesParams extends ShaderSizingParams {
|
|
|
36
36
|
frequency?: number;
|
|
37
37
|
amplitude?: number;
|
|
38
38
|
spacing?: number;
|
|
39
|
-
|
|
39
|
+
proportion?: number;
|
|
40
40
|
softness?: number;
|
|
41
41
|
}
|
package/dist/shaders/waves.js
CHANGED
|
@@ -16,7 +16,7 @@ uniform float u_shape;
|
|
|
16
16
|
uniform float u_frequency;
|
|
17
17
|
uniform float u_amplitude;
|
|
18
18
|
uniform float u_spacing;
|
|
19
|
-
uniform float
|
|
19
|
+
uniform float u_proportion;
|
|
20
20
|
uniform float u_softness;
|
|
21
21
|
|
|
22
22
|
${sizingVariablesDeclaration}
|
|
@@ -45,7 +45,7 @@ void main() {
|
|
|
45
45
|
|
|
46
46
|
float edge_width = .02 / (1. + abs(shape)) * (.001 + u_scale);
|
|
47
47
|
edge_width += .5 * max(0., u_softness);
|
|
48
|
-
float dc = clamp(
|
|
48
|
+
float dc = clamp(u_proportion, 0., 1.);
|
|
49
49
|
float t = smoothstep(dc - edge_width, dc + edge_width, shape);
|
|
50
50
|
|
|
51
51
|
vec3 color = mix(u_color1.rgb * u_color1.a, u_color2.rgb * u_color2.a, t);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/waves.ts"],
|
|
4
|
-
"sourcesContent": ["import { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, declareRotate } from '../shader-utils';\n\n/**\n * Waves static pattern on the transparent background\n *\n * Uniforms include:\n * u_color1 - the first color\n * u_color2 - the second color\n * u_shape (0 ... 3) - the line shaping coefficient, non-integer\n values allowed and produce mixed shapes\n - u_shape = 0 is zigzag\n - u_shape = 1 is perfect sine wave\n - u_shape = 2 is irregular wave #1\n - u_shape = 3 is irregular wave #2\n * u_frequency - the wave frequency\n * u_amplitude - the wave amplitude\n * u_spacing - the density of pattern lines\n *
|
|
4
|
+
"sourcesContent": ["import { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing';\nimport { declarePI, declareRotate } from '../shader-utils';\n\n/**\n * Waves static pattern on the transparent background\n *\n * Uniforms include:\n * u_color1 - the first color\n * u_color2 - the second color\n * u_shape (0 ... 3) - the line shaping coefficient, non-integer\n values allowed and produce mixed shapes\n - u_shape = 0 is zigzag\n - u_shape = 1 is perfect sine wave\n - u_shape = 2 is irregular wave #1\n - u_shape = 3 is irregular wave #2\n * u_frequency - the wave frequency\n * u_amplitude - the wave amplitude\n * u_spacing - the density of pattern lines\n * u_proportion (0 ... 1) - the proportion of stroke width to the pattern step\n * u_softness (0 ... 1) - the blur applied to the lines edges\n */\nexport const wavesFragmentShader: string = `#version 300 es\nprecision highp float;\n\nuniform float u_scale;\n\nuniform vec4 u_color1;\nuniform vec4 u_color2;\nuniform float u_shape;\nuniform float u_frequency;\nuniform float u_amplitude;\nuniform float u_spacing;\nuniform float u_proportion;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareRotate}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .05;\n\n float wave = .5 * cos(shape_uv.x * u_frequency * TWO_PI);\n float zigzag = 2. * abs(fract(shape_uv.x * u_frequency) - .5);\n float irregular = sin(shape_uv.x * .25 * u_frequency * TWO_PI) * cos(shape_uv.x * u_frequency * TWO_PI);\n float irregular2 = .75 * (sin(shape_uv.x * u_frequency * TWO_PI) + .5 * cos(shape_uv.x * .5 * u_frequency * TWO_PI));\n\n float offset = mix(zigzag, wave, smoothstep(0., 1., u_shape));\n offset = mix(offset, irregular, smoothstep(1., 2., u_shape));\n offset = mix(offset, irregular2, smoothstep(2., 3., u_shape));\n offset *= 2. * u_amplitude;\n\n float spacing = .02 + .98 * u_spacing;\n float shape = .5 + .5 * sin((shape_uv.y + offset) * PI / spacing);\n\n float edge_width = .02 / (1. + abs(shape)) * (.001 + u_scale);\n edge_width += .5 * max(0., u_softness);\n float dc = clamp(u_proportion, 0., 1.);\n float t = smoothstep(dc - edge_width, dc + edge_width, shape);\n\n vec3 color = mix(u_color1.rgb * u_color1.a, u_color2.rgb * u_color2.a, t);\n float opacity = mix(u_color1.a, u_color2.a, t);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WavesUniforms extends ShaderSizingUniforms {\n u_color1: [number, number, number, number];\n u_color2: [number, number, number, number];\n u_shape: number;\n u_frequency: number;\n u_amplitude: number;\n u_spacing: number;\n u_proportion: number;\n u_softness: number;\n}\n\nexport interface WavesParams extends ShaderSizingParams {\n color1?: string;\n color2?: string;\n rotation?: number;\n shape?: number;\n frequency?: number;\n amplitude?: number;\n spacing?: number;\n proportion?: number;\n softness?: number;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;AAAA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,qBAAqB;AAoBlC,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAczC,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|