@paper-design/shaders 0.0.46 → 0.0.47

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.
@@ -427,6 +427,7 @@ const defaultStyle = `@layer paper-shaders {
427
427
  width: 100%;
428
428
  height: 100%;
429
429
  border-radius: inherit;
430
+ corner-shape: inherit;
430
431
  }
431
432
  }
432
433
  }`;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/shader-mount.ts"],
4
- "sourcesContent": ["import { vertexShaderSource } from './vertex-shader.js';\n\nconst DEFAULT_MAX_PIXEL_COUNT: number = 1920 * 1080 * 4;\n\nexport class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGL2RenderingContext;\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 currentFrame = 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 private uniformCache: Record<string, unknown> = {};\n private textureUnitMap: Map<string, number> = new Map();\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 = DEFAULT_MAX_PIXEL_COUNT\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-shader]')) {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shader', '');\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.currentFrame = 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-shader', '');\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}AspectRatio`;\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 or the max pixel count changes 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 // - visualViewport.width is affected by hard scrollbars, so they need to be added manually\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n const innerWidth = visualViewport\n ? visualViewport.scale * visualViewport.width + scrollbarWidth\n : 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.currentFrame += 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.currentFrame * 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\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 // Get texture unit\n if (!this.textureUnitMap.has(uniformName)) {\n this.textureUnitMap.set(uniformName, this.textureUnitMap.size);\n }\n const textureUnit = this.textureUnitMap.get(uniformName)!;\n // Activate correct texture unit before creating the texture\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\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.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\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 this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}AspectRatio`;\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 /** Utility: recursive equality test for all the uniforms */\n private areUniformValuesEqual = (a: any, b: any): boolean => {\n if (a === b) return true;\n if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {\n return a.every((val, i) => this.areUniformValuesEqual(val, (b as any)[i]));\n }\n return false;\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 // Grab the value to use in the uniform cache\n let cacheValue: ShaderMountUniforms[keyof ShaderMountUniforms] | string = value;\n if (value instanceof HTMLImageElement) {\n // Images use their src for the cache value to save memory\n cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`;\n }\n\n // Check if the uniform value has changed and, if not, bail early to avoid extra work\n if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return;\n // Update the uniform cache if we are still here\n this.uniformCache[key] = cacheValue;\n\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 // May happen on the server for SSR when undefined images are passed in\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 getCurrentFrame = (): number => {\n return this.currentFrame;\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.currentFrame = 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 /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */\n public setMaxPixelCount = (newMaxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT): void => {\n this.maxPixelCount = newMaxPixelCount;\n\n this.handleResize();\n };\n\n /** Set the minimum pixel ratio for the shader */\n public setMinPixelRatio = (newMinPixelRatio: number = 2): void => {\n this.minPixelRatio = newMinPixelRatio;\n\n this.handleResize();\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.setUniformValues(newUniforms);\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\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\nfunction createShader(gl: WebGL2RenderingContext, 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: WebGL2RenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);\n const precision = format ? format.precision : null;\n // MEDIUM_FLOAT precision can be 10, 16 or 23 bits depending on device;\n // Shaders fail on 10 bit (and 16 bit is hard to test) => we force 23-bit by switching to highp\n if (precision && precision < 23) {\n vertexShaderSource = vertexShaderSource.replace(/precision\\s+(lowp|mediump)\\s+float;/g, 'precision highp float;');\n fragmentShaderSource = fragmentShaderSource\n .replace(/precision\\s+(lowp|mediump)\\s+float/g, 'precision highp float')\n .replace(/\\b(uniform|varying|attribute)\\s+(lowp|mediump)\\s+(\\w+)/g, '$1 highp $3');\n }\n\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-shader]) {\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 border-radius: inherit;\n }\n }\n}`;\n\n/** The parent `<div>` element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if an element is a Paper shader element */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/**\n * Uniform types that we support to be auto-mapped into the fragment shader\n *\n * We accept undefined as a convenience for server rendering, when some things may be undefined\n * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering\n */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;\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
- "mappings": "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",
4
+ "sourcesContent": ["import { vertexShaderSource } from './vertex-shader.js';\n\nconst DEFAULT_MAX_PIXEL_COUNT: number = 1920 * 1080 * 4;\n\nexport class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGL2RenderingContext;\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 currentFrame = 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 private uniformCache: Record<string, unknown> = {};\n private textureUnitMap: Map<string, number> = new Map();\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 = DEFAULT_MAX_PIXEL_COUNT\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-shader]')) {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shader', '');\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.currentFrame = 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-shader', '');\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}AspectRatio`;\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 or the max pixel count changes 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 // - visualViewport.width is affected by hard scrollbars, so they need to be added manually\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n const innerWidth = visualViewport\n ? visualViewport.scale * visualViewport.width + scrollbarWidth\n : 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.currentFrame += 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.currentFrame * 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 // Get texture unit\n if (!this.textureUnitMap.has(uniformName)) {\n this.textureUnitMap.set(uniformName, this.textureUnitMap.size);\n }\n const textureUnit = this.textureUnitMap.get(uniformName)!;\n // Activate correct texture unit before creating the texture\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\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.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\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 this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}AspectRatio`;\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 /** Utility: recursive equality test for all the uniforms */\n private areUniformValuesEqual = (a: any, b: any): boolean => {\n if (a === b) return true;\n if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {\n return a.every((val, i) => this.areUniformValuesEqual(val, (b as any)[i]));\n }\n return false;\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 // Grab the value to use in the uniform cache\n let cacheValue: ShaderMountUniforms[keyof ShaderMountUniforms] | string = value;\n if (value instanceof HTMLImageElement) {\n // Images use their src for the cache value to save memory\n cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`;\n }\n\n // Check if the uniform value has changed and, if not, bail early to avoid extra work\n if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return;\n // Update the uniform cache if we are still here\n this.uniformCache[key] = cacheValue;\n\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 // May happen on the server for SSR when undefined images are passed in\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 getCurrentFrame = (): number => {\n return this.currentFrame;\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.currentFrame = 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 /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */\n public setMaxPixelCount = (newMaxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT): void => {\n this.maxPixelCount = newMaxPixelCount;\n\n this.handleResize();\n };\n\n /** Set the minimum pixel ratio for the shader */\n public setMinPixelRatio = (newMinPixelRatio: number = 2): void => {\n this.minPixelRatio = newMinPixelRatio;\n\n this.handleResize();\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.setUniformValues(newUniforms);\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\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\nfunction createShader(gl: WebGL2RenderingContext, 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: WebGL2RenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);\n const precision = format ? format.precision : null;\n // MEDIUM_FLOAT precision can be 10, 16 or 23 bits depending on device;\n // Shaders fail on 10 bit (and 16 bit is hard to test) => we force 23-bit by switching to highp\n if (precision && precision < 23) {\n vertexShaderSource = vertexShaderSource.replace(/precision\\s+(lowp|mediump)\\s+float;/g, 'precision highp float;');\n fragmentShaderSource = fragmentShaderSource\n .replace(/precision\\s+(lowp|mediump)\\s+float/g, 'precision highp float')\n .replace(/\\b(uniform|varying|attribute)\\s+(lowp|mediump)\\s+(\\w+)/g, '$1 highp $3');\n }\n\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-shader]) {\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 border-radius: inherit;\n corner-shape: inherit;\n }\n }\n}`;\n\n/** The parent `<div>` element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if an element is a Paper shader element */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/**\n * Uniform types that we support to be auto-mapped into the fragment shader\n *\n * We accept undefined as a convenience for server rendering, when some things may be undefined\n * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering\n */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;\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
+ "mappings": "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",
6
6
  "names": ["vertexShaderSource"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  export declare const sizingVariablesDeclaration = "\nin vec2 v_objectUV;\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_patternUV;\nin vec2 v_imageUV;";
2
2
  export declare const sizingDebugVariablesDeclaration = "\nin vec2 v_objectBoxSize;\nin vec2 v_objectHelperBox;\nin vec2 v_responsiveBoxSize;\nin vec2 v_responsiveHelperBox;\nin vec2 v_patternBoxSize;\nin vec2 v_patternHelperBox;";
3
3
  export declare const sizingUniformsDeclaration = "\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;";
4
- export declare const sizingUV = "\n\n vec2 uv = gl_FragCoord.xy / u_resolution.xy;\n #ifdef USE_PIXELIZATION\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUv = gl_FragCoord.xy;\n pxSizeUv -= .5 * u_resolution;\n pxSizeUv /= pxSize;\n uv = floor(pxSizeUv) * pxSize / u_resolution.xy; \n uv += .5;\n #endif\n uv -= .5;\n\n \n // ===================================================\n // sizing params shared between objects and patterns\n \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 objects (graphics with fixed ratio)\n\n #ifdef USE_OBJECT_SIZING\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 vec2 objectBoxSize = vec2(0.);\n // fit = none\n objectBoxSize.x = fixedRatio * min(fixedRatioBoxGivenSize.x / fixedRatio, fixedRatioBoxGivenSize.y);\n if (u_fit == 1.) { // fit = contain\n objectBoxSize.x = fixedRatio * min(maxBoxSize.x / fixedRatio, maxBoxSize.y);\n } else if (u_fit == 2.) { // fit = cover\n objectBoxSize.x = fixedRatio * max(maxBoxSize.x / fixedRatio, maxBoxSize.y);\n }\n objectBoxSize.y = objectBoxSize.x / fixedRatio;\n vec2 objectWorldScale = u_resolution.xy / objectBoxSize;\n \n #ifdef ADD_HELPERS\n vec2 objectHelperBox = gl_FragCoord.xy / u_resolution.xy;\n objectHelperBox -= .5;\n objectHelperBox *= objectWorldScale;\n objectHelperBox += boxOrigin * (objectWorldScale - 1.); \n #endif\n \n vec2 objectUV = uv;\n objectUV *= objectWorldScale;\n objectUV += boxOrigin * (objectWorldScale - 1.);\n objectUV += vec2(-u_offsetX, u_offsetY);\n objectUV /= u_scale;\n objectUV = graphicRotation * objectUV;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for patterns (graphics respecting u_worldWidth / u_worldHeight ratio)\n \n #ifdef USE_PATTERN_SIZING\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 vec2 patternBoxSize = vec2(0.);\n // fit = none\n patternBoxSize.x = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n float patternWorldNoFitBoxWidth = patternBoxSize.x;\n if (u_fit == 1.) { // fit = contain\n patternBoxSize.x = patternBoxRatio * min(maxBoxSize.x / patternBoxRatio, maxBoxSize.y);\n } else if (u_fit == 2.) { // fit = cover\n patternBoxSize.x = patternBoxRatio * max(maxBoxSize.x / patternBoxRatio, maxBoxSize.y);\n }\n patternBoxSize.y = patternBoxSize.x / patternBoxRatio;\n vec2 patternWorldScale = u_resolution.xy / patternBoxSize;\n \n #ifdef ADD_HELPERS \n vec2 patternHelperBox = gl_FragCoord.xy / u_resolution.xy;\n patternHelperBox -= .5;\n patternHelperBox *= patternWorldScale;\n patternHelperBox += boxOrigin * (patternWorldScale - 1.); \n #endif\n \n vec2 patternUV = uv;\n patternUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;\n patternUV += boxOrigin;\n patternUV -= boxOrigin / patternWorldScale;\n patternUV *= u_resolution.xy;\n patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n patternUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);\n }\n patternUV /= u_scale;\n patternUV = graphicRotation * patternUV;\n patternUV += boxOrigin / patternWorldScale;\n patternUV -= boxOrigin;\n patternUV += .5;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for image filters\n \n #ifdef USE_IMAGE_SIZING\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n \n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n #endif\n";
4
+ export declare const sizingUV = "\n\n vec2 uv = gl_FragCoord.xy / u_resolution.xy;\n #ifdef USE_PIXELIZATION\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUv = gl_FragCoord.xy;\n pxSizeUv -= .5 * u_resolution;\n pxSizeUv /= pxSize;\n uv = floor(pxSizeUv) * pxSize / u_resolution.xy; \n uv += .5;\n #endif\n uv -= .5;\n\n \n // ===================================================\n // sizing params shared between objects and patterns\n \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 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 objects (graphics with fixed ratio)\n\n #ifdef USE_OBJECT_SIZING\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 vec2 objectBoxSize = vec2(0.);\n // fit = none\n objectBoxSize.x = fixedRatio * min(fixedRatioBoxGivenSize.x / fixedRatio, fixedRatioBoxGivenSize.y);\n if (u_fit == 1.) { // fit = contain\n objectBoxSize.x = fixedRatio * min(u_resolution.x / fixedRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n objectBoxSize.x = fixedRatio * max(u_resolution.x / fixedRatio, u_resolution.y);\n }\n objectBoxSize.y = objectBoxSize.x / fixedRatio;\n vec2 objectWorldScale = u_resolution.xy / objectBoxSize;\n \n #ifdef ADD_HELPERS\n vec2 objectHelperBox = gl_FragCoord.xy / u_resolution.xy;\n objectHelperBox -= .5;\n objectHelperBox *= objectWorldScale;\n objectHelperBox += boxOrigin * (objectWorldScale - 1.); \n #endif\n \n vec2 objectUV = uv;\n objectUV *= objectWorldScale;\n objectUV += boxOrigin * (objectWorldScale - 1.);\n objectUV += vec2(-u_offsetX, u_offsetY);\n objectUV /= u_scale;\n objectUV = graphicRotation * objectUV;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for patterns (graphics respecting u_worldWidth / u_worldHeight ratio)\n \n #ifdef USE_PATTERN_SIZING\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 vec2 patternBoxSize = vec2(0.);\n // fit = none\n patternBoxSize.x = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n float patternWorldNoFitBoxWidth = patternBoxSize.x;\n if (u_fit == 1.) { // fit = contain\n patternBoxSize.x = patternBoxRatio * min(u_resolution.x / patternBoxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n patternBoxSize.x = patternBoxRatio * max(u_resolution.x / patternBoxRatio, u_resolution.y);\n }\n patternBoxSize.y = patternBoxSize.x / patternBoxRatio;\n vec2 patternWorldScale = u_resolution.xy / patternBoxSize;\n \n #ifdef ADD_HELPERS \n vec2 patternHelperBox = gl_FragCoord.xy / u_resolution.xy;\n patternHelperBox -= .5;\n patternHelperBox *= patternWorldScale;\n patternHelperBox += boxOrigin * (patternWorldScale - 1.); \n #endif\n \n vec2 patternUV = uv;\n patternUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;\n patternUV += boxOrigin;\n patternUV -= boxOrigin / patternWorldScale;\n patternUV *= u_resolution.xy;\n patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n patternUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);\n }\n patternUV /= u_scale;\n patternUV = graphicRotation * patternUV;\n patternUV += boxOrigin / patternWorldScale;\n patternUV -= boxOrigin;\n patternUV += .5;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for image filters\n \n #ifdef USE_IMAGE_SIZING\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n \n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n #endif\n";
5
5
  export declare const drawSizingHelpers = "\n vec2 worldBoxDist = abs(helperBox);\n float boxStroke = (step(max(worldBoxDist.x, worldBoxDist.y), .5) - step(max(worldBoxDist.x, worldBoxDist.y), .495));\n color.rgb = mix(color.rgb, vec3(1., 0., 0.), boxStroke);\n opacity += boxStroke;\n\n vec2 boxOriginCopy = vec2(.5 - u_originX, u_originY - .5);\n vec2 boxOriginDist = helperBox + boxOriginCopy;\n boxOriginDist.x *= (boxSize.x / boxSize.y);\n float boxOriginPoint = 1. - smoothstep(0., .05, length(boxOriginDist));\n \n vec2 graphicOriginPointDist = helperBox + vec2(-u_offsetX, u_offsetY);\n graphicOriginPointDist.x *= (boxSize.x / boxSize.y);\n float graphicOriginPoint = 1. - smoothstep(0., .05, length(graphicOriginPointDist));\n \n color.rgb = mix(color.rgb, vec3(0., 1., 0.), boxOriginPoint);\n opacity += boxOriginPoint;\n color.rgb = mix(color.rgb, vec3(0., 0., 1.), graphicOriginPoint);\n opacity += graphicOriginPoint;\n";
6
6
  export interface ShaderSizingUniforms {
7
7
  u_fit: (typeof ShaderFitOptions)[ShaderFit];
@@ -47,7 +47,6 @@ const sizingUV = `
47
47
  vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
48
48
  vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
49
49
  givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
50
- vec2 maxBoxSize = vec2(max(u_resolution.x, givenBoxSize.x), max(u_resolution.y, givenBoxSize.y));
51
50
  float r = u_rotation * 3.14159265358979323846 / 180.;
52
51
  mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
53
52
  vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
@@ -66,9 +65,9 @@ const sizingUV = `
66
65
  // fit = none
67
66
  objectBoxSize.x = fixedRatio * min(fixedRatioBoxGivenSize.x / fixedRatio, fixedRatioBoxGivenSize.y);
68
67
  if (u_fit == 1.) { // fit = contain
69
- objectBoxSize.x = fixedRatio * min(maxBoxSize.x / fixedRatio, maxBoxSize.y);
68
+ objectBoxSize.x = fixedRatio * min(u_resolution.x / fixedRatio, u_resolution.y);
70
69
  } else if (u_fit == 2.) { // fit = cover
71
- objectBoxSize.x = fixedRatio * max(maxBoxSize.x / fixedRatio, maxBoxSize.y);
70
+ objectBoxSize.x = fixedRatio * max(u_resolution.x / fixedRatio, u_resolution.y);
72
71
  }
73
72
  objectBoxSize.y = objectBoxSize.x / fixedRatio;
74
73
  vec2 objectWorldScale = u_resolution.xy / objectBoxSize;
@@ -104,9 +103,9 @@ const sizingUV = `
104
103
  patternBoxSize.x = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);
105
104
  float patternWorldNoFitBoxWidth = patternBoxSize.x;
106
105
  if (u_fit == 1.) { // fit = contain
107
- patternBoxSize.x = patternBoxRatio * min(maxBoxSize.x / patternBoxRatio, maxBoxSize.y);
106
+ patternBoxSize.x = patternBoxRatio * min(u_resolution.x / patternBoxRatio, u_resolution.y);
108
107
  } else if (u_fit == 2.) { // fit = cover
109
- patternBoxSize.x = patternBoxRatio * max(maxBoxSize.x / patternBoxRatio, maxBoxSize.y);
108
+ patternBoxSize.x = patternBoxRatio * max(u_resolution.x / patternBoxRatio, u_resolution.y);
110
109
  }
111
110
  patternBoxSize.y = patternBoxSize.x / patternBoxRatio;
112
111
  vec2 patternWorldScale = u_resolution.xy / patternBoxSize;
@@ -143,9 +142,9 @@ const sizingUV = `
143
142
 
144
143
  vec2 imageBoxSize;
145
144
  if (u_fit == 1.) { // contain
146
- imageBoxSize.x = min(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;
145
+ imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
147
146
  } else if (u_fit == 2.) { // cover
148
- imageBoxSize.x = max(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;
147
+ imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
149
148
  } else {
150
149
  imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);
151
150
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/shader-sizing.ts"],
4
- "sourcesContent": ["/*\n ===================================================================\n The space coordinates passed from the vertex shader.\n\n `sizingVariablesDeclaration` must be included in every fragment\n shader\u2014unless we want to apply sizing to the coordinates directly\n in the fragment shader.\n\n So far, the only exception is when we need to apply pixelization\n before sizing (e.g., to make dithering pixels independent of sizing).\n*/\nexport const sizingVariablesDeclaration = `\nin vec2 v_objectUV;\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_patternUV;\nin vec2 v_imageUV;`;\n\n/*\n ===================================================================\n Additional variables used only for drawing a sizing overlay.\n*/\nexport const sizingDebugVariablesDeclaration = `\nin vec2 v_objectBoxSize;\nin vec2 v_objectHelperBox;\nin vec2 v_responsiveBoxSize;\nin vec2 v_responsiveHelperBox;\nin vec2 v_patternBoxSize;\nin vec2 v_patternHelperBox;`;\n\n/*\n ===================================================================\n In most cases, sizing UNIFORMS are used only in the vertex shader.\n But there are cases where we need to pass them to the fragment shader\n as well:\n - dithering pixelization where all the sizing happens in fragment\n - drawing the sizing helpers\n*/\nexport const sizingUniformsDeclaration = `\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\n/*\n ===================================================================\n In most cases, sizing TRANSFORMS are applied in the vertex shader.\n For exceptions (e.g., dithering pixelization), the operations below\n need to be included in the fragment shader instead.\n\n The transforms are identical to those in the vertex shader,\n except for the `USE_PIXELIZATION` part we insert at start.\n*/\nexport const sizingUV = `\n\n vec2 uv = gl_FragCoord.xy / u_resolution.xy;\n #ifdef USE_PIXELIZATION\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUv = gl_FragCoord.xy;\n pxSizeUv -= .5 * u_resolution;\n pxSizeUv /= pxSize;\n uv = floor(pxSizeUv) * pxSize / u_resolution.xy; \n uv += .5;\n #endif\n uv -= .5;\n\n \n // ===================================================\n // sizing params shared between objects and patterns\n \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 objects (graphics with fixed ratio)\n\n #ifdef USE_OBJECT_SIZING\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 vec2 objectBoxSize = vec2(0.);\n // fit = none\n objectBoxSize.x = fixedRatio * min(fixedRatioBoxGivenSize.x / fixedRatio, fixedRatioBoxGivenSize.y);\n if (u_fit == 1.) { // fit = contain\n objectBoxSize.x = fixedRatio * min(maxBoxSize.x / fixedRatio, maxBoxSize.y);\n } else if (u_fit == 2.) { // fit = cover\n objectBoxSize.x = fixedRatio * max(maxBoxSize.x / fixedRatio, maxBoxSize.y);\n }\n objectBoxSize.y = objectBoxSize.x / fixedRatio;\n vec2 objectWorldScale = u_resolution.xy / objectBoxSize;\n \n #ifdef ADD_HELPERS\n vec2 objectHelperBox = gl_FragCoord.xy / u_resolution.xy;\n objectHelperBox -= .5;\n objectHelperBox *= objectWorldScale;\n objectHelperBox += boxOrigin * (objectWorldScale - 1.); \n #endif\n \n vec2 objectUV = uv;\n objectUV *= objectWorldScale;\n objectUV += boxOrigin * (objectWorldScale - 1.);\n objectUV += vec2(-u_offsetX, u_offsetY);\n objectUV /= u_scale;\n objectUV = graphicRotation * objectUV;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for patterns (graphics respecting u_worldWidth / u_worldHeight ratio)\n \n #ifdef USE_PATTERN_SIZING\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 vec2 patternBoxSize = vec2(0.);\n // fit = none\n patternBoxSize.x = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n float patternWorldNoFitBoxWidth = patternBoxSize.x;\n if (u_fit == 1.) { // fit = contain\n patternBoxSize.x = patternBoxRatio * min(maxBoxSize.x / patternBoxRatio, maxBoxSize.y);\n } else if (u_fit == 2.) { // fit = cover\n patternBoxSize.x = patternBoxRatio * max(maxBoxSize.x / patternBoxRatio, maxBoxSize.y);\n }\n patternBoxSize.y = patternBoxSize.x / patternBoxRatio;\n vec2 patternWorldScale = u_resolution.xy / patternBoxSize;\n \n #ifdef ADD_HELPERS \n vec2 patternHelperBox = gl_FragCoord.xy / u_resolution.xy;\n patternHelperBox -= .5;\n patternHelperBox *= patternWorldScale;\n patternHelperBox += boxOrigin * (patternWorldScale - 1.); \n #endif\n \n vec2 patternUV = uv;\n patternUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;\n patternUV += boxOrigin;\n patternUV -= boxOrigin / patternWorldScale;\n patternUV *= u_resolution.xy;\n patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n patternUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);\n }\n patternUV /= u_scale;\n patternUV = graphicRotation * patternUV;\n patternUV += boxOrigin / patternWorldScale;\n patternUV -= boxOrigin;\n patternUV += .5;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for image filters\n \n #ifdef USE_IMAGE_SIZING\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n \n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n #endif\n`;\n\n/*\n ===================================================================\n Helpers used to draw the sizing (box, box origin and graphic origin)\n over the shader. Can be used with both vertex sizing and vector sizing\n\n helperBox and boxSize should be defined before inserting the code\n*/\nexport const drawSizingHelpers = `\n vec2 worldBoxDist = abs(helperBox);\n float boxStroke = (step(max(worldBoxDist.x, worldBoxDist.y), .5) - step(max(worldBoxDist.x, worldBoxDist.y), .495));\n color.rgb = mix(color.rgb, vec3(1., 0., 0.), boxStroke);\n opacity += boxStroke;\n\n vec2 boxOriginCopy = vec2(.5 - u_originX, u_originY - .5);\n vec2 boxOriginDist = helperBox + boxOriginCopy;\n boxOriginDist.x *= (boxSize.x / boxSize.y);\n float boxOriginPoint = 1. - smoothstep(0., .05, length(boxOriginDist));\n \n vec2 graphicOriginPointDist = helperBox + vec2(-u_offsetX, u_offsetY);\n graphicOriginPointDist.x *= (boxSize.x / boxSize.y);\n float graphicOriginPoint = 1. - smoothstep(0., .05, length(graphicOriginPointDist));\n \n color.rgb = mix(color.rgb, vec3(0., 1., 0.), boxOriginPoint);\n opacity += boxOriginPoint;\n color.rgb = mix(color.rgb, vec3(0., 0., 1.), graphicOriginPoint);\n opacity += graphicOriginPoint;\n`;\n\nexport interface ShaderSizingUniforms {\n u_fit: (typeof ShaderFitOptions)[ShaderFit];\n u_scale: number;\n u_rotation: number;\n u_originX: number;\n u_originY: number;\n u_offsetX: number;\n u_offsetY: number;\n u_worldWidth: number;\n u_worldHeight: number;\n}\n\nexport interface ShaderSizingParams {\n fit?: 'none' | 'contain' | 'cover';\n scale?: number;\n rotation?: number;\n originX?: number;\n originY?: number;\n offsetX?: number;\n offsetY?: number;\n worldWidth?: number;\n worldHeight?: number;\n}\n\nexport const defaultObjectSizing: Required<ShaderSizingParams> = {\n fit: 'contain',\n scale: 1,\n rotation: 0,\n offsetX: 0,\n offsetY: 0,\n originX: 0.5,\n originY: 0.5,\n worldWidth: 0,\n worldHeight: 0,\n};\n\nexport const defaultPatternSizing: Required<ShaderSizingParams> = {\n fit: 'none',\n scale: 1,\n rotation: 0,\n offsetX: 0,\n offsetY: 0,\n originX: 0.5,\n originY: 0.5,\n worldWidth: 0,\n worldHeight: 0,\n};\n\nexport const ShaderFitOptions = {\n none: 0,\n contain: 1,\n cover: 2,\n} as const;\n\nexport type ShaderFit = keyof typeof ShaderFitOptions;\n"],
5
- "mappings": ";;;;;AAWO,MAAM,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAWnC,MAAM,kCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBxC,MAAM,4BAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBlC,MAAM,WAAW;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwJjB,MAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6C1B,MAAM,sBAAoD;AAAA,EAC/D,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,MAAM,uBAAqD;AAAA,EAChE,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,MAAM,mBAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AACT;",
4
+ "sourcesContent": ["/*\n ===================================================================\n The space coordinates passed from the vertex shader.\n\n `sizingVariablesDeclaration` must be included in every fragment\n shader\u2014unless we want to apply sizing to the coordinates directly\n in the fragment shader.\n\n So far, the only exception is when we need to apply pixelization\n before sizing (e.g., to make dithering pixels independent of sizing).\n*/\nexport const sizingVariablesDeclaration = `\nin vec2 v_objectUV;\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_patternUV;\nin vec2 v_imageUV;`;\n\n/*\n ===================================================================\n Additional variables used only for drawing a sizing overlay.\n*/\nexport const sizingDebugVariablesDeclaration = `\nin vec2 v_objectBoxSize;\nin vec2 v_objectHelperBox;\nin vec2 v_responsiveBoxSize;\nin vec2 v_responsiveHelperBox;\nin vec2 v_patternBoxSize;\nin vec2 v_patternHelperBox;`;\n\n/*\n ===================================================================\n In most cases, sizing UNIFORMS are used only in the vertex shader.\n But there are cases where we need to pass them to the fragment shader\n as well:\n - dithering pixelization where all the sizing happens in fragment\n - drawing the sizing helpers\n*/\nexport const sizingUniformsDeclaration = `\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\n/*\n ===================================================================\n In most cases, sizing TRANSFORMS are applied in the vertex shader.\n For exceptions (e.g., dithering pixelization), the operations below\n need to be included in the fragment shader instead.\n\n The transforms are identical to those in the vertex shader,\n except for the `USE_PIXELIZATION` part we insert at start.\n*/\nexport const sizingUV = `\n\n vec2 uv = gl_FragCoord.xy / u_resolution.xy;\n #ifdef USE_PIXELIZATION\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUv = gl_FragCoord.xy;\n pxSizeUv -= .5 * u_resolution;\n pxSizeUv /= pxSize;\n uv = floor(pxSizeUv) * pxSize / u_resolution.xy; \n uv += .5;\n #endif\n uv -= .5;\n\n \n // ===================================================\n // sizing params shared between objects and patterns\n \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 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 objects (graphics with fixed ratio)\n\n #ifdef USE_OBJECT_SIZING\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 vec2 objectBoxSize = vec2(0.);\n // fit = none\n objectBoxSize.x = fixedRatio * min(fixedRatioBoxGivenSize.x / fixedRatio, fixedRatioBoxGivenSize.y);\n if (u_fit == 1.) { // fit = contain\n objectBoxSize.x = fixedRatio * min(u_resolution.x / fixedRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n objectBoxSize.x = fixedRatio * max(u_resolution.x / fixedRatio, u_resolution.y);\n }\n objectBoxSize.y = objectBoxSize.x / fixedRatio;\n vec2 objectWorldScale = u_resolution.xy / objectBoxSize;\n \n #ifdef ADD_HELPERS\n vec2 objectHelperBox = gl_FragCoord.xy / u_resolution.xy;\n objectHelperBox -= .5;\n objectHelperBox *= objectWorldScale;\n objectHelperBox += boxOrigin * (objectWorldScale - 1.); \n #endif\n \n vec2 objectUV = uv;\n objectUV *= objectWorldScale;\n objectUV += boxOrigin * (objectWorldScale - 1.);\n objectUV += vec2(-u_offsetX, u_offsetY);\n objectUV /= u_scale;\n objectUV = graphicRotation * objectUV;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for patterns (graphics respecting u_worldWidth / u_worldHeight ratio)\n \n #ifdef USE_PATTERN_SIZING\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 vec2 patternBoxSize = vec2(0.);\n // fit = none\n patternBoxSize.x = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n float patternWorldNoFitBoxWidth = patternBoxSize.x;\n if (u_fit == 1.) { // fit = contain\n patternBoxSize.x = patternBoxRatio * min(u_resolution.x / patternBoxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n patternBoxSize.x = patternBoxRatio * max(u_resolution.x / patternBoxRatio, u_resolution.y);\n }\n patternBoxSize.y = patternBoxSize.x / patternBoxRatio;\n vec2 patternWorldScale = u_resolution.xy / patternBoxSize;\n \n #ifdef ADD_HELPERS \n vec2 patternHelperBox = gl_FragCoord.xy / u_resolution.xy;\n patternHelperBox -= .5;\n patternHelperBox *= patternWorldScale;\n patternHelperBox += boxOrigin * (patternWorldScale - 1.); \n #endif\n \n vec2 patternUV = uv;\n patternUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;\n patternUV += boxOrigin;\n patternUV -= boxOrigin / patternWorldScale;\n patternUV *= u_resolution.xy;\n patternUV /= u_pixelRatio;\n if (u_fit > 0.) {\n patternUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);\n }\n patternUV /= u_scale;\n patternUV = graphicRotation * patternUV;\n patternUV += boxOrigin / patternWorldScale;\n patternUV -= boxOrigin;\n patternUV += .5;\n #endif\n \n // ===================================================\n \n // ===================================================\n // Sizing api for image filters\n \n #ifdef USE_IMAGE_SIZING\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n \n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n #endif\n`;\n\n/*\n ===================================================================\n Helpers used to draw the sizing (box, box origin and graphic origin)\n over the shader. Can be used with both vertex sizing and vector sizing\n\n helperBox and boxSize should be defined before inserting the code\n*/\nexport const drawSizingHelpers = `\n vec2 worldBoxDist = abs(helperBox);\n float boxStroke = (step(max(worldBoxDist.x, worldBoxDist.y), .5) - step(max(worldBoxDist.x, worldBoxDist.y), .495));\n color.rgb = mix(color.rgb, vec3(1., 0., 0.), boxStroke);\n opacity += boxStroke;\n\n vec2 boxOriginCopy = vec2(.5 - u_originX, u_originY - .5);\n vec2 boxOriginDist = helperBox + boxOriginCopy;\n boxOriginDist.x *= (boxSize.x / boxSize.y);\n float boxOriginPoint = 1. - smoothstep(0., .05, length(boxOriginDist));\n \n vec2 graphicOriginPointDist = helperBox + vec2(-u_offsetX, u_offsetY);\n graphicOriginPointDist.x *= (boxSize.x / boxSize.y);\n float graphicOriginPoint = 1. - smoothstep(0., .05, length(graphicOriginPointDist));\n \n color.rgb = mix(color.rgb, vec3(0., 1., 0.), boxOriginPoint);\n opacity += boxOriginPoint;\n color.rgb = mix(color.rgb, vec3(0., 0., 1.), graphicOriginPoint);\n opacity += graphicOriginPoint;\n`;\n\nexport interface ShaderSizingUniforms {\n u_fit: (typeof ShaderFitOptions)[ShaderFit];\n u_scale: number;\n u_rotation: number;\n u_originX: number;\n u_originY: number;\n u_offsetX: number;\n u_offsetY: number;\n u_worldWidth: number;\n u_worldHeight: number;\n}\n\nexport interface ShaderSizingParams {\n fit?: 'none' | 'contain' | 'cover';\n scale?: number;\n rotation?: number;\n originX?: number;\n originY?: number;\n offsetX?: number;\n offsetY?: number;\n worldWidth?: number;\n worldHeight?: number;\n}\n\nexport const defaultObjectSizing: Required<ShaderSizingParams> = {\n fit: 'contain',\n scale: 1,\n rotation: 0,\n offsetX: 0,\n offsetY: 0,\n originX: 0.5,\n originY: 0.5,\n worldWidth: 0,\n worldHeight: 0,\n};\n\nexport const defaultPatternSizing: Required<ShaderSizingParams> = {\n fit: 'none',\n scale: 1,\n rotation: 0,\n offsetX: 0,\n offsetY: 0,\n originX: 0.5,\n originY: 0.5,\n worldWidth: 0,\n worldHeight: 0,\n};\n\nexport const ShaderFitOptions = {\n none: 0,\n contain: 1,\n cover: 2,\n} as const;\n\nexport type ShaderFit = keyof typeof ShaderFitOptions;\n"],
5
+ "mappings": ";;;;;AAWO,MAAM,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAWnC,MAAM,kCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBxC,MAAM,4BAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBlC,MAAM,WAAW;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuJjB,MAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6C1B,MAAM,sBAAoD;AAAA,EAC/D,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,MAAM,uBAAqD;AAAA,EAChE,KAAK;AAAA,EACL,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,aAAa;AACf;AAEO,MAAM,mBAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -53,12 +53,12 @@ vec2 getPanel(float angle, vec2 uv, float invLength, float aa) {
53
53
  float zOffset = zRatio - .5;
54
54
  float left = -.5 + zOffset * u_angle1;
55
55
  float right = .5 - zOffset * u_angle2;
56
- float blurX = aa + panelMap * u_blur;
56
+ float blurX = aa + 2. * panelMap * u_blur;
57
57
 
58
- float leftEdge1 = left - .5 * blurX;
59
- float leftEdge2 = left + blurX;
60
- float rightEdge1 = right - blurX;
61
- float rightEdge2 = right + .5 * blurX;
58
+ float leftEdge1 = left - blurX;
59
+ float leftEdge2 = left + .25 * blurX;
60
+ float rightEdge1 = right - .25 * blurX;
61
+ float rightEdge2 = right + blurX;
62
62
 
63
63
  float panel = smoothstep(leftEdge1, leftEdge2, x) * (1.0 - smoothstep(rightEdge1, rightEdge2, x));
64
64
  panel *= mix(0., panel, smoothstep(0., .01 / u_scale, panelMap));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/color-panels.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, colorBandingFix } from '../shader-utils.js';\n\nexport const colorPanelsMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Pseudo-3D panels rotating around a central axis\n *\n * Uniforms include:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_density: angle between every 2 panels\n * - u_angle1, u_angle2: skew angle applied to all panes\n * - u_length: panel length (relative to total height)\n * - u_edges: faking edges effect\n * - u_blur: side blur (0 for sharp edges)\n * - u_fadeIn: transparency near central axis\n * - u_fadeOut: transparency near viewer\n * - u_gradient: color mixing within panes (0 = single color, 1 = two colors)\n *\n */\n\n// language=GLSL\nexport const colorPanelsFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\nuniform mediump float u_scale;\n\nuniform vec4 u_colors[${colorPanelsMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform vec4 u_colorBack;\nuniform float u_density;\nuniform float u_angle1;\nuniform float u_angle2;\nuniform float u_length;\nuniform bool u_edges;\nuniform float u_blur;\nuniform float u_fadeIn;\nuniform float u_fadeOut;\nuniform float u_gradient;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nconst float zLimit = .5;\n\nvec2 getPanel(float angle, vec2 uv, float invLength, float aa) {\n float sinA = sin(angle);\n float cosA = cos(angle);\n\n float denom = sinA - uv.y * cosA;\n if (abs(denom) < .01) return vec2(0.);\n \n float z = uv.y / denom;\n\n if (z <= 0. || z > zLimit) return vec2(0.);\n\n float zRatio = z / zLimit;\n float panelMap = 1. - zRatio;\n float x = uv.x * (cosA * z + 1.) * invLength;\n\n float zOffset = zRatio - .5;\n float left = -.5 + zOffset * u_angle1;\n float right = .5 - zOffset * u_angle2;\n float blurX = aa + panelMap * u_blur;\n\n float leftEdge1 = left - .5 * blurX;\n float leftEdge2 = left + blurX;\n float rightEdge1 = right - blurX;\n float rightEdge2 = right + .5 * blurX;\n\n float panel = smoothstep(leftEdge1, leftEdge2, x) * (1.0 - smoothstep(rightEdge1, rightEdge2, x));\n panel *= mix(0., panel, smoothstep(0., .01 / u_scale, panelMap));\n\n float midScreen = abs(sinA);\n if (u_edges == true) {\n panelMap = mix(.99, panelMap, panel * clamp(panelMap / (.15 * (1. - pow(midScreen, .1))), 0.0, 1.0));\n } else if (midScreen < .07) {\n panel *= (midScreen * 15.);\n }\n \n return vec2(panel, panelMap);\n}\n\nvec4 blendColor(vec4 colorA, float panelMask, float panelMap) {\n float fade = smoothstep(1., .97 - .97 * u_fadeIn, panelMap);\n fade *= smoothstep(-.2 * (1. - u_fadeOut), u_fadeOut, panelMap);\n\n vec3 blendedRGB = mix(vec3(0.), colorA.rgb, fade);\n float blendedAlpha = mix(0., colorA.a, fade);\n\n return vec4(blendedRGB, blendedAlpha) * panelMask;\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv *= 1.25;\n\n float t = .02 * u_time;\n t = fract(t);\n bool reverseTime = (t < 0.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n\n float aa = .005 / u_scale;\n int colorsCount = int(u_colorsCount);\n\n vec4 premultipliedColors[${colorPanelsMeta.maxColorCount}];\n for (int i = 0; i < ${colorPanelsMeta.maxColorCount}; i++) {\n if (i >= colorsCount) break;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n premultipliedColors[i] = c;\n }\n\n float invLength = 1.5 / (u_length + 0.001);\n\n float totalColorWeight = 0.;\n int panelsNumber = 12;\n\n float densityNormalizer = 1.;\n if (colorsCount == 4) {\n panelsNumber = 16;\n densityNormalizer = 1.34;\n } else if (colorsCount == 5) {\n panelsNumber = 20;\n densityNormalizer = 1.67;\n } else if (colorsCount == 7) {\n panelsNumber = 14;\n densityNormalizer = 1.17;\n }\n\n float fPanelsNumber = float(panelsNumber);\n\n float totalPanelsShape = 0.;\n float panelGrad = 1. - clamp(u_gradient, 0., 1.);\n\n for (int set = 0; set < 2; set++) {\n bool isForward = (set == 0 && !reverseTime) || (set == 1 && reverseTime);\n if (!isForward) continue;\n\n for (int i = 0; i <= 20; i++) {\n if (i >= panelsNumber) break;\n\n int idx = panelsNumber - 1 - i;\n\n float offset = float(idx) / fPanelsNumber;\n if (set == 1) {\n offset += .5;\n }\n\n float densityFract = densityNormalizer * fract(t + offset);\n float angleNorm = densityFract / u_density;\n if (densityFract >= .5 || angleNorm >= .3) continue;\n\n float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);\n float smoothAngle = clamp((.3 - angleNorm) / .05, 0., 1.);\n if (smoothDensity * smoothAngle < .001) continue;\n\n if (angleNorm > .5) {\n angleNorm = 0.5;\n }\n vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);\n if (panel[0] <= .001) continue;\n float panelMask = panel[0] * smoothDensity * smoothAngle;\n float panelMap = panel[1];\n\n int colorIdx = idx % colorsCount;\n int nextColorIdx = (idx + 1) % colorsCount;\n\n vec4 colorA = premultipliedColors[colorIdx];\n vec4 colorB = premultipliedColors[nextColorIdx];\n\n colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));\n vec4 blended = blendColor(colorA, panelMask, panelMap);\n color = blended.rgb + color * (1. - blended.a);\n opacity = blended.a + opacity * (1. - blended.a);\n }\n\n\n for (int i = 0; i <= 20; i++) {\n if (i >= panelsNumber) break;\n\n int idx = panelsNumber - 1 - i;\n\n float offset = float(idx) / fPanelsNumber;\n if (set == 0) {\n offset += .5;\n }\n\n float densityFract = densityNormalizer * fract(-t + offset);\n float angleNorm = -densityFract / u_density;\n if (densityFract >= .5 || angleNorm < -.3) continue;\n\n float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);\n float smoothAngle = clamp((angleNorm + .3) / .05, 0., 1.);\n if (smoothDensity * smoothAngle < .001) continue;\n\n vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);\n float panelMask = panel[0] * smoothDensity * smoothAngle;\n if (panelMask <= .001) continue;\n float panelMap = panel[1];\n\n int colorIdx = (colorsCount - (idx % colorsCount)) % colorsCount;\n if (colorIdx < 0) colorIdx += colorsCount;\n int nextColorIdx = (colorIdx + 1) % colorsCount;\n\n vec4 colorA = premultipliedColors[colorIdx];\n vec4 colorB = premultipliedColors[nextColorIdx];\n\n colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));\n vec4 blended = blendColor(colorA, panelMask, panelMap);\n color = blended.rgb + color * (1. - blended.a);\n opacity = blended.a + opacity * (1. - blended.a);\n }\n }\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ColorPanelsUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_colorBack: [number, number, number, number];\n u_angle1: number;\n u_angle2: number;\n u_length: number;\n u_edges: boolean;\n u_blur: number;\n u_fadeIn: number;\n u_fadeOut: number;\n u_density: number;\n u_gradient: number;\n}\n\nexport interface ColorPanelsParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n colorBack?: string;\n angle1?: number;\n angle2?: number;\n length?: number;\n edges?: boolean;\n blur?: number;\n fadeIn?: number;\n fadeOut?: number;\n density?: number;\n gradient?: number;\n}\n"],
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, colorBandingFix } from '../shader-utils.js';\n\nexport const colorPanelsMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Pseudo-3D panels rotating around a central axis\n *\n * Uniforms include:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_density: angle between every 2 panels\n * - u_angle1, u_angle2: skew angle applied to all panes\n * - u_length: panel length (relative to total height)\n * - u_edges: faking edges effect\n * - u_blur: side blur (0 for sharp edges)\n * - u_fadeIn: transparency near central axis\n * - u_fadeOut: transparency near viewer\n * - u_gradient: color mixing within panes (0 = single color, 1 = two colors)\n *\n */\n\n// language=GLSL\nexport const colorPanelsFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\nuniform mediump float u_scale;\n\nuniform vec4 u_colors[${colorPanelsMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform vec4 u_colorBack;\nuniform float u_density;\nuniform float u_angle1;\nuniform float u_angle2;\nuniform float u_length;\nuniform bool u_edges;\nuniform float u_blur;\nuniform float u_fadeIn;\nuniform float u_fadeOut;\nuniform float u_gradient;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nconst float zLimit = .5;\n\nvec2 getPanel(float angle, vec2 uv, float invLength, float aa) {\n float sinA = sin(angle);\n float cosA = cos(angle);\n\n float denom = sinA - uv.y * cosA;\n if (abs(denom) < .01) return vec2(0.);\n \n float z = uv.y / denom;\n\n if (z <= 0. || z > zLimit) return vec2(0.);\n\n float zRatio = z / zLimit;\n float panelMap = 1. - zRatio;\n float x = uv.x * (cosA * z + 1.) * invLength;\n\n float zOffset = zRatio - .5;\n float left = -.5 + zOffset * u_angle1;\n float right = .5 - zOffset * u_angle2;\n float blurX = aa + 2. * panelMap * u_blur;\n\n float leftEdge1 = left - blurX;\n float leftEdge2 = left + .25 * blurX;\n float rightEdge1 = right - .25 * blurX;\n float rightEdge2 = right + blurX;\n\n float panel = smoothstep(leftEdge1, leftEdge2, x) * (1.0 - smoothstep(rightEdge1, rightEdge2, x));\n panel *= mix(0., panel, smoothstep(0., .01 / u_scale, panelMap));\n\n float midScreen = abs(sinA);\n if (u_edges == true) {\n panelMap = mix(.99, panelMap, panel * clamp(panelMap / (.15 * (1. - pow(midScreen, .1))), 0.0, 1.0));\n } else if (midScreen < .07) {\n panel *= (midScreen * 15.);\n }\n \n return vec2(panel, panelMap);\n}\n\nvec4 blendColor(vec4 colorA, float panelMask, float panelMap) {\n float fade = smoothstep(1., .97 - .97 * u_fadeIn, panelMap);\n fade *= smoothstep(-.2 * (1. - u_fadeOut), u_fadeOut, panelMap);\n\n vec3 blendedRGB = mix(vec3(0.), colorA.rgb, fade);\n float blendedAlpha = mix(0., colorA.a, fade);\n\n return vec4(blendedRGB, blendedAlpha) * panelMask;\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv *= 1.25;\n\n float t = .02 * u_time;\n t = fract(t);\n bool reverseTime = (t < 0.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n\n float aa = .005 / u_scale;\n int colorsCount = int(u_colorsCount);\n\n vec4 premultipliedColors[${colorPanelsMeta.maxColorCount}];\n for (int i = 0; i < ${colorPanelsMeta.maxColorCount}; i++) {\n if (i >= colorsCount) break;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n premultipliedColors[i] = c;\n }\n\n float invLength = 1.5 / (u_length + 0.001);\n\n float totalColorWeight = 0.;\n int panelsNumber = 12;\n\n float densityNormalizer = 1.;\n if (colorsCount == 4) {\n panelsNumber = 16;\n densityNormalizer = 1.34;\n } else if (colorsCount == 5) {\n panelsNumber = 20;\n densityNormalizer = 1.67;\n } else if (colorsCount == 7) {\n panelsNumber = 14;\n densityNormalizer = 1.17;\n }\n\n float fPanelsNumber = float(panelsNumber);\n\n float totalPanelsShape = 0.;\n float panelGrad = 1. - clamp(u_gradient, 0., 1.);\n\n for (int set = 0; set < 2; set++) {\n bool isForward = (set == 0 && !reverseTime) || (set == 1 && reverseTime);\n if (!isForward) continue;\n\n for (int i = 0; i <= 20; i++) {\n if (i >= panelsNumber) break;\n\n int idx = panelsNumber - 1 - i;\n\n float offset = float(idx) / fPanelsNumber;\n if (set == 1) {\n offset += .5;\n }\n\n float densityFract = densityNormalizer * fract(t + offset);\n float angleNorm = densityFract / u_density;\n if (densityFract >= .5 || angleNorm >= .3) continue;\n\n float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);\n float smoothAngle = clamp((.3 - angleNorm) / .05, 0., 1.);\n if (smoothDensity * smoothAngle < .001) continue;\n\n if (angleNorm > .5) {\n angleNorm = 0.5;\n }\n vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);\n if (panel[0] <= .001) continue;\n float panelMask = panel[0] * smoothDensity * smoothAngle;\n float panelMap = panel[1];\n\n int colorIdx = idx % colorsCount;\n int nextColorIdx = (idx + 1) % colorsCount;\n\n vec4 colorA = premultipliedColors[colorIdx];\n vec4 colorB = premultipliedColors[nextColorIdx];\n\n colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));\n vec4 blended = blendColor(colorA, panelMask, panelMap);\n color = blended.rgb + color * (1. - blended.a);\n opacity = blended.a + opacity * (1. - blended.a);\n }\n\n\n for (int i = 0; i <= 20; i++) {\n if (i >= panelsNumber) break;\n\n int idx = panelsNumber - 1 - i;\n\n float offset = float(idx) / fPanelsNumber;\n if (set == 0) {\n offset += .5;\n }\n\n float densityFract = densityNormalizer * fract(-t + offset);\n float angleNorm = -densityFract / u_density;\n if (densityFract >= .5 || angleNorm < -.3) continue;\n\n float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);\n float smoothAngle = clamp((angleNorm + .3) / .05, 0., 1.);\n if (smoothDensity * smoothAngle < .001) continue;\n\n vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);\n float panelMask = panel[0] * smoothDensity * smoothAngle;\n if (panelMask <= .001) continue;\n float panelMap = panel[1];\n\n int colorIdx = (colorsCount - (idx % colorsCount)) % colorsCount;\n if (colorIdx < 0) colorIdx += colorsCount;\n int nextColorIdx = (colorIdx + 1) % colorsCount;\n\n vec4 colorA = premultipliedColors[colorIdx];\n vec4 colorB = premultipliedColors[nextColorIdx];\n\n colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));\n vec4 blended = blendColor(colorA, panelMask, panelMap);\n color = blended.rgb + color * (1. - blended.a);\n opacity = blended.a + opacity * (1. - blended.a);\n }\n }\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ColorPanelsUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_colorBack: [number, number, number, number];\n u_angle1: number;\n u_angle2: number;\n u_length: number;\n u_edges: boolean;\n u_blur: number;\n u_fadeIn: number;\n u_fadeOut: number;\n u_density: number;\n u_gradient: number;\n}\n\nexport interface ColorPanelsParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n colorBack?: string;\n angle1?: number;\n angle2?: number;\n length?: number;\n edges?: boolean;\n blur?: number;\n fadeIn?: number;\n fadeOut?: number;\n density?: number;\n gradient?: number;\n}\n"],
5
5
  "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,uBAAuB;AAEpC,MAAM,kBAAkB;AAAA,EAC7B,eAAe;AACjB;AAoBO,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMzB,gBAAgB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAanD,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;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,6BAkEkB,gBAAgB,aAAa;AAAA,wBAClC,gBAAgB,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;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,IAiHjD,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -9,7 +9,7 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
9
9
  * - u_shape (float used as integer):
10
10
  * ---- 1: simplex noise pattern
11
11
  * ---- 2: warp noise pattern
12
- * ---- 3: columns if dots moving vertically
12
+ * ---- 3: columns of dots moving vertically
13
13
  * ---- 4: sine wave
14
14
  * ---- 5: ripple effect
15
15
  * ---- 6: swirl animation
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/dithering.ts"],
4
- "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n sizingUV,\n drawSizingHelpers,\n} from '../shader-sizing.js';\nimport { simplexNoise, declarePI, proceduralHash11, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * 2-color dithering effect over animated abstract shapes\n *\n * Uniforms:\n * - u_colorBack, u_colorFront (RGBA)\n * - pxSize: px size relative to canvas resolution\n * - u_shape (float used as integer):\n * ---- 1: simplex noise pattern\n * ---- 2: warp noise pattern\n * ---- 3: columns if dots moving vertically\n * ---- 4: sine wave\n * ---- 5: ripple effect\n * ---- 6: swirl animation\n * ---- 7: rotating sphere\n * - u_type (float used as integer)\n * ---- 1: random dithering\n * ---- 2: 2x2 Bayer matrix\n * ---- 3: 4x4 Bayer matrix\n * ---- 4: 8x8 Bayer matrix\n *\n * Note: pixelization is applied to the shapes BEFORE dithering, meaning pixels don't react to scaling and fit\n */\n\n// language=GLSL\nexport const ditheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\n${sizingUniformsDeclaration}\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_shape;\nuniform float u_type;\nuniform float u_pxSize;\n\nout vec4 fragColor;\n\n${simplexNoise}\n${declarePI}\n${proceduralHash11}\n${proceduralHash21}\n\nfloat getSimplexNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n 0, 8, 2, 10,\n 12, 4, 14, 6,\n 3, 11, 1, 9,\n 15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n 0, 32, 8, 40, 2, 34, 10, 42,\n 48, 16, 56, 24, 50, 18, 58, 26,\n 12, 44, 4, 36, 14, 46, 6, 38,\n 60, 28, 52, 20, 62, 30, 54, 22,\n 3, 35, 11, 43, 1, 33, 9, 41,\n 51, 19, 59, 27, 49, 17, 57, 25,\n 15, 47, 7, 39, 13, 45, 5, 37,\n 63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(mod(uv, float(size)));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n float t = .5 * u_time;\n\n #define USE_PATTERN_SIZING\n #define USE_OBJECT_SIZING\n #define USE_PIXELIZATION\n // #define ADD_HELPERS\n\n ${sizingUV}\n\n vec2 dithering_uv = pxSizeUv;\n vec2 ditheringNoise_uv = uv * u_resolution;\n vec2 shape_uv = objectUV;\n if (u_shape < 3.5) {\n shape_uv = patternUV;\n }\n\n float shape = 0.;\n if (u_shape < 1.5) {\n // Simplex noise\n shape_uv *= .001;\n\n shape = 0.5 + 0.5 * getSimplexNoise(shape_uv, t);\n shape = smoothstep(0.3, 0.9, shape);\n\n } else if (u_shape < 2.5) {\n // Warp\n shape_uv *= .003;\n\n for (float i = 1.0; i < 6.0; i++) {\n shape_uv.x += 0.6 / i * cos(i * 2.5 * shape_uv.y + t);\n shape_uv.y += 0.6 / i * cos(i * 1.5 * shape_uv.x + t);\n }\n\n shape = .15 / abs(sin(t - shape_uv.y - shape_uv.x));\n shape = smoothstep(0.02, 1., shape);\n\n } else if (u_shape < 3.5) {\n // Dots\n shape_uv *= .05;\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx * 10.);\n rand = sign(rand - .5) * pow(.1 + abs(rand), .4);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(abs(shape), 6.);\n\n } else if (u_shape < 4.5) {\n // Sine wave\n shape_uv *= 4.;\n\n float wave = cos(.5 * shape_uv.x - 2. * t) * sin(1.5 * shape_uv.x + t) * (.75 + .25 * cos(3. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n float dist = length(shape_uv);\n float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Swirl\n\n float l = length(shape_uv);\n float angle = 6. * atan(shape_uv.y, shape_uv.x) + 4. * t;\n float twist = 1.2;\n float offset = pow(l, -twist) + angle / TWO_PI;\n float mid = smoothstep(0., 1., pow(l, twist));\n shape = mix(0., fract(offset), mid);\n\n } else {\n // Sphere\n shape_uv *= 2.;\n\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(d));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoise_uv), shape);\n } break;\n case 2:\n dithering = getBayerValue(dithering_uv, 2);\n break;\n case 3:\n dithering = getBayerValue(dithering_uv, 4);\n break;\n default:\n dithering = getBayerValue(dithering_uv, 8);\n break;\n }\n\n dithering -= .5;\n float res = step(.5, shape + dithering);\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n #ifdef ADD_HELPERS\n vec2 helperBox = objectHelperBox;\n vec2 boxSize = objectBoxSize;\n if (u_shape < 3.5) {\n helperBox = patternHelperBox;\n boxSize = patternBoxSize;\n }\n ${drawSizingHelpers}\n #endif\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DitheringUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_shape: (typeof DitheringShapes)[DitheringShape];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n}\n\nexport interface DitheringParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n shape?: DitheringShape;\n type?: DitheringType;\n pxSize?: number;\n}\n\nexport const DitheringShapes = {\n simplex: 1,\n warp: 2,\n dots: 3,\n wave: 4,\n ripple: 5,\n swirl: 6,\n sphere: 7,\n} as const;\n\nexport type DitheringShape = keyof typeof DitheringShapes;\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"],
4
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n sizingUV,\n drawSizingHelpers,\n} from '../shader-sizing.js';\nimport { simplexNoise, declarePI, proceduralHash11, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * 2-color dithering effect over animated abstract shapes\n *\n * Uniforms:\n * - u_colorBack, u_colorFront (RGBA)\n * - pxSize: px size relative to canvas resolution\n * - u_shape (float used as integer):\n * ---- 1: simplex noise pattern\n * ---- 2: warp noise pattern\n * ---- 3: columns of dots moving vertically\n * ---- 4: sine wave\n * ---- 5: ripple effect\n * ---- 6: swirl animation\n * ---- 7: rotating sphere\n * - u_type (float used as integer)\n * ---- 1: random dithering\n * ---- 2: 2x2 Bayer matrix\n * ---- 3: 4x4 Bayer matrix\n * ---- 4: 8x8 Bayer matrix\n *\n * Note: pixelization is applied to the shapes BEFORE dithering, meaning pixels don't react to scaling and fit\n */\n\n// language=GLSL\nexport const ditheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\n${sizingUniformsDeclaration}\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_shape;\nuniform float u_type;\nuniform float u_pxSize;\n\nout vec4 fragColor;\n\n${simplexNoise}\n${declarePI}\n${proceduralHash11}\n${proceduralHash21}\n\nfloat getSimplexNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n 0, 8, 2, 10,\n 12, 4, 14, 6,\n 3, 11, 1, 9,\n 15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n 0, 32, 8, 40, 2, 34, 10, 42,\n 48, 16, 56, 24, 50, 18, 58, 26,\n 12, 44, 4, 36, 14, 46, 6, 38,\n 60, 28, 52, 20, 62, 30, 54, 22,\n 3, 35, 11, 43, 1, 33, 9, 41,\n 51, 19, 59, 27, 49, 17, 57, 25,\n 15, 47, 7, 39, 13, 45, 5, 37,\n 63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(mod(uv, float(size)));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n float t = .5 * u_time;\n\n #define USE_PATTERN_SIZING\n #define USE_OBJECT_SIZING\n #define USE_PIXELIZATION\n // #define ADD_HELPERS\n\n ${sizingUV}\n\n vec2 dithering_uv = pxSizeUv;\n vec2 ditheringNoise_uv = uv * u_resolution;\n vec2 shape_uv = objectUV;\n if (u_shape < 3.5) {\n shape_uv = patternUV;\n }\n\n float shape = 0.;\n if (u_shape < 1.5) {\n // Simplex noise\n shape_uv *= .001;\n\n shape = 0.5 + 0.5 * getSimplexNoise(shape_uv, t);\n shape = smoothstep(0.3, 0.9, shape);\n\n } else if (u_shape < 2.5) {\n // Warp\n shape_uv *= .003;\n\n for (float i = 1.0; i < 6.0; i++) {\n shape_uv.x += 0.6 / i * cos(i * 2.5 * shape_uv.y + t);\n shape_uv.y += 0.6 / i * cos(i * 1.5 * shape_uv.x + t);\n }\n\n shape = .15 / abs(sin(t - shape_uv.y - shape_uv.x));\n shape = smoothstep(0.02, 1., shape);\n\n } else if (u_shape < 3.5) {\n // Dots\n shape_uv *= .05;\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx * 10.);\n rand = sign(rand - .5) * pow(.1 + abs(rand), .4);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(abs(shape), 6.);\n\n } else if (u_shape < 4.5) {\n // Sine wave\n shape_uv *= 4.;\n\n float wave = cos(.5 * shape_uv.x - 2. * t) * sin(1.5 * shape_uv.x + t) * (.75 + .25 * cos(3. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n float dist = length(shape_uv);\n float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Swirl\n\n float l = length(shape_uv);\n float angle = 6. * atan(shape_uv.y, shape_uv.x) + 4. * t;\n float twist = 1.2;\n float offset = pow(l, -twist) + angle / TWO_PI;\n float mid = smoothstep(0., 1., pow(l, twist));\n shape = mix(0., fract(offset), mid);\n\n } else {\n // Sphere\n shape_uv *= 2.;\n\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(d));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoise_uv), shape);\n } break;\n case 2:\n dithering = getBayerValue(dithering_uv, 2);\n break;\n case 3:\n dithering = getBayerValue(dithering_uv, 4);\n break;\n default:\n dithering = getBayerValue(dithering_uv, 8);\n break;\n }\n\n dithering -= .5;\n float res = step(.5, shape + dithering);\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n #ifdef ADD_HELPERS\n vec2 helperBox = objectHelperBox;\n vec2 boxSize = objectBoxSize;\n if (u_shape < 3.5) {\n helperBox = patternHelperBox;\n boxSize = patternBoxSize;\n }\n ${drawSizingHelpers}\n #endif\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DitheringUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_shape: (typeof DitheringShapes)[DitheringShape];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n}\n\nexport interface DitheringParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n shape?: DitheringShape;\n type?: DitheringType;\n pxSize?: number;\n}\n\nexport const DitheringShapes = {\n simplex: 1,\n warp: 2,\n dots: 3,\n wave: 4,\n ripple: 5,\n swirl: 6,\n sphere: 7,\n} as const;\n\nexport type DitheringShape = keyof typeof DitheringShapes;\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"],
5
5
  "mappings": ";;;;;AACA;AAAA,EACE;AAAA,EAGA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc,WAAW,kBAAkB,wBAAwB;AA0BrE,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7C,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUzB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,gBAAgB;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,IAmDd,QAAQ;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;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,MAkHN,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBhB,MAAM,kBAAkB;AAAA,EAC7B,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AACV;AAIO,MAAM,iBAAiB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -155,8 +155,8 @@ void main() {
155
155
  // Grid (dots)
156
156
 
157
157
  float stripeIdx = floor(2. * shape_uv.x / TWO_PI);
158
- float rand = hash11(stripeIdx + 2.);
159
- rand = sign(rand - .5) * pow(.2 + abs(rand), .3);
158
+ float rand = hash11(stripeIdx * 100.);
159
+ rand = sign(rand - .5) * pow(4. * abs(rand), .3);
160
160
  shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);
161
161
  shape = pow(shape, 4.);
162
162
 
@@ -236,7 +236,7 @@ void main() {
236
236
 
237
237
  float simplex = snoise(grain_uv * .5);
238
238
  float grainDist = simplex * snoise(grain_uv * .2) - fbmR(.002 * grain_uv + 10.) - fbmR(.003 * grain_uv);
239
- float rawNoise = .6 * simplex - fbmR(rotate(.4 * grain_uv, 2.)) - fbmR(.001 * grain_uv);
239
+ float rawNoise = .75 * simplex - fbmR(rotate(.4 * grain_uv, 2.)) - fbmR(.001 * grain_uv);
240
240
  float noise = clamp(rawNoise, 0., 1.);
241
241
 
242
242
  shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/grain-gradient.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n sizingDebugVariablesDeclaration,\n} from '../shader-sizing.js';\nimport {\n simplexNoise,\n declarePI,\n rotation2,\n textureRandomizerR,\n proceduralHash21,\n proceduralHash11,\n} from '../shader-utils.js';\n\nexport const grainGradientMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Multi-color gradient with noise & grain over animated abstract shapes\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_softness (0..1): blur between color bands\n * - u_intensity (0..1): distortion between color bands\n * - u_noise (0..1): grainy noise independent of softness\n * - u_shape (float used as integer):\n * ---- 1: single sine wave\n * ---- 2: dots pattern\n * ---- 3: truchet pattern\n * ---- 4: corners (2 rounded rectangles)\n * ---- 5: ripple\n * ---- 6: blob (metaballs)\n * ---- 7: circle imitating 3d look\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit\n *\n */\n\n// language=GLSL\nexport const grainGradientFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump float u_time;\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${grainGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_noise;\nuniform float u_shape;\n\nuniform mediump float u_originX;\nuniform mediump float u_originY;\nuniform mediump float u_worldWidth;\nuniform mediump float u_worldHeight;\nuniform mediump float u_fit;\n\nuniform mediump float u_scale;\nuniform mediump float u_rotation;\nuniform mediump float u_offsetX;\nuniform mediump float u_offsetY;\n\n${sizingVariablesDeclaration}\n${ sizingDebugVariablesDeclaration }\n\nout vec4 fragColor;\n\n${declarePI}\n${simplexNoise}\n${rotation2}\n${proceduralHash21}\n${textureRandomizerR}\n\nfloat valueNoiseR(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbmR(vec2 n) {\n float total = 0.;\n float amplitude = .2;\n for (int i = 0; i < 3; i++) {\n n = rotate(n, .3);\n total += valueNoiseR(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.6;\n }\n return total;\n}\n\n${proceduralHash11}\n\nvec2 truchet(vec2 uv, float idx){\n idx = fract(((idx - .5) * 2.));\n if (idx > 0.75) {\n uv = vec2(1.0) - uv;\n } else if (idx > 0.5) {\n uv = vec2(1.0 - uv.x, uv.y);\n } else if (idx > 0.25) {\n uv = 1.0 - vec2(1.0 - uv.x, uv.y);\n }\n return uv;\n}\n\nvoid main() {\n\n float t = .1 * u_time;\n\n vec2 shape_uv = vec2(0.);\n vec2 grain_uv = vec2(0.);\n\n if (u_shape > 3.5) {\n shape_uv = v_objectUV;\n grain_uv = shape_uv;\n\n // apply inverse transform to grain_uv so it respects the originXY\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 grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n grain_uv -= graphicOffset;\n grain_uv *= v_objectBoxSize;\n grain_uv *= .7;\n } else {\n shape_uv = .5 * v_patternUV;\n grain_uv = 100. * v_patternUV;\n\n // apply inverse transform to grain_uv so it respects the originXY\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 grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n if (u_fit > 0.) {\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\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 float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n grain_uv -= graphicOffset / patternBoxScale;\n grain_uv *= 1.6;\n }\n\n\n float shape = 0.;\n\n if (u_shape < 1.5) {\n // Sine wave\n\n float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 2.5) {\n // Grid (dots)\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx + 2.);\n rand = sign(rand - .5) * pow(.2 + abs(rand), .3);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(shape, 4.);\n\n } else if (u_shape < 3.5) {\n // Truchet pattern\n\n float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t);\n shape_uv.x += 10.;\n shape_uv *= .6;\n\n vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv)));\n\n float distance1 = length(tile);\n float distance2 = length(tile - vec2(1.));\n\n n2 -= .5;\n n2 *= .1;\n shape = smoothstep(.2, .55, distance1 + n2) * smoothstep(.8, .45, distance1 - n2);\n shape += smoothstep(.2, .55, distance2 + n2) * smoothstep(.8, .45, distance2 - n2);\n\n shape = pow(shape, 1.5);\n\n } else if (u_shape < 4.5) {\n // Corners\n\n shape_uv *= .6;\n vec2 outer = vec2(.5);\n\n vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t)));\n vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape = 1. - bl.x * bl.y * tr.x * tr.y;\n\n shape_uv = -shape_uv;\n bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t)));\n tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape -= bl.x * bl.y * tr.x * tr.y;\n\n shape = 1. - smoothstep(0., 1., shape);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n shape_uv *= 2.;\n float dist = length(.4 * shape_uv);\n float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Blob\n\n t *= 2.;\n\n vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.));\n vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t));\n vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t));\n vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.));\n\n shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.);\n\n shape = smoothstep(.0, .9, shape);\n float edge = smoothstep(.25, .3, shape);\n shape = mix(.0, shape, edge);\n\n } else {\n // Sphere\n\n shape_uv *= 2.;\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(d));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n float simplex = snoise(grain_uv * .5);\n float grainDist = simplex * snoise(grain_uv * .2) - fbmR(.002 * grain_uv + 10.) - fbmR(.003 * grain_uv);\n float rawNoise = .6 * simplex - fbmR(rotate(.4 * grain_uv, 2.)) - fbmR(.001 * grain_uv);\n float noise = clamp(rawNoise, 0., 1.);\n\n shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);\n shape += u_noise * 10. / u_colorsCount * noise;\n\n float aa = fwidth(shape);\n\n shape = clamp(shape - .5 / u_colorsCount, 0., 1.);\n float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.));\n float mixer = shape * (u_colorsCount - 1.);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${grainGradientMeta.maxColorCount}; i++) {\n if (i > int(u_colorsCount) - 1) break;\n\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, 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 * totalShape;\n float opacity = gradient.a * totalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GrainGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_softness: number;\n u_intensity: number;\n u_noise: number;\n u_shape: (typeof GrainGradientShapes)[GrainGradientShape];\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n softness?: number;\n intensity?: number;\n noise?: number;\n shape?: GrainGradientShape;\n}\n\nexport const GrainGradientShapes = {\n wave: 1,\n dots: 2,\n truchet: 3,\n corners: 4,\n ripple: 5,\n blob: 6,\n sphere: 7,\n};\n\nexport type GrainGradientShape = keyof typeof GrainGradientShapes;\n"],
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n sizingDebugVariablesDeclaration,\n} from '../shader-sizing.js';\nimport {\n simplexNoise,\n declarePI,\n rotation2,\n textureRandomizerR,\n proceduralHash21,\n proceduralHash11,\n} from '../shader-utils.js';\n\nexport const grainGradientMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Multi-color gradient with noise & grain over animated abstract shapes\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_softness (0..1): blur between color bands\n * - u_intensity (0..1): distortion between color bands\n * - u_noise (0..1): grainy noise independent of softness\n * - u_shape (float used as integer):\n * ---- 1: single sine wave\n * ---- 2: dots pattern\n * ---- 3: truchet pattern\n * ---- 4: corners (2 rounded rectangles)\n * ---- 5: ripple\n * ---- 6: blob (metaballs)\n * ---- 7: circle imitating 3d look\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit\n *\n */\n\n// language=GLSL\nexport const grainGradientFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump float u_time;\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${grainGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_noise;\nuniform float u_shape;\n\nuniform mediump float u_originX;\nuniform mediump float u_originY;\nuniform mediump float u_worldWidth;\nuniform mediump float u_worldHeight;\nuniform mediump float u_fit;\n\nuniform mediump float u_scale;\nuniform mediump float u_rotation;\nuniform mediump float u_offsetX;\nuniform mediump float u_offsetY;\n\n${sizingVariablesDeclaration}\n${ sizingDebugVariablesDeclaration }\n\nout vec4 fragColor;\n\n${declarePI}\n${simplexNoise}\n${rotation2}\n${proceduralHash21}\n${textureRandomizerR}\n\nfloat valueNoiseR(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbmR(vec2 n) {\n float total = 0.;\n float amplitude = .2;\n for (int i = 0; i < 3; i++) {\n n = rotate(n, .3);\n total += valueNoiseR(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.6;\n }\n return total;\n}\n\n${proceduralHash11}\n\nvec2 truchet(vec2 uv, float idx){\n idx = fract(((idx - .5) * 2.));\n if (idx > 0.75) {\n uv = vec2(1.0) - uv;\n } else if (idx > 0.5) {\n uv = vec2(1.0 - uv.x, uv.y);\n } else if (idx > 0.25) {\n uv = 1.0 - vec2(1.0 - uv.x, uv.y);\n }\n return uv;\n}\n\nvoid main() {\n\n float t = .1 * u_time;\n\n vec2 shape_uv = vec2(0.);\n vec2 grain_uv = vec2(0.);\n\n if (u_shape > 3.5) {\n shape_uv = v_objectUV;\n grain_uv = shape_uv;\n\n // apply inverse transform to grain_uv so it respects the originXY\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 grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n grain_uv -= graphicOffset;\n grain_uv *= v_objectBoxSize;\n grain_uv *= .7;\n } else {\n shape_uv = .5 * v_patternUV;\n grain_uv = 100. * v_patternUV;\n\n // apply inverse transform to grain_uv so it respects the originXY\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 grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n if (u_fit > 0.) {\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\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 float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n grain_uv -= graphicOffset / patternBoxScale;\n grain_uv *= 1.6;\n }\n\n\n float shape = 0.;\n\n if (u_shape < 1.5) {\n // Sine wave\n\n float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 2.5) {\n // Grid (dots)\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx * 100.);\n rand = sign(rand - .5) * pow(4. * abs(rand), .3);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(shape, 4.);\n\n } else if (u_shape < 3.5) {\n // Truchet pattern\n\n float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t);\n shape_uv.x += 10.;\n shape_uv *= .6;\n\n vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv)));\n\n float distance1 = length(tile);\n float distance2 = length(tile - vec2(1.));\n\n n2 -= .5;\n n2 *= .1;\n shape = smoothstep(.2, .55, distance1 + n2) * smoothstep(.8, .45, distance1 - n2);\n shape += smoothstep(.2, .55, distance2 + n2) * smoothstep(.8, .45, distance2 - n2);\n\n shape = pow(shape, 1.5);\n\n } else if (u_shape < 4.5) {\n // Corners\n\n shape_uv *= .6;\n vec2 outer = vec2(.5);\n\n vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t)));\n vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape = 1. - bl.x * bl.y * tr.x * tr.y;\n\n shape_uv = -shape_uv;\n bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t)));\n tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape -= bl.x * bl.y * tr.x * tr.y;\n\n shape = 1. - smoothstep(0., 1., shape);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n shape_uv *= 2.;\n float dist = length(.4 * shape_uv);\n float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Blob\n\n t *= 2.;\n\n vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.));\n vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t));\n vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t));\n vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.));\n\n shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.);\n\n shape = smoothstep(.0, .9, shape);\n float edge = smoothstep(.25, .3, shape);\n shape = mix(.0, shape, edge);\n\n } else {\n // Sphere\n\n shape_uv *= 2.;\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(d));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n float simplex = snoise(grain_uv * .5);\n float grainDist = simplex * snoise(grain_uv * .2) - fbmR(.002 * grain_uv + 10.) - fbmR(.003 * grain_uv);\n float rawNoise = .75 * simplex - fbmR(rotate(.4 * grain_uv, 2.)) - fbmR(.001 * grain_uv);\n float noise = clamp(rawNoise, 0., 1.);\n\n shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);\n shape += u_noise * 10. / u_colorsCount * noise;\n\n float aa = fwidth(shape);\n\n shape = clamp(shape - .5 / u_colorsCount, 0., 1.);\n float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.));\n float mixer = shape * (u_colorsCount - 1.);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${grainGradientMeta.maxColorCount}; i++) {\n if (i > int(u_colorsCount) - 1) break;\n\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, 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 * totalShape;\n float opacity = gradient.a * totalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GrainGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_softness: number;\n u_intensity: number;\n u_noise: number;\n u_shape: (typeof GrainGradientShapes)[GrainGradientShape];\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n softness?: number;\n intensity?: number;\n noise?: number;\n shape?: GrainGradientShape;\n}\n\nexport const GrainGradientShapes = {\n wave: 1,\n dots: 2,\n truchet: 3,\n corners: 4,\n ripple: 5,\n blob: 6,\n sphere: 7,\n};\n\nexport type GrainGradientShape = keyof typeof GrainGradientShapes;\n"],
5
5
  "mappings": ";;;;;AAEA;AAAA,EACE;AAAA,EAGA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AACjB;AA2BO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAU3B,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBrD,0BAA0B;AAAA,EACzB,+BAAgC;AAAA;AAAA;AAAA;AAAA,EAIjC,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,kBAAkB;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,EA0BlB,gBAAgB;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;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;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,wBAyKM,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0ChD,MAAM,sBAAsB;AAAA,EACjC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AACV;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,7 @@ import type { ShaderMotionParams } from '../shader-mount.js';
2
2
  import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
3
3
  /**
4
4
  *
5
- * Fractal-like structure made of several layers of since arches
5
+ * Fractal-like structure made of several layers of sine arches
6
6
  * Original algorithm: https://x.com/zozuar/status/1625182758745128981/
7
7
  *
8
8
  * Uniforms:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/neuro-noise.ts"],
4
- "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, colorBandingFix } from '../shader-utils.js';\n\n/**\n *\n * Fractal-like structure made of several layers of since arches\n * Original algorithm: https://x.com/zozuar/status/1625182758745128981/\n *\n * Uniforms:\n * - u_colorBack, u_colorMid, u_colorFront (RGBA)\n * - u_brightness, u_contrast\n *\n */\n\n// language=GLSL\nexport const neuroNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorMid;\nuniform vec4 u_colorBack;\nuniform float u_brightness;\nuniform float u_contrast;\n\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${rotation2}\n\nfloat neuroShape(vec2 uv, float t) {\n vec2 sine_acc = vec2(0.);\n vec2 res = vec2(0.);\n float scale = 8.;\n\n for (int j = 0; j < 15; j++) {\n uv = rotate(uv, 1.);\n sine_acc = rotate(sine_acc, 1.);\n vec2 layer = uv * scale + float(j) + sine_acc - t;\n sine_acc += sin(layer);\n res += (.5 + .5 * cos(layer)) / scale;\n scale *= (1.2);\n }\n return res.x + res.y;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .13;\n\n float t = .5 * u_time;\n\n float noise = neuroShape(shape_uv, t);\n\n noise = (1. + u_brightness) * pow(noise, 2.);\n noise = pow(noise, .7 + 6. * u_contrast);\n noise = min(1.4, noise);\n\n float blend = smoothstep(0.7, 1.4, noise);\n\n vec4 frontC = u_colorFront;\n frontC.rgb *= frontC.a;\n vec4 midC = u_colorMid;\n midC.rgb *= midC.a;\n vec4 blendFront = mix(midC, frontC, blend);\n\n float safeNoise = max(noise, 0.0);\n vec3 color = blendFront.rgb * safeNoise;\n float opacity = clamp(blendFront.a * safeNoise, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface NeuroNoiseUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorMid: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_brightness: number;\n u_contrast: number;\n}\n\nexport interface NeuroNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colorFront?: string;\n colorMid?: string;\n colorBack?: string;\n brightness?: number;\n contrast?: number;\n}\n"],
4
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, colorBandingFix } from '../shader-utils.js';\n\n/**\n *\n * Fractal-like structure made of several layers of sine arches\n * Original algorithm: https://x.com/zozuar/status/1625182758745128981/\n *\n * Uniforms:\n * - u_colorBack, u_colorMid, u_colorFront (RGBA)\n * - u_brightness, u_contrast\n *\n */\n\n// language=GLSL\nexport const neuroNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorMid;\nuniform vec4 u_colorBack;\nuniform float u_brightness;\nuniform float u_contrast;\n\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${rotation2}\n\nfloat neuroShape(vec2 uv, float t) {\n vec2 sine_acc = vec2(0.);\n vec2 res = vec2(0.);\n float scale = 8.;\n\n for (int j = 0; j < 15; j++) {\n uv = rotate(uv, 1.);\n sine_acc = rotate(sine_acc, 1.);\n vec2 layer = uv * scale + float(j) + sine_acc - t;\n sine_acc += sin(layer);\n res += (.5 + .5 * cos(layer)) / scale;\n scale *= (1.2);\n }\n return res.x + res.y;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .13;\n\n float t = .5 * u_time;\n\n float noise = neuroShape(shape_uv, t);\n\n noise = (1. + u_brightness) * pow(noise, 2.);\n noise = pow(noise, .7 + 6. * u_contrast);\n noise = min(1.4, noise);\n\n float blend = smoothstep(0.7, 1.4, noise);\n\n vec4 frontC = u_colorFront;\n frontC.rgb *= frontC.a;\n vec4 midC = u_colorMid;\n midC.rgb *= midC.a;\n vec4 blendFront = mix(midC, frontC, blend);\n\n float safeNoise = max(noise, 0.0);\n vec3 color = blendFront.rgb * safeNoise;\n float opacity = clamp(blendFront.a * safeNoise, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface NeuroNoiseUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorMid: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_brightness: number;\n u_contrast: number;\n}\n\nexport interface NeuroNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colorFront?: string;\n colorMid?: string;\n colorBack?: string;\n brightness?: number;\n contrast?: number;\n}\n"],
5
5
  "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,uBAAuB;AAcpC,MAAM,2BAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc9C,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8CP,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -205,27 +205,29 @@ void main() {
205
205
  normalImage += .2 * fiber;
206
206
 
207
207
  vec3 lightPos = vec3(1., 2., 1.);
208
- float res = clamp(dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos)), 0., 1.);
208
+ float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos));
209
209
 
210
210
  vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
211
211
  float fgOpacity = u_colorFront.a;
212
212
  vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
213
213
  float bgOpacity = u_colorBack.a;
214
214
 
215
+ imageUV += .02 * normalImage;
216
+ float frame = getUvFrame(imageUV);
217
+
215
218
  vec3 color = fgColor * res;
216
219
  float opacity = fgOpacity * res;
217
220
 
218
221
  color += bgColor * (1. - opacity);
219
222
  opacity += bgOpacity * (1. - opacity);
223
+ opacity = mix(opacity, 1., frame);
220
224
 
221
225
  color -= .007 * drops;
222
226
 
223
- imageUV += .02 * normalImage;
224
227
  vec4 image = texture(u_image, imageUV);
225
- image.rgb += .5 * (res - .6);
228
+ image.rgb += .6 * pow(u_contrast, .4) * (res - .7);
226
229
 
227
- float frame = getUvFrame(imageUV);
228
- color.rgb = mix(color, image.rgb, min(.8 * frame, image.a));
230
+ color.rgb = mix(color, image.rgb, min(frame, image.a));
229
231
 
230
232
  fragColor = vec4(color, opacity);
231
233
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/paper-texture.ts"],
4
- "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * Mimicking paper texture with a combination of noises\n *\n * Uniforms:\n * - u_colorFront, u_colorBack (RGBA)\n * - u_contrast - mixing front and back colors\n * - u_roughness - pixel noise, related to canvas => not scalable\n * - u_fiber, u_fiberScale - curly shaped noise\n * - u_crumples, u_crumplesScale - cell-based pattern\n * - u_folds, u_foldsNumber - lines pattern, 15 max\n * - u_drops - metaballs-like pattern\n * - u_seed - applied to folds, crumples and dots\n * - u_blur - big-scale noise mask applied to everything but roughness\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_contrast;\nuniform float u_roughness;\nuniform float u_fiber;\nuniform float u_fiberScale;\nuniform float u_crumples;\nuniform float u_crumplesScale;\nuniform float u_folds;\nuniform float u_foldsNumber;\nuniform float u_drops;\nuniform float u_seed;\nuniform float u_blur;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\n${declarePI}\n${rotation2}\n${textureRandomizerR}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbm(vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < 3; i++) {\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat roughness(vec2 p) {\n p *= .1;\n float o = 0.;\n for (float i = 0.; ++i < 4.; p *= 2.1) {\n vec4 w = vec4(floor(p), ceil(p));\n vec2 f = fract(p);\n o += mix(\n mix(randomG(w.xy), randomG(w.xw), f.y),\n mix(randomG(w.zy), randomG(w.zw), f.y),\n f.x);\n o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));\n }\n return o / 3.;\n}\n\n${fiberNoise}\n\nvec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n}\nfloat crumpledNoise(vec2 t, float pw) {\n vec2 p = floor(t);\n float wsum = 0.;\n float cl = 0.;\n for (int y = -1; y < 2; y += 1) {\n for (int x = -1; x < 2; x += 1) {\n vec2 b = vec2(float(x), float(y));\n vec2 q = b + p;\n vec2 q2 = q - floor(q / 8.) * 8.;\n vec2 c = q + randomGB(q2);\n vec2 r = c - t;\n float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);\n cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;\n wsum += w;\n }\n }\n return pow(cl / wsum, .5) * 2.;\n}\nfloat crumplesShape(vec2 uv) {\n return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);\n}\n\n\nvec2 folds(vec2 uv) {\n vec3 pp = vec3(0.);\n float l = 9.;\n for (float i = 0.; i < 15.; i++) {\n if (i >= u_foldsNumber) break;\n vec2 rand = randomGB(vec2(i, i * u_seed));\n float an = rand.x * TWO_PI;\n vec2 p = vec2(cos(an), sin(an)) * rand.y;\n float dist = distance(uv, p);\n l = min(l, dist);\n \n if (l == dist) {\n pp.xy = (uv - p.xy);\n pp.z = dist;\n }\n }\n return mix(pp.xy, vec2(0.), pow(pp.z, .25));\n}\n\nfloat drops(vec2 uv) {\n vec2 iDropsUV = floor(uv);\n vec2 fDropsUV = fract(uv);\n float dropsMinDist = 1.;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 neighbor = vec2(float(i), float(j));\n vec2 offset = randomGB(iDropsUV + neighbor);\n offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset);\n vec2 pos = neighbor + offset - fDropsUV;\n float dist = length(pos);\n dropsMinDist = min(dropsMinDist, dropsMinDist*dist);\n }\n }\n return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));\n}\n\nvoid main() {\n\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.));\n\n vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;\n float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));\n\n vec2 crumplesUV = fract(patternUV * .1 * u_crumplesScale - u_seed) * 32.;\n float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));\n\n vec2 fiberUV = 10. * u_fiberScale * patternUV;\n float fiber = fiberNoise(fiberUV, vec2(0.));\n fiber = .5 * u_fiber * (fiber - 1.);\n\n vec2 normal = vec2(0.);\n vec2 normalImage = vec2(0.);\n\n vec2 foldsUV = patternUV * .12;\n foldsUV = rotate(foldsUV, 4. * u_seed);\n vec2 w = folds(foldsUV);\n foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed));\n vec2 w2 = folds(foldsUV);\n\n float drops = u_drops * drops(patternUV * 2.);\n \n normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);\n normalImage.xy += u_folds * 2. * w;\n\n normal.xy += crumples;\n normalImage.xy += 1.5 * crumples;\n\n normal.xy += 3. * drops;\n normalImage.xy += .2 * drops;\n\n float blur = u_blur * smoothstep(0., 1., fbm(.17 * patternUV + 10. * u_seed));\n normal *= (1. - 2. * blur);\n fiber *= (1. - blur);\n\n normal.xy += u_roughness * 1.5 * roughness;\n normal.xy += fiber;\n \n normalImage += u_roughness * .75 * roughness;\n normalImage += .2 * fiber;\n\n vec3 lightPos = vec3(1., 2., 1.);\n float res = clamp(dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos)), 0., 1.);\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n \n color -= .007 * drops;\n\n imageUV += .02 * normalImage;\n vec4 image = texture(u_image, imageUV);\n image.rgb += .5 * (res - .6);\n\n float frame = getUvFrame(imageUV);\n color.rgb = mix(color, image.rgb, min(.8 * frame, image.a));\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PaperTextureUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_contrast: number;\n u_roughness: number;\n u_fiber: number;\n u_fiberScale: number;\n u_crumples: number;\n u_foldsNumber: number;\n u_folds: number;\n u_blur: number;\n u_crumplesScale: number;\n u_drops: number;\n u_seed: number;\n}\n\nexport interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string | undefined;\n colorFront?: string;\n colorBack?: string;\n contrast?: number;\n roughness?: number;\n fiber?: number;\n fiberScale?: number;\n crumples?: number;\n foldsNumber?: number;\n folds?: number;\n blur?: number;\n crumplesScale?: number;\n drops?: number;\n seed?: number;\n}\n"],
5
- "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,YAAY,0BAA0B;AAqB9D,MAAM,6BAAqC;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,EA2BhD,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,kBAAkB;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,EA2ClB,UAAU;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * Mimicking paper texture with a combination of noises\n *\n * Uniforms:\n * - u_colorFront, u_colorBack (RGBA)\n * - u_contrast - mixing front and back colors\n * - u_roughness - pixel noise, related to canvas => not scalable\n * - u_fiber, u_fiberScale - curly shaped noise\n * - u_crumples, u_crumplesScale - cell-based pattern\n * - u_folds, u_foldsNumber - lines pattern, 15 max\n * - u_drops - metaballs-like pattern\n * - u_seed - applied to folds, crumples and dots\n * - u_blur - big-scale noise mask applied to everything but roughness\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_contrast;\nuniform float u_roughness;\nuniform float u_fiber;\nuniform float u_fiberScale;\nuniform float u_crumples;\nuniform float u_crumplesScale;\nuniform float u_folds;\nuniform float u_foldsNumber;\nuniform float u_drops;\nuniform float u_seed;\nuniform float u_blur;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\n${declarePI}\n${rotation2}\n${textureRandomizerR}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbm(vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < 3; i++) {\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat roughness(vec2 p) {\n p *= .1;\n float o = 0.;\n for (float i = 0.; ++i < 4.; p *= 2.1) {\n vec4 w = vec4(floor(p), ceil(p));\n vec2 f = fract(p);\n o += mix(\n mix(randomG(w.xy), randomG(w.xw), f.y),\n mix(randomG(w.zy), randomG(w.zw), f.y),\n f.x);\n o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));\n }\n return o / 3.;\n}\n\n${fiberNoise}\n\nvec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n}\nfloat crumpledNoise(vec2 t, float pw) {\n vec2 p = floor(t);\n float wsum = 0.;\n float cl = 0.;\n for (int y = -1; y < 2; y += 1) {\n for (int x = -1; x < 2; x += 1) {\n vec2 b = vec2(float(x), float(y));\n vec2 q = b + p;\n vec2 q2 = q - floor(q / 8.) * 8.;\n vec2 c = q + randomGB(q2);\n vec2 r = c - t;\n float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);\n cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;\n wsum += w;\n }\n }\n return pow(cl / wsum, .5) * 2.;\n}\nfloat crumplesShape(vec2 uv) {\n return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);\n}\n\n\nvec2 folds(vec2 uv) {\n vec3 pp = vec3(0.);\n float l = 9.;\n for (float i = 0.; i < 15.; i++) {\n if (i >= u_foldsNumber) break;\n vec2 rand = randomGB(vec2(i, i * u_seed));\n float an = rand.x * TWO_PI;\n vec2 p = vec2(cos(an), sin(an)) * rand.y;\n float dist = distance(uv, p);\n l = min(l, dist);\n \n if (l == dist) {\n pp.xy = (uv - p.xy);\n pp.z = dist;\n }\n }\n return mix(pp.xy, vec2(0.), pow(pp.z, .25));\n}\n\nfloat drops(vec2 uv) {\n vec2 iDropsUV = floor(uv);\n vec2 fDropsUV = fract(uv);\n float dropsMinDist = 1.;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 neighbor = vec2(float(i), float(j));\n vec2 offset = randomGB(iDropsUV + neighbor);\n offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset);\n vec2 pos = neighbor + offset - fDropsUV;\n float dist = length(pos);\n dropsMinDist = min(dropsMinDist, dropsMinDist*dist);\n }\n }\n return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));\n}\n\nvoid main() {\n\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.));\n\n vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;\n float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));\n\n vec2 crumplesUV = fract(patternUV * .1 * u_crumplesScale - u_seed) * 32.;\n float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));\n\n vec2 fiberUV = 10. * u_fiberScale * patternUV;\n float fiber = fiberNoise(fiberUV, vec2(0.));\n fiber = .5 * u_fiber * (fiber - 1.);\n\n vec2 normal = vec2(0.);\n vec2 normalImage = vec2(0.);\n\n vec2 foldsUV = patternUV * .12;\n foldsUV = rotate(foldsUV, 4. * u_seed);\n vec2 w = folds(foldsUV);\n foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed));\n vec2 w2 = folds(foldsUV);\n\n float drops = u_drops * drops(patternUV * 2.);\n \n normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);\n normalImage.xy += u_folds * 2. * w;\n\n normal.xy += crumples;\n normalImage.xy += 1.5 * crumples;\n\n normal.xy += 3. * drops;\n normalImage.xy += .2 * drops;\n\n float blur = u_blur * smoothstep(0., 1., fbm(.17 * patternUV + 10. * u_seed));\n normal *= (1. - 2. * blur);\n fiber *= (1. - blur);\n\n normal.xy += u_roughness * 1.5 * roughness;\n normal.xy += fiber;\n \n normalImage += u_roughness * .75 * roughness;\n normalImage += .2 * fiber;\n\n vec3 lightPos = vec3(1., 2., 1.);\n float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos));\n\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n\n imageUV += .02 * normalImage;\n float frame = getUvFrame(imageUV);\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n opacity = mix(opacity, 1., frame);\n \n color -= .007 * drops;\n\n vec4 image = texture(u_image, imageUV);\n image.rgb += .6 * pow(u_contrast, .4) * (res - .7);\n\n color.rgb = mix(color, image.rgb, min(frame, image.a));\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PaperTextureUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_contrast: number;\n u_roughness: number;\n u_fiber: number;\n u_fiberScale: number;\n u_crumples: number;\n u_foldsNumber: number;\n u_folds: number;\n u_blur: number;\n u_crumplesScale: number;\n u_drops: number;\n u_seed: number;\n}\n\nexport interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string | undefined;\n colorFront?: string;\n colorBack?: string;\n contrast?: number;\n roughness?: number;\n fiber?: number;\n fiberScale?: number;\n crumples?: number;\n foldsNumber?: number;\n folds?: number;\n blur?: number;\n crumplesScale?: number;\n drops?: number;\n seed?: number;\n}\n"],
5
+ "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,YAAY,0BAA0B;AAqB9D,MAAM,6BAAqC;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,EA2BhD,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,kBAAkB;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,EA2ClB,UAAU;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -146,7 +146,7 @@ void main() {
146
146
  m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));
147
147
  cornerFadeMask += m;
148
148
  }
149
-
149
+ cornerFade = clamp(cornerFade, 0., 1.);
150
150
  cornerFade *= cornerFadeMask;
151
151
  border += cornerFade;
152
152
 
@@ -161,6 +161,8 @@ void main() {
161
161
  smoke = clamp(smoke, 0., 1.);
162
162
 
163
163
  border += smoke;
164
+ float borderBounds = 1. - smoothstep(.9, 1., length(v_responsiveUV));
165
+ border *= borderBounds;
164
166
  border = clamp(border, 0., 1.);
165
167
 
166
168
  vec3 blendColor = vec3(0.);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/pulsing-border.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerGB, colorBandingFix } from '../shader-utils.js';\n\nexport const pulsingBorderMeta = {\n maxColorCount: 5,\n maxSpots: 4,\n} as const;\n\n/**\n * Color spots traveling around rectangular stroke (border)\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_roundness, u_thickness, u_softness: border parameters\n * - u_intensity: thickness of individual spots\n * - u_bloom: normal / additive color blending\n * - u_spotSize: angular size of spots\n * - u_spots (float used as int): number of spots rendered per color\n * - u_pulse: optional pulsing animation\n * - u_smoke, u_smokeSize: optional noisy shapes around the border\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const pulsingBorderFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_roundness;\nuniform float u_thickness;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_bloom;\nuniform float u_spotSize;\nuniform float u_spots;\nuniform float u_pulse;\nuniform float u_smoke;\nuniform float u_smokeSize;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat beat(float time) {\n float first = pow(sin(time * TWO_PI), 10.);\n float second = pow(sin((time - 0.15) * TWO_PI), 10.);\n\n return clamp(first + 0.6 * second, 0.0, 1.0);\n}\n\nfloat roundedBox(vec2 uv, float distance) {\n float thickness = .5 * u_thickness;\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-u_softness * thickness - 2. * fwidth(borderDistance), .5 * u_softness * thickness, borderDistance - .5 * thickness);\n border = pow(border, 2.);\n\n return border;\n}\n\nfloat roundedBoxSmoke(vec2 uv, float distance, float size) {\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-.75 * size, .75 * size, borderDistance);\n border *= border;\n return border;\n}\n\n${textureRandomizerGB}\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomG(i);\n float b = randomG(i + vec2(1.0, 0.0));\n float c = randomG(i + vec2(0.0, 1.0));\n float d = randomG(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat linearstep(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n float t = 1.2 * u_time;\n\n vec2 borderUV = v_responsiveUV;\n\n float angle = atan(borderUV.y, borderUV.x) / TWO_PI;\n\n float pulse = u_pulse * beat(.18 * u_time);\n\n float borderRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n borderUV.x *= borderRatio;\n vec2 halfSize = vec2(.5);\n halfSize.x *= borderRatio;\n float radius = min(.5 * u_roundness, halfSize.x);\n vec2 d = abs(borderUV) - halfSize + radius;\n float outsideDistance = length(max(d, 0.)) - radius;\n float insideDistance = min(max(d.x, d.y), 0.0);\n float distance = outsideDistance + insideDistance;\n\n float border = roundedBox(borderUV, distance);\n\n vec2 v0 = borderUV + halfSize;\n vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);\n vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);\n vec2 v3 = borderUV - halfSize;\n\n float cornerFade = 1. - abs(v0.x - v0.y);\n cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));\n cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));\n cornerFade = max(cornerFade, 1. - abs(v3.x - v3.y));\n cornerFade = .75 * pow(cornerFade, 20.);\n\n float cornerFadeMask = 0.;\n float maskR = (.35 * u_thickness - .25 * radius);\n float maskHL = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, borderUV.x);\n float maskHR = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, -borderUV.x);\n float maskVT = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, -borderUV.y);\n float maskVB = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, borderUV.y);\n float maskOffset = .25 * (u_thickness + radius);\n {\n float m = maskHR;\n m *= maskVT;\n m *= (1. - clamp(length((v0 - maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHR;\n m *= maskVB;\n m *= (1. - clamp(length((v1 - vec2(1., -1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVT;\n m *= (1. - clamp(length((v2 - vec2(-1., 1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVB;\n m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n\n cornerFade *= cornerFadeMask;\n border += cornerFade;\n\n vec2 smokeUV = .2 * u_smokeSize * v_patternUV;\n float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);\n smoke -= valueNoise(3.4 * smokeUV - .5 * t);\n smoke *= roundedBoxSmoke(borderUV, distance, u_smoke);\n smoke = 30. * pow(smoke, 2.);\n smoke += cornerFadeMask;\n smoke *= u_smoke;\n smoke *= mix(1., pulse, u_pulse);\n smoke = clamp(smoke, 0., 1.);\n\n border += smoke;\n border = clamp(border, 0., 1.);\n\n vec3 blendColor = vec3(0.);\n float blendAlpha = 0.0;\n vec3 addColor = vec3(0.);\n float addAlpha = 0.0;\n\n float bloom = 4. * u_bloom;\n float intensity = 1. + 4. * u_intensity;\n\n for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {\n if (colorIdx >= int(u_colorsCount)) break;\n float colorIdxF = float(colorIdx);\n\n vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a;\n float a = u_colors[colorIdx].a;\n\n for (int spotIdx = 0; spotIdx < ${pulsingBorderMeta.maxSpots}; spotIdx++) {\n if (spotIdx >= int(u_spots)) break;\n float spotIdxF = float(spotIdx);\n\n vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));\n\n float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;\n time *= mix(1., -1., step(.5, randVal.y));\n\n float mask = .5 + .5 * mix(\n sin(t + spotIdxF * (5. - 1.5 * colorIdxF)),\n cos(t + spotIdxF * (3. + 1.3 * colorIdxF)),\n step(mod(colorIdxF, 2.), .5)\n );\n\n float p = clamp(2. * u_pulse - randVal.x, 0., 1.);\n mask = mix(mask, pulse, p);\n\n float atg1 = fract(angle + time);\n float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;\n spotSize = mix(spotSize, .1, p);\n float sector = smoothstep(.5 - spotSize, .5, atg1) * smoothstep(.5 + spotSize, .5, atg1);\n\n sector *= mask;\n sector *= border;\n sector *= intensity;\n sector = clamp(sector, 0., 1.);\n\n vec3 srcColor = c * sector;\n float srcAlpha = a * sector;\n\n blendColor += ((1. - blendAlpha) * srcColor);\n blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha;\n addColor += srcColor;\n addAlpha += srcAlpha;\n }\n }\n\n vec3 accumColor = mix(blendColor, addColor, bloom);\n float accumAlpha = mix(blendAlpha, addAlpha, bloom);\n accumAlpha = clamp(accumAlpha, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}`;\n\nexport interface PulsingBorderUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_roundness: number;\n u_thickness: number;\n u_softness: number;\n u_intensity: number;\n u_bloom: number;\n u_spots: number;\n u_spotSize: number;\n u_pulse: number;\n u_smoke: number;\n u_smokeSize: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n roundness?: number;\n thickness?: number;\n softness?: number;\n intensity?: number;\n bloom?: number;\n spots?: number;\n spotSize?: number;\n pulse?: number;\n smoke?: number;\n smokeSize?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,qBAAqB,uBAAuB;AAEzD,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AACZ;AAqBO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM3B,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAerD,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,EAyBT,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;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,sCAgHiB,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAO/B,kBAAkB,QAAQ;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,IA8C5D,eAAe;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerGB, colorBandingFix } from '../shader-utils.js';\n\nexport const pulsingBorderMeta = {\n maxColorCount: 5,\n maxSpots: 4,\n} as const;\n\n/**\n * Color spots traveling around rectangular stroke (border)\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_roundness, u_thickness, u_softness: border parameters\n * - u_intensity: thickness of individual spots\n * - u_bloom: normal / additive color blending\n * - u_spotSize: angular size of spots\n * - u_spots (float used as int): number of spots rendered per color\n * - u_pulse: optional pulsing animation\n * - u_smoke, u_smokeSize: optional noisy shapes around the border\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const pulsingBorderFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_roundness;\nuniform float u_thickness;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_bloom;\nuniform float u_spotSize;\nuniform float u_spots;\nuniform float u_pulse;\nuniform float u_smoke;\nuniform float u_smokeSize;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat beat(float time) {\n float first = pow(sin(time * TWO_PI), 10.);\n float second = pow(sin((time - 0.15) * TWO_PI), 10.);\n\n return clamp(first + 0.6 * second, 0.0, 1.0);\n}\n\nfloat roundedBox(vec2 uv, float distance) {\n float thickness = .5 * u_thickness;\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-u_softness * thickness - 2. * fwidth(borderDistance), .5 * u_softness * thickness, borderDistance - .5 * thickness);\n border = pow(border, 2.);\n\n return border;\n}\n\nfloat roundedBoxSmoke(vec2 uv, float distance, float size) {\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-.75 * size, .75 * size, borderDistance);\n border *= border;\n return border;\n}\n\n${textureRandomizerGB}\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomG(i);\n float b = randomG(i + vec2(1.0, 0.0));\n float c = randomG(i + vec2(0.0, 1.0));\n float d = randomG(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat linearstep(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n float t = 1.2 * u_time;\n\n vec2 borderUV = v_responsiveUV;\n\n float angle = atan(borderUV.y, borderUV.x) / TWO_PI;\n\n float pulse = u_pulse * beat(.18 * u_time);\n\n float borderRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n borderUV.x *= borderRatio;\n vec2 halfSize = vec2(.5);\n halfSize.x *= borderRatio;\n float radius = min(.5 * u_roundness, halfSize.x);\n vec2 d = abs(borderUV) - halfSize + radius;\n float outsideDistance = length(max(d, 0.)) - radius;\n float insideDistance = min(max(d.x, d.y), 0.0);\n float distance = outsideDistance + insideDistance;\n\n float border = roundedBox(borderUV, distance);\n\n vec2 v0 = borderUV + halfSize;\n vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);\n vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);\n vec2 v3 = borderUV - halfSize;\n\n float cornerFade = 1. - abs(v0.x - v0.y);\n cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));\n cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));\n cornerFade = max(cornerFade, 1. - abs(v3.x - v3.y));\n cornerFade = .75 * pow(cornerFade, 20.);\n\n float cornerFadeMask = 0.;\n float maskR = (.35 * u_thickness - .25 * radius);\n float maskHL = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, borderUV.x);\n float maskHR = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, -borderUV.x);\n float maskVT = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, -borderUV.y);\n float maskVB = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, borderUV.y);\n float maskOffset = .25 * (u_thickness + radius);\n {\n float m = maskHR;\n m *= maskVT;\n m *= (1. - clamp(length((v0 - maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHR;\n m *= maskVB;\n m *= (1. - clamp(length((v1 - vec2(1., -1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVT;\n m *= (1. - clamp(length((v2 - vec2(-1., 1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVB;\n m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n cornerFade = clamp(cornerFade, 0., 1.);\n cornerFade *= cornerFadeMask;\n border += cornerFade;\n\n vec2 smokeUV = .2 * u_smokeSize * v_patternUV;\n float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);\n smoke -= valueNoise(3.4 * smokeUV - .5 * t);\n smoke *= roundedBoxSmoke(borderUV, distance, u_smoke);\n smoke = 30. * pow(smoke, 2.);\n smoke += cornerFadeMask;\n smoke *= u_smoke;\n smoke *= mix(1., pulse, u_pulse);\n smoke = clamp(smoke, 0., 1.);\n\n border += smoke;\n float borderBounds = 1. - smoothstep(.9, 1., length(v_responsiveUV));\n border *= borderBounds;\n border = clamp(border, 0., 1.);\n\n vec3 blendColor = vec3(0.);\n float blendAlpha = 0.0;\n vec3 addColor = vec3(0.);\n float addAlpha = 0.0;\n\n float bloom = 4. * u_bloom;\n float intensity = 1. + 4. * u_intensity;\n\n for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {\n if (colorIdx >= int(u_colorsCount)) break;\n float colorIdxF = float(colorIdx);\n\n vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a;\n float a = u_colors[colorIdx].a;\n\n for (int spotIdx = 0; spotIdx < ${pulsingBorderMeta.maxSpots}; spotIdx++) {\n if (spotIdx >= int(u_spots)) break;\n float spotIdxF = float(spotIdx);\n\n vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));\n\n float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;\n time *= mix(1., -1., step(.5, randVal.y));\n\n float mask = .5 + .5 * mix(\n sin(t + spotIdxF * (5. - 1.5 * colorIdxF)),\n cos(t + spotIdxF * (3. + 1.3 * colorIdxF)),\n step(mod(colorIdxF, 2.), .5)\n );\n\n float p = clamp(2. * u_pulse - randVal.x, 0., 1.);\n mask = mix(mask, pulse, p);\n\n float atg1 = fract(angle + time);\n float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;\n spotSize = mix(spotSize, .1, p);\n float sector = smoothstep(.5 - spotSize, .5, atg1) * smoothstep(.5 + spotSize, .5, atg1);\n\n sector *= mask;\n sector *= border;\n sector *= intensity;\n sector = clamp(sector, 0., 1.);\n\n vec3 srcColor = c * sector;\n float srcAlpha = a * sector;\n\n blendColor += ((1. - blendAlpha) * srcColor);\n blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha;\n addColor += srcColor;\n addAlpha += srcAlpha;\n }\n }\n\n vec3 accumColor = mix(blendColor, addColor, bloom);\n float accumAlpha = mix(blendAlpha, addAlpha, bloom);\n accumAlpha = clamp(accumAlpha, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}`;\n\nexport interface PulsingBorderUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_roundness: number;\n u_thickness: number;\n u_softness: number;\n u_intensity: number;\n u_bloom: number;\n u_spots: number;\n u_spotSize: number;\n u_pulse: number;\n u_smoke: number;\n u_smokeSize: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n roundness?: number;\n thickness?: number;\n softness?: number;\n intensity?: number;\n bloom?: number;\n spots?: number;\n spotSize?: number;\n pulse?: number;\n smoke?: number;\n smokeSize?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,qBAAqB,uBAAuB;AAEzD,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AACZ;AAqBO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM3B,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAerD,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,EAyBT,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;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,sCAkHiB,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAO/B,kBAAkB,QAAQ;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,IA8C5D,eAAe;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -35,7 +35,8 @@ float getNoise(vec2 uv, float t) {
35
35
  float steppedSmooth(float m, float steps, float softness) {
36
36
  float stepT = floor(m * steps) / steps;
37
37
  float f = m * steps - floor(m * steps);
38
- float smoothed = smoothstep(.5 - softness, .5 + softness, f);
38
+ float fw = steps * fwidth(m);
39
+ float smoothed = smoothstep(.5 - softness, min(1., .5 + softness + fw), f);
39
40
  return stepT + smoothed / steps;
40
41
  }
41
42
 
@@ -62,7 +63,7 @@ void main() {
62
63
  if (i >= int(u_colorsCount)) break;
63
64
 
64
65
  float localM = clamp(mixer - float(i - 1), 0., 1.);
65
- localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));
66
+ localM = steppedSmooth(localM, steps, .5 * u_softness);
66
67
 
67
68
  vec4 c = u_colors[i];
68
69
  c.rgb *= c.a;
@@ -75,7 +76,7 @@ void main() {
75
76
  if (mixer > (u_colorsCount - 1.)) {
76
77
  localM = mixer - (u_colorsCount - 1.);
77
78
  }
78
- localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));
79
+ localM = steppedSmooth(localM, steps, .5 * u_softness);
79
80
  vec4 cFst = u_colors[0];
80
81
  cFst.rgb *= cFst.a;
81
82
  vec4 cLast = u_colors[int(u_colorsCount - 1.)];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/simplex-noise.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const simplexNoiseMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Color Gradient mapped over a combination of 2 Simplex noises\n *\n * Uniforms:\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_stepsPerColor (float, used as int): discrete color steps between u_colors\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n *\n * */\n\n// language=GLSL\nexport const simplexNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform vec4 u_colors[${simplexNoiseMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${simplexNoise}\n\nfloat getNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nfloat steppedSmooth(float m, float steps, float softness) { \n float stepT = floor(m * steps) / steps;\n float f = m * steps - floor(m * steps);\n float smoothed = smoothstep(.5 - softness, .5 + softness, f);\n return stepT + smoothed / steps;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .1;\n\n float t = .2 * u_time;\n\n float shape = .5 + .5 * getNoise(shape_uv, t);\n\n bool u_extraSides = true;\n\n float mixer = shape * (u_colorsCount - 1.);\n if (u_extraSides == true) {\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n }\n\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 < ${simplexNoiseMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n float localM = clamp(mixer - float(i - 1), 0., 1.);\n localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localM);\n }\n\n if (u_extraSides == true) {\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localM = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localM = mixer - (u_colorsCount - 1.);\n }\n localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));\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, localM);\n }\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 SimplexNoiseUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_softness: number;\n}\n\nexport interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n softness?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,cAAc,uBAAuB;AAEvC,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAaO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,YAAY;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,wBAmCU,iBAAiB,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,IA6BlD,eAAe;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const simplexNoiseMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Color Gradient mapped over a combination of 2 Simplex noises\n *\n * Uniforms:\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_stepsPerColor (float, used as int): discrete color steps between u_colors\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n *\n * */\n\n// language=GLSL\nexport const simplexNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform vec4 u_colors[${simplexNoiseMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${simplexNoise}\n\nfloat getNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nfloat steppedSmooth(float m, float steps, float softness) { \n float stepT = floor(m * steps) / steps;\n float f = m * steps - floor(m * steps);\n float fw = steps * fwidth(m);\n float smoothed = smoothstep(.5 - softness, min(1., .5 + softness + fw), f);\n return stepT + smoothed / steps;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .1;\n\n float t = .2 * u_time;\n\n float shape = .5 + .5 * getNoise(shape_uv, t);\n\n bool u_extraSides = true;\n\n float mixer = shape * (u_colorsCount - 1.);\n if (u_extraSides == true) {\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n }\n\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 < ${simplexNoiseMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n float localM = clamp(mixer - float(i - 1), 0., 1.);\n localM = steppedSmooth(localM, steps, .5 * u_softness);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localM);\n }\n\n if (u_extraSides == true) {\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localM = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localM = mixer - (u_colorsCount - 1.);\n }\n localM = steppedSmooth(localM, steps, .5 * u_softness);\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, localM);\n }\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 SimplexNoiseUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_softness: number;\n}\n\nexport interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n softness?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,cAAc,uBAAuB;AAEvC,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAaO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,YAAY;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,wBAoCU,iBAAiB,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,IA6BlD,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -99,15 +99,14 @@ void main() {
99
99
 
100
100
  float ringShape = getRingShape(shape_uv);
101
101
 
102
- float mixer = pow(ringShape, 3.) * (u_colorsCount - 1.);
103
- vec4 gradient = u_colors[0];
102
+ float mixer = pow(ringShape, 2.) * (u_colorsCount - 1.);
103
+ vec4 gradient = u_colors[int(u_colorsCount) - 1];
104
104
  gradient.rgb *= gradient.a;
105
- for (int i = 1; i < ${smokeRingMeta.maxColorCount}; i++) {
106
- if (i >= int(u_colorsCount)) break;
107
- float localT = clamp(mixer - float(i - 1), 0., 1.);
108
- vec4 c = u_colors[i];
109
- c.rgb *= c.a;
110
- gradient = mix(gradient, c, localT);
105
+ for (int i = ${smokeRingMeta.maxColorCount} - 2; i >= 0; i--) {
106
+ float localT = clamp(mixer - float(int(u_colorsCount) - 1 - i - 1), 0., 1.);
107
+ vec4 c = u_colors[i];
108
+ c.rgb *= c.a;
109
+ gradient = mix(gradient, c, localT);
111
110
  }
112
111
 
113
112
  vec3 color = gradient.rgb * ringShape;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/smoke-ring.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerR, colorBandingFix } from '../shader-utils.js';\n\nexport const smokeRingMeta = {\n maxColorCount: 10,\n maxNoiseIterations: 8,\n} as const;\n\n/**\n * Radial gradient with layered FBM displacement, masked with ring shape\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_thickness, u_radius, u_innerShape: ring mask settings\n * - u_noiseIterations, u_noiseScale: how detailed is the noise (number of fbm layers & noise frequency)\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n */\n\n// language=GLSL\nexport const smokeRingFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${smokeRingMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_thickness;\nuniform float u_radius;\nuniform float u_innerShape;\nuniform float u_noiseScale;\nuniform float u_noiseIterations;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${textureRandomizerR}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbm(in vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) {\n if (i >= int(u_noiseIterations)) break;\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\nfloat getNoise(vec2 uv, vec2 pUv, float t) {\n float noiseLeft = fbm(pUv + .03 * t);\n pUv.x = mod(pUv.x, u_noiseScale * TWO_PI);\n float noiseRight = fbm(pUv + .03 * t);\n return mix(noiseRight, noiseLeft, smoothstep(-.25, .25, uv.x));\n}\n\nfloat getRingShape(vec2 uv) {\n float radius = u_radius;\n float thickness = u_thickness;\n\n float distance = length(uv);\n float ringValue = 1. - smoothstep(radius, radius + thickness, distance);\n ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance);\n\n return ringValue;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = u_time;\n\n float cycleDuration = 3.;\n float localTime1 = mod(.1 * t + cycleDuration, 2. * cycleDuration);\n float localTime2 = mod(.1 * t, 2. * cycleDuration);\n float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI);\n\n float atg = atan(shape_uv.y, shape_uv.x) + .001;\n float l = length(shape_uv);\n vec2 polar_uv1 = vec2(atg, localTime1 - (.5 * l) + 1. / pow(l, .5));\n polar_uv1 *= u_noiseScale;\n float noise1 = getNoise(shape_uv, polar_uv1, t);\n\n vec2 polar_uv2 = vec2(atg, localTime2 - (.5 * l) + 1. / pow(l, .5));\n polar_uv2 *= u_noiseScale;\n float noise2 = getNoise(shape_uv, polar_uv2, t);\n\n float noise = mix(noise1, noise2, timeBlend);\n\n shape_uv *= (.8 + 1.2 * noise);\n\n float ringShape = getRingShape(shape_uv);\n\n float mixer = pow(ringShape, 3.) * (u_colorsCount - 1.);\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${smokeRingMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * ringShape;\n float opacity = gradient.a * ringShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SmokeRingUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_noiseScale: number;\n u_thickness: number;\n u_radius: number;\n u_innerShape: number;\n u_noiseIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n noiseScale?: number;\n thickness?: number;\n radius?: number;\n innerShape?: number;\n noiseIterations?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,oBAAoB;AACtB;AAeO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQvB,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAeI,cAAc,kBAAkB;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,wBAwDhC,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAe/C,eAAe;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerR, colorBandingFix } from '../shader-utils.js';\n\nexport const smokeRingMeta = {\n maxColorCount: 10,\n maxNoiseIterations: 8,\n} as const;\n\n/**\n * Radial gradient with layered FBM displacement, masked with ring shape\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_thickness, u_radius, u_innerShape: ring mask settings\n * - u_noiseIterations, u_noiseScale: how detailed is the noise (number of fbm layers & noise frequency)\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n */\n\n// language=GLSL\nexport const smokeRingFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${smokeRingMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_thickness;\nuniform float u_radius;\nuniform float u_innerShape;\nuniform float u_noiseScale;\nuniform float u_noiseIterations;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${textureRandomizerR}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbm(in vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) {\n if (i >= int(u_noiseIterations)) break;\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\nfloat getNoise(vec2 uv, vec2 pUv, float t) {\n float noiseLeft = fbm(pUv + .03 * t);\n pUv.x = mod(pUv.x, u_noiseScale * TWO_PI);\n float noiseRight = fbm(pUv + .03 * t);\n return mix(noiseRight, noiseLeft, smoothstep(-.25, .25, uv.x));\n}\n\nfloat getRingShape(vec2 uv) {\n float radius = u_radius;\n float thickness = u_thickness;\n\n float distance = length(uv);\n float ringValue = 1. - smoothstep(radius, radius + thickness, distance);\n ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance);\n\n return ringValue;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = u_time;\n\n float cycleDuration = 3.;\n float localTime1 = mod(.1 * t + cycleDuration, 2. * cycleDuration);\n float localTime2 = mod(.1 * t, 2. * cycleDuration);\n float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI);\n\n float atg = atan(shape_uv.y, shape_uv.x) + .001;\n float l = length(shape_uv);\n vec2 polar_uv1 = vec2(atg, localTime1 - (.5 * l) + 1. / pow(l, .5));\n polar_uv1 *= u_noiseScale;\n float noise1 = getNoise(shape_uv, polar_uv1, t);\n\n vec2 polar_uv2 = vec2(atg, localTime2 - (.5 * l) + 1. / pow(l, .5));\n polar_uv2 *= u_noiseScale;\n float noise2 = getNoise(shape_uv, polar_uv2, t);\n\n float noise = mix(noise1, noise2, timeBlend);\n\n shape_uv *= (.8 + 1.2 * noise);\n\n float ringShape = getRingShape(shape_uv);\n\n float mixer = pow(ringShape, 2.) * (u_colorsCount - 1.);\n vec4 gradient = u_colors[int(u_colorsCount) - 1];\n gradient.rgb *= gradient.a;\n for (int i = ${smokeRingMeta.maxColorCount} - 2; i >= 0; i--) {\n float localT = clamp(mixer - float(int(u_colorsCount) - 1 - i - 1), 0., 1.);\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * ringShape;\n float opacity = gradient.a * ringShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SmokeRingUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_noiseScale: number;\n u_thickness: number;\n u_radius: number;\n u_innerShape: number;\n u_noiseIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n noiseScale?: number;\n thickness?: number;\n radius?: number;\n innerShape?: number;\n noiseIterations?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,oBAAoB;AACtB;AAeO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQvB,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAeI,cAAc,kBAAkB;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,iBAwDvC,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcxC,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,7 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
5
5
  * Can be applied over the texture or just be used as an animated pattern
6
6
  *
7
7
  * Uniforms:
8
- * - u_colorBack, u_highlightColor (RGBA)
8
+ * - u_colorBack, u_colorHighlight (RGBA)
9
9
  * - u_effectScale: pattern scale relative to the image
10
10
  * - u_caustic: power of caustic distortion
11
11
  * - u_layering: the power of 2nd layer of caustic distortion
@@ -18,7 +18,7 @@ export declare const waterFragmentShader: string;
18
18
  export interface WaterUniforms extends ShaderSizingUniforms {
19
19
  u_image: HTMLImageElement | string | undefined;
20
20
  u_colorBack: [number, number, number, number];
21
- u_highlightColor: [number, number, number, number];
21
+ u_colorHighlight: [number, number, number, number];
22
22
  u_highlights: number;
23
23
  u_layering: number;
24
24
  u_edges: number;
@@ -29,7 +29,7 @@ export interface WaterUniforms extends ShaderSizingUniforms {
29
29
  export interface WaterParams extends ShaderSizingParams, ShaderMotionParams {
30
30
  image?: HTMLImageElement | string | undefined;
31
31
  colorBack?: string;
32
- highlightColor?: string;
32
+ colorHighlight?: string;
33
33
  highlights?: number;
34
34
  layering?: number;
35
35
  edges?: number;
@@ -11,7 +11,7 @@ precision mediump float;
11
11
  uniform float u_time;
12
12
 
13
13
  uniform vec4 u_colorBack;
14
- uniform vec4 u_highlightColor;
14
+ uniform vec4 u_colorHighlight;
15
15
 
16
16
  uniform sampler2D u_image;
17
17
  uniform float u_imageAspectRatio;
@@ -101,8 +101,8 @@ void main() {
101
101
  causticNoise = max(-.2, causticNoise);
102
102
 
103
103
  float hightlight = .025 * u_highlights * causticNoise;
104
- hightlight *= u_highlightColor.a;
105
- color = mix(color, u_highlightColor.rgb, .05 * u_highlights * causticNoise);
104
+ hightlight *= u_colorHighlight.a;
105
+ color = mix(color, u_colorHighlight.rgb, .05 * u_highlights * causticNoise);
106
106
  opacity += hightlight;
107
107
 
108
108
  color += hightlight * (.5 + .5 * wavesNoise);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/water.ts"],
4
- "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise } from '../shader-utils.js';\n\n/**\n * Mimicking water surface distortion with a combination of noises;\n * Can be applied over the texture or just be used as an animated pattern\n *\n * Uniforms:\n * - u_colorBack, u_highlightColor (RGBA)\n * - u_effectScale: pattern scale relative to the image\n * - u_caustic: power of caustic distortion\n * - u_layering: the power of 2nd layer of caustic distortion\n * - u_edges: caustic distortion power on the image edges\n * - u_waves: additional distortion based in Simplex noise, independent from caustic\n * - u_highlights: a coloring added over the image/background, following the caustic shape\n *\n */\n\n// language=GLSL\nexport const waterFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_highlightColor;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_effectScale;\nuniform float u_highlights;\nuniform float u_layering;\nuniform float u_edges;\nuniform float u_caustic;\nuniform float u_waves;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${simplexNoise}\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\nmat2 rotate2D(float r) {\n return mat2(cos(r), sin(r), -sin(r), cos(r));\n}\n\nfloat getCausticNoise(vec2 uv, float t, float scale) {\n vec2 n = vec2(.1);\n vec2 N = vec2(.1);\n mat2 m = rotate2D(.5);\n for (int j = 0; j < 6; j++) {\n uv *= m;\n n *= m;\n vec2 q = uv * scale + float(j) + n + (.5 + .5 * float(j)) * (mod(float(j), 2.) - 1.) * t;\n n += sin(q);\n N += cos(q) / scale;\n scale *= 1.1;\n }\n return (N.x + N.y + 1.);\n}\n\nvoid main() {\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 10. * u_effectScale * (patternUV * vec2(u_imageAspectRatio, 1.));\n \n float t = u_time;\n \n float wavesNoise = snoise((.3 + .1 * sin(t)) * .1 * patternUV + vec2(0., .4 * t));\n\n float causticNoise = getCausticNoise(patternUV + u_waves * vec2(1., -1.) * wavesNoise, 2. * t, 1.5);\n\n causticNoise += u_layering * getCausticNoise(patternUV + 2. * u_waves * vec2(1., -1.) * wavesNoise, 1.5 * t, 2.);\n causticNoise = pow(causticNoise, 2.);\n \n float edgesDistortion = smoothstep(0., .1, imageUV.x);\n edgesDistortion *= smoothstep(0., .1, imageUV.y);\n edgesDistortion *= (smoothstep(1., 1.1, imageUV.x) + smoothstep(.95, .8, imageUV.x));\n edgesDistortion *= smoothstep(1., .9, imageUV.y);\n edgesDistortion = mix(edgesDistortion, 1., u_edges);\n \n float causticNoiseDistortion = .02 * causticNoise * edgesDistortion;\n \n float wavesDistortion = .1 * u_waves * wavesNoise;\n \n imageUV += vec2(wavesDistortion, -wavesDistortion);\n imageUV += (u_caustic * causticNoiseDistortion);\n\n float frame = getUvFrame(imageUV);\n\n vec4 image = texture(u_image, imageUV);\n vec4 backColor = u_colorBack;\n backColor.rgb *= backColor.a;\n \n vec3 color = mix(backColor.rgb, image.rgb, image.a * frame);\n float opacity = backColor.a + image.a * frame;\n\n causticNoise = max(-.2, causticNoise);\n \n float hightlight = .025 * u_highlights * causticNoise;\n hightlight *= u_highlightColor.a;\n color = mix(color, u_highlightColor.rgb, .05 * u_highlights * causticNoise);\n opacity += hightlight;\n \n color += hightlight * (.5 + .5 * wavesNoise);\n opacity += hightlight * (.5 + .5 * wavesNoise);\n \n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WaterUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorBack: [number, number, number, number];\n u_highlightColor: [number, number, number, number];\n u_highlights: number;\n u_layering: number;\n u_edges: number;\n u_caustic: number;\n u_waves: number;\n u_effectScale: number;\n}\n\nexport interface WaterParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string | undefined;\n colorBack?: string;\n highlightColor?: string;\n highlights?: number;\n layering?: number;\n edges?: number;\n caustic?: number;\n waves?: number;\n effectScale?: number;\n}\n"],
4
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise } from '../shader-utils.js';\n\n/**\n * Mimicking water surface distortion with a combination of noises;\n * Can be applied over the texture or just be used as an animated pattern\n *\n * Uniforms:\n * - u_colorBack, u_colorHighlight (RGBA)\n * - u_effectScale: pattern scale relative to the image\n * - u_caustic: power of caustic distortion\n * - u_layering: the power of 2nd layer of caustic distortion\n * - u_edges: caustic distortion power on the image edges\n * - u_waves: additional distortion based in Simplex noise, independent from caustic\n * - u_highlights: a coloring added over the image/background, following the caustic shape\n *\n */\n\n// language=GLSL\nexport const waterFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_effectScale;\nuniform float u_highlights;\nuniform float u_layering;\nuniform float u_edges;\nuniform float u_caustic;\nuniform float u_waves;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${simplexNoise}\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\nmat2 rotate2D(float r) {\n return mat2(cos(r), sin(r), -sin(r), cos(r));\n}\n\nfloat getCausticNoise(vec2 uv, float t, float scale) {\n vec2 n = vec2(.1);\n vec2 N = vec2(.1);\n mat2 m = rotate2D(.5);\n for (int j = 0; j < 6; j++) {\n uv *= m;\n n *= m;\n vec2 q = uv * scale + float(j) + n + (.5 + .5 * float(j)) * (mod(float(j), 2.) - 1.) * t;\n n += sin(q);\n N += cos(q) / scale;\n scale *= 1.1;\n }\n return (N.x + N.y + 1.);\n}\n\nvoid main() {\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 10. * u_effectScale * (patternUV * vec2(u_imageAspectRatio, 1.));\n \n float t = u_time;\n \n float wavesNoise = snoise((.3 + .1 * sin(t)) * .1 * patternUV + vec2(0., .4 * t));\n\n float causticNoise = getCausticNoise(patternUV + u_waves * vec2(1., -1.) * wavesNoise, 2. * t, 1.5);\n\n causticNoise += u_layering * getCausticNoise(patternUV + 2. * u_waves * vec2(1., -1.) * wavesNoise, 1.5 * t, 2.);\n causticNoise = pow(causticNoise, 2.);\n \n float edgesDistortion = smoothstep(0., .1, imageUV.x);\n edgesDistortion *= smoothstep(0., .1, imageUV.y);\n edgesDistortion *= (smoothstep(1., 1.1, imageUV.x) + smoothstep(.95, .8, imageUV.x));\n edgesDistortion *= smoothstep(1., .9, imageUV.y);\n edgesDistortion = mix(edgesDistortion, 1., u_edges);\n \n float causticNoiseDistortion = .02 * causticNoise * edgesDistortion;\n \n float wavesDistortion = .1 * u_waves * wavesNoise;\n \n imageUV += vec2(wavesDistortion, -wavesDistortion);\n imageUV += (u_caustic * causticNoiseDistortion);\n\n float frame = getUvFrame(imageUV);\n\n vec4 image = texture(u_image, imageUV);\n vec4 backColor = u_colorBack;\n backColor.rgb *= backColor.a;\n \n vec3 color = mix(backColor.rgb, image.rgb, image.a * frame);\n float opacity = backColor.a + image.a * frame;\n\n causticNoise = max(-.2, causticNoise);\n \n float hightlight = .025 * u_highlights * causticNoise;\n hightlight *= u_colorHighlight.a;\n color = mix(color, u_colorHighlight.rgb, .05 * u_highlights * causticNoise);\n opacity += hightlight;\n \n color += hightlight * (.5 + .5 * wavesNoise);\n opacity += hightlight * (.5 + .5 * wavesNoise);\n \n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WaterUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorBack: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_highlights: number;\n u_layering: number;\n u_edges: number;\n u_caustic: number;\n u_waves: number;\n u_effectScale: number;\n}\n\nexport interface WaterParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string | undefined;\n colorBack?: string;\n colorHighlight?: string;\n highlights?: number;\n layering?: number;\n edges?: number;\n caustic?: number;\n waves?: number;\n effectScale?: number;\n}\n"],
5
5
  "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,oBAAoB;AAkB5C,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBzC,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;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;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
  }
@@ -1,2 +1,2 @@
1
1
  /** Vertex shader for the shader mount */
2
- export declare const vertexShaderSource = "#version 300 es\nprecision mediump float;\n\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_imageAspectRatio;\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\nout vec2 v_imageUV;\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 // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n v_patternUV *= .01;\n\n // ===================================================\n\n\n // ===================================================\n // Sizing api for images\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n v_imageUV = uv;\n v_imageUV *= imageBoxScale;\n v_imageUV += boxOrigin * (imageBoxScale - 1.);\n v_imageUV += graphicOffset;\n v_imageUV /= u_scale;\n v_imageUV.x *= u_imageAspectRatio;\n v_imageUV = graphicRotation * v_imageUV;\n v_imageUV.x /= u_imageAspectRatio;\n\n v_imageUV += .5;\n v_imageUV.y = 1. - v_imageUV.y;\n\n // ===================================================\n\n}";
2
+ export declare const vertexShaderSource = "#version 300 es\nprecision mediump float;\n\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_imageAspectRatio;\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\nout vec2 v_imageUV;\n\n// #define ADD_HELPERS\n\nvec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {\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(u_resolution.x / boxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);\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 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).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).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);\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 // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n v_patternUV *= .01;\n\n // ===================================================\n\n\n // ===================================================\n // Sizing api for images\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n v_imageUV = uv;\n v_imageUV *= imageBoxScale;\n v_imageUV += boxOrigin * (imageBoxScale - 1.);\n v_imageUV += graphicOffset;\n v_imageUV /= u_scale;\n v_imageUV.x *= u_imageAspectRatio;\n v_imageUV = graphicRotation * v_imageUV;\n v_imageUV.x /= u_imageAspectRatio;\n\n v_imageUV += .5;\n v_imageUV.y = 1. - v_imageUV.y;\n\n // ===================================================\n\n}";
@@ -42,15 +42,15 @@ out vec2 v_imageUV;
42
42
 
43
43
  // #define ADD_HELPERS
44
44
 
45
- vec3 getBoxSize(float boxRatio, vec2 givenBoxSize, vec2 maxBoxSize) {
45
+ vec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {
46
46
  vec2 box = vec2(0.);
47
47
  // fit = none
48
48
  box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);
49
49
  float noFitBoxWidth = box.x;
50
50
  if (u_fit == 1.) { // fit = contain
51
- box.x = boxRatio * min(maxBoxSize[0] / boxRatio, maxBoxSize[1]);
51
+ box.x = boxRatio * min(u_resolution.x / boxRatio, u_resolution.y);
52
52
  } else if (u_fit == 2.) { // fit = cover
53
- box.x = boxRatio * max(maxBoxSize[0] / boxRatio, maxBoxSize[1]);
53
+ box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);
54
54
  }
55
55
  box.y = box.x / boxRatio;
56
56
  return vec3(box, noFitBoxWidth);
@@ -63,7 +63,6 @@ void main() {
63
63
  vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
64
64
  vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
65
65
  givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
66
- vec2 maxBoxSize = vec2(max(u_resolution.x, givenBoxSize.x), max(u_resolution.y, givenBoxSize.y));
67
66
  float r = u_rotation * 3.14159265358979323846 / 180.;
68
67
  mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
69
68
  vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
@@ -79,7 +78,7 @@ void main() {
79
78
  (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
80
79
  );
81
80
 
82
- v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize, maxBoxSize).xy;
81
+ v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize).xy;
83
82
  vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;
84
83
 
85
84
  #ifdef ADD_HELPERS
@@ -108,7 +107,7 @@ void main() {
108
107
  (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
109
108
  );
110
109
  float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
111
- v_responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize, maxBoxSize).xy;
110
+ v_responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy;
112
111
  vec2 responsiveBoxScale = u_resolution.xy / v_responsiveBoxSize;
113
112
 
114
113
  #ifdef ADD_HELPERS
@@ -140,7 +139,7 @@ void main() {
140
139
  );
141
140
  patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;
142
141
 
143
- vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize, maxBoxSize);
142
+ vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize);
144
143
  v_patternBoxSize = boxSizeData.xy;
145
144
  float patternBoxNoFitBoxWidth = boxSizeData.z;
146
145
  vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;
@@ -176,9 +175,9 @@ void main() {
176
175
 
177
176
  vec2 imageBoxSize;
178
177
  if (u_fit == 1.) { // contain
179
- imageBoxSize.x = min(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;
178
+ imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
180
179
  } else if (u_fit == 2.) { // cover
181
- imageBoxSize.x = max(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;
180
+ imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
182
181
  } else {
183
182
  imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);
184
183
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/vertex-shader.ts"],
4
- "sourcesContent": ["/** Vertex shader for the shader mount */\n// language=GLSL\nexport const vertexShaderSource = `#version 300 es\nprecision mediump float;\n\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_imageAspectRatio;\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\nout vec2 v_imageUV;\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 // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n v_patternUV *= .01;\n\n // ===================================================\n\n\n // ===================================================\n // Sizing api for images\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(maxBoxSize.x / u_imageAspectRatio, maxBoxSize.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n v_imageUV = uv;\n v_imageUV *= imageBoxScale;\n v_imageUV += boxOrigin * (imageBoxScale - 1.);\n v_imageUV += graphicOffset;\n v_imageUV /= u_scale;\n v_imageUV.x *= u_imageAspectRatio;\n v_imageUV = graphicRotation * v_imageUV;\n v_imageUV.x /= u_imageAspectRatio;\n\n v_imageUV += .5;\n v_imageUV.y = 1. - v_imageUV.y;\n\n // ===================================================\n\n}`;\n"],
5
- "mappings": ";;;;;AAEO,MAAM,qBAAqB;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;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["/** Vertex shader for the shader mount */\n// language=GLSL\nexport const vertexShaderSource = `#version 300 es\nprecision mediump float;\n\nlayout(location = 0) in vec4 a_position;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_imageAspectRatio;\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\nout vec2 v_imageUV;\n\n// #define ADD_HELPERS\n\nvec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {\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(u_resolution.x / boxRatio, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);\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 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).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).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);\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 // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n v_patternUV *= .01;\n\n // ===================================================\n\n\n // ===================================================\n // Sizing api for images\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n #ifdef ADD_HELPERS\n vec2 imageHelperBox = uv;\n imageHelperBox *= imageBoxScale;\n imageHelperBox += boxOrigin * (imageBoxScale - 1.);\n #endif\n\n v_imageUV = uv;\n v_imageUV *= imageBoxScale;\n v_imageUV += boxOrigin * (imageBoxScale - 1.);\n v_imageUV += graphicOffset;\n v_imageUV /= u_scale;\n v_imageUV.x *= u_imageAspectRatio;\n v_imageUV = graphicRotation * v_imageUV;\n v_imageUV.x /= u_imageAspectRatio;\n\n v_imageUV += .5;\n v_imageUV.y = 1. - v_imageUV.y;\n\n // ===================================================\n\n}`;\n"],
5
+ "mappings": ";;;;;AAEO,MAAM,qBAAqB;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;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;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@paper-design/shaders",
3
- "version": "0.0.46",
4
- "license": "MIT",
3
+ "version": "0.0.47",
4
+ "license": "SEE LICENSE IN https://github.com/paper-design/shaders/blob/main/LICENSE",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "publishConfig": {