` element that has a ShaderMount available on it */
+export interface PaperShaderElement extends HTMLElement {
+ paperShaderMount: ShaderMount | undefined;
+}
+/** Check if an element is a Paper shader element */
+export declare function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement;
+/**
+ * Uniform types that we support to be auto-mapped into the fragment shader
+ *
+ * We accept undefined as a convenience for server rendering, when some things may be undefined
+ * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering
+ */
+export interface ShaderMountUniforms {
+ [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;
+}
+export interface ShaderMotionParams {
+ speed?: number;
+ frame?: number;
+}
+export type ShaderPreset
= {
+ name: string;
+ params: Required;
+};
+export type ImageShaderPreset = {
+ name: string;
+ /**
+ * Params for the shader excluding the image.
+ * Image is excluded as it isn't considered a preset,
+ * e.g. when switching between presets it shouldn't switch the image.
+ *
+ * While we exclude images from presets they should still be set with a default prop value so the code-first usage of shaders remains great.
+ */
+ params: Required>;
+};
diff --git a/public/vendor/paper-shaders/shader-mount.js b/public/vendor/paper-shaders/shader-mount.js
new file mode 100644
index 0000000..5cf3dfe
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-mount.js
@@ -0,0 +1,510 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import { vertexShaderSource } from "./vertex-shader.js";
+const DEFAULT_MAX_PIXEL_COUNT = 1920 * 1080 * 4;
+class ShaderMount {
+ parentElement;
+ canvasElement;
+ gl;
+ program = null;
+ uniformLocations = {};
+ /** The fragment shader that we are using */
+ fragmentShader;
+ /** Stores the RAF for the render loop */
+ rafId = null;
+ /** Time of the last rendered frame */
+ lastRenderTime = 0;
+ /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */
+ currentFrame = 0;
+ /** The 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 */
+ speed = 0;
+ /** Actual speed used that accounts for visibility: we pause the shader if the tab is hidden or the element out of the viewport */
+ currentSpeed = 0;
+ /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */
+ providedUniforms;
+ /** Names of the uniforms that should have mipmaps generated for them */
+ mipmaps = [];
+ /** Just a sanity check to make sure frames don't run after we're disposed */
+ hasBeenDisposed = false;
+ /** If the resolution of the canvas has changed since the last render */
+ resolutionChanged = true;
+ /** Store textures that are provided by the user */
+ textures = /* @__PURE__ */ new Map();
+ minPixelRatio;
+ maxPixelCount;
+ isSafari = isSafari();
+ uniformCache = {};
+ textureUnitMap = /* @__PURE__ */ new Map();
+ ownerDocument;
+ constructor(parentElement, fragmentShader, uniforms, webGlContextAttributes, speed = 0, frame = 0, minPixelRatio = 2, maxPixelCount = DEFAULT_MAX_PIXEL_COUNT, mipmaps = []) {
+ if (parentElement?.nodeType === 1) {
+ this.parentElement = parentElement;
+ } else {
+ throw new Error("Paper Shaders: parent element must be an HTMLElement");
+ }
+ this.ownerDocument = parentElement.ownerDocument;
+ if (!this.ownerDocument.querySelector("style[data-paper-shader]")) {
+ const styleElement = this.ownerDocument.createElement("style");
+ styleElement.innerHTML = defaultStyle;
+ styleElement.setAttribute("data-paper-shader", "");
+ this.ownerDocument.head.prepend(styleElement);
+ }
+ const canvasElement = this.ownerDocument.createElement("canvas");
+ this.canvasElement = canvasElement;
+ this.parentElement.prepend(canvasElement);
+ this.fragmentShader = fragmentShader;
+ this.providedUniforms = uniforms;
+ this.mipmaps = mipmaps;
+ this.currentFrame = frame;
+ this.minPixelRatio = minPixelRatio;
+ this.maxPixelCount = maxPixelCount;
+ const gl = canvasElement.getContext("webgl2", webGlContextAttributes);
+ if (!gl) {
+ throw new Error("Paper Shaders: WebGL is not supported in this browser");
+ }
+ this.gl = gl;
+ this.initProgram();
+ this.setupPositionAttribute();
+ this.setupUniforms();
+ this.setUniformValues(this.providedUniforms);
+ this.setupResizeObserver();
+ visualViewport?.addEventListener("resize", this.handleVisualViewportChange);
+ this.setupIntersectionObserver();
+ this.setSpeed(speed);
+ this.parentElement.setAttribute("data-paper-shader", "");
+ this.parentElement.paperShaderMount = this;
+ this.ownerDocument.addEventListener("visibilitychange", this.handleDocumentVisibilityChange);
+ }
+ initProgram = () => {
+ const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);
+ if (!program) return;
+ this.program = program;
+ };
+ setupPositionAttribute = () => {
+ const positionAttributeLocation = this.gl.getAttribLocation(this.program, "a_position");
+ const positionBuffer = this.gl.createBuffer();
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);
+ const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];
+ this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW);
+ this.gl.enableVertexAttribArray(positionAttributeLocation);
+ this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);
+ };
+ setupUniforms = () => {
+ const uniformLocations = {
+ u_time: this.gl.getUniformLocation(this.program, "u_time"),
+ u_pixelRatio: this.gl.getUniformLocation(this.program, "u_pixelRatio"),
+ u_resolution: this.gl.getUniformLocation(this.program, "u_resolution")
+ };
+ Object.entries(this.providedUniforms).forEach(([key, value]) => {
+ uniformLocations[key] = this.gl.getUniformLocation(this.program, key);
+ if (value instanceof HTMLImageElement) {
+ const aspectRatioUniformName = `${key}AspectRatio`;
+ uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program, aspectRatioUniformName);
+ }
+ });
+ this.uniformLocations = uniformLocations;
+ };
+ /**
+ * The scale that we should render at.
+ * - Used to target 2x rendering even on 1x screens for better antialiasing
+ * - Prevents the virtual resolution from going beyond the maximum resolution
+ * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels
+ */
+ renderScale = 1;
+ parentWidth = 0;
+ parentHeight = 0;
+ parentDevicePixelWidth = 0;
+ parentDevicePixelHeight = 0;
+ devicePixelsSupported = false;
+ intersectionObserver = null;
+ isInViewport = true;
+ resizeObserver = null;
+ setupResizeObserver = () => {
+ this.resizeObserver = new ResizeObserver(([entry]) => {
+ if (entry?.borderBoxSize[0]) {
+ const physicalPixelSize = entry.devicePixelContentBoxSize?.[0];
+ if (physicalPixelSize !== void 0) {
+ this.devicePixelsSupported = true;
+ this.parentDevicePixelWidth = physicalPixelSize.inlineSize;
+ this.parentDevicePixelHeight = physicalPixelSize.blockSize;
+ }
+ this.parentWidth = entry.borderBoxSize[0].inlineSize;
+ this.parentHeight = entry.borderBoxSize[0].blockSize;
+ }
+ this.handleResize();
+ });
+ this.resizeObserver.observe(this.parentElement);
+ };
+ setupIntersectionObserver = () => {
+ const view = this.ownerDocument.defaultView;
+ if (!view?.IntersectionObserver) return;
+ this.intersectionObserver = new view.IntersectionObserver(([entry]) => {
+ this.isInViewport = entry?.isIntersecting ?? true;
+ this.updateCurrentSpeed();
+ });
+ this.intersectionObserver.observe(this.parentElement);
+ };
+ // Visual viewport resize handler, mainly used to react to browser zoom changes.
+ // Resize observer by itself does not react to pinch zoom, and although it usually
+ // reacts to classic browser zoom, it's not guaranteed in edge cases.
+ // Since timing between visual viewport changes and resize observer is complex
+ // and because we'd like to know the device pixel sizes of elements, we just restart
+ // the observer to get a guaranteed fresh callback regardless if it would have triggered or not.
+ handleVisualViewportChange = () => {
+ this.resizeObserver?.disconnect();
+ this.setupResizeObserver();
+ };
+ /** Resize handler for when the container div changes size or the max pixel count changes and we want to resize our canvas to match */
+ handleResize = () => {
+ let targetPixelWidth = 0;
+ let targetPixelHeight = 0;
+ const dpr = Math.max(1, window.devicePixelRatio);
+ const pinchZoom = visualViewport?.scale ?? 1;
+ if (this.devicePixelsSupported) {
+ const scaleToMeetMinPixelRatio = Math.max(1, this.minPixelRatio / dpr);
+ targetPixelWidth = this.parentDevicePixelWidth * scaleToMeetMinPixelRatio * pinchZoom;
+ targetPixelHeight = this.parentDevicePixelHeight * scaleToMeetMinPixelRatio * pinchZoom;
+ } else {
+ let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom;
+ if (this.isSafari) {
+ const zoomLevel = bestGuessBrowserZoom(this.ownerDocument);
+ targetRenderScale *= Math.max(1, zoomLevel);
+ }
+ targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale;
+ targetPixelHeight = Math.round(this.parentHeight) * targetRenderScale;
+ }
+ const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);
+ const scaleToMeetMaxPixelCount = Math.min(1, maxPixelCountHeadroom);
+ const newWidth = Math.round(targetPixelWidth * scaleToMeetMaxPixelCount);
+ const newHeight = Math.round(targetPixelHeight * scaleToMeetMaxPixelCount);
+ const newRenderScale = newWidth / Math.round(this.parentWidth);
+ if (this.canvasElement.width !== newWidth || this.canvasElement.height !== newHeight || this.renderScale !== newRenderScale) {
+ this.renderScale = newRenderScale;
+ this.canvasElement.width = newWidth;
+ this.canvasElement.height = newHeight;
+ this.resolutionChanged = true;
+ this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
+ this.render(performance.now());
+ }
+ };
+ render = (currentTime) => {
+ if (this.hasBeenDisposed) return;
+ if (this.program === null) {
+ console.warn("Tried to render before program or gl was initialized");
+ return;
+ }
+ const dt = currentTime - this.lastRenderTime;
+ this.lastRenderTime = currentTime;
+ if (this.currentSpeed !== 0) {
+ this.currentFrame += dt * this.currentSpeed;
+ }
+ this.gl.clear(this.gl.COLOR_BUFFER_BIT);
+ this.gl.useProgram(this.program);
+ this.gl.uniform1f(this.uniformLocations.u_time, this.currentFrame * 1e-3);
+ if (this.resolutionChanged) {
+ this.gl.uniform2f(this.uniformLocations.u_resolution, this.gl.canvas.width, this.gl.canvas.height);
+ this.gl.uniform1f(this.uniformLocations.u_pixelRatio, this.renderScale);
+ this.resolutionChanged = false;
+ }
+ this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
+ if (this.currentSpeed !== 0) {
+ this.requestRender();
+ } else {
+ this.rafId = null;
+ }
+ };
+ requestRender = () => {
+ if (this.rafId !== null) {
+ cancelAnimationFrame(this.rafId);
+ }
+ this.rafId = requestAnimationFrame(this.render);
+ };
+ /** Creates a texture from an image and sets it into a uniform value */
+ setTextureUniform = (uniformName, image) => {
+ if (!image.complete || image.naturalWidth === 0) {
+ throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);
+ }
+ const existingTexture = this.textures.get(uniformName);
+ if (existingTexture) {
+ this.gl.deleteTexture(existingTexture);
+ }
+ if (!this.textureUnitMap.has(uniformName)) {
+ this.textureUnitMap.set(uniformName, this.textureUnitMap.size);
+ }
+ const textureUnit = this.textureUnitMap.get(uniformName);
+ this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);
+ const texture = this.gl.createTexture();
+ this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
+ this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);
+ if (this.mipmaps.includes(uniformName)) {
+ this.gl.generateMipmap(this.gl.TEXTURE_2D);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);
+ }
+ const error = this.gl.getError();
+ if (error !== this.gl.NO_ERROR || texture === null) {
+ console.error("Paper Shaders: WebGL error when uploading texture:", error);
+ return;
+ }
+ this.textures.set(uniformName, texture);
+ const location = this.uniformLocations[uniformName];
+ if (location) {
+ this.gl.uniform1i(location, textureUnit);
+ const aspectRatioUniformName = `${uniformName}AspectRatio`;
+ const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName];
+ if (aspectRatioLocation) {
+ const aspectRatio = image.naturalWidth / image.naturalHeight;
+ this.gl.uniform1f(aspectRatioLocation, aspectRatio);
+ }
+ }
+ };
+ /** Utility: recursive equality test for all the uniforms */
+ areUniformValuesEqual = (a, b) => {
+ if (a === b) return true;
+ if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {
+ return a.every((val, i) => this.areUniformValuesEqual(val, b[i]));
+ }
+ return false;
+ };
+ /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */
+ setUniformValues = (updatedUniforms) => {
+ this.gl.useProgram(this.program);
+ Object.entries(updatedUniforms).forEach(([key, value]) => {
+ let cacheValue = value;
+ if (value instanceof HTMLImageElement) {
+ cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`;
+ }
+ if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return;
+ this.uniformCache[key] = cacheValue;
+ const location = this.uniformLocations[key];
+ if (!location) {
+ console.warn(`Uniform location for ${key} not found`);
+ return;
+ }
+ if (value instanceof HTMLImageElement) {
+ this.setTextureUniform(key, value);
+ } else if (Array.isArray(value)) {
+ let flatArray = null;
+ let valueLength = null;
+ if (value[0] !== void 0 && Array.isArray(value[0])) {
+ const firstChildLength = value[0].length;
+ if (value.every((arr) => arr.length === firstChildLength)) {
+ flatArray = value.flat();
+ valueLength = firstChildLength;
+ } else {
+ console.warn(`All child arrays must be the same length for ${key}`);
+ return;
+ }
+ } else {
+ flatArray = value;
+ valueLength = flatArray.length;
+ }
+ switch (valueLength) {
+ case 2:
+ this.gl.uniform2fv(location, flatArray);
+ break;
+ case 3:
+ this.gl.uniform3fv(location, flatArray);
+ break;
+ case 4:
+ this.gl.uniform4fv(location, flatArray);
+ break;
+ case 9:
+ this.gl.uniformMatrix3fv(location, false, flatArray);
+ break;
+ case 16:
+ this.gl.uniformMatrix4fv(location, false, flatArray);
+ break;
+ default:
+ console.warn(`Unsupported uniform array length: ${valueLength}`);
+ }
+ } else if (typeof value === "number") {
+ this.gl.uniform1f(location, value);
+ } else if (typeof value === "boolean") {
+ this.gl.uniform1i(location, value ? 1 : 0);
+ } else {
+ console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);
+ }
+ });
+ };
+ /** Gets the current total animation time from 0ms */
+ getCurrentFrame = () => {
+ return this.currentFrame;
+ };
+ /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */
+ setFrame = (newFrame) => {
+ this.currentFrame = newFrame;
+ this.lastRenderTime = performance.now();
+ this.render(performance.now());
+ };
+ /** Set an animation speed (or 0 to stop animation) */
+ setSpeed = (newSpeed = 1) => {
+ this.speed = newSpeed;
+ this.updateCurrentSpeed();
+ };
+ /** Apply the target speed, pausing (0) while the tab is hidden or the element is out of the viewport */
+ updateCurrentSpeed = () => {
+ this.setCurrentSpeed(this.ownerDocument.hidden || !this.isInViewport ? 0 : this.speed);
+ };
+ setCurrentSpeed = (newSpeed) => {
+ this.currentSpeed = newSpeed;
+ if (this.rafId === null && newSpeed !== 0) {
+ this.lastRenderTime = performance.now();
+ this.rafId = requestAnimationFrame(this.render);
+ }
+ if (this.rafId !== null && newSpeed === 0) {
+ cancelAnimationFrame(this.rafId);
+ this.rafId = null;
+ }
+ };
+ /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */
+ setMaxPixelCount = (newMaxPixelCount = DEFAULT_MAX_PIXEL_COUNT) => {
+ this.maxPixelCount = newMaxPixelCount;
+ this.handleResize();
+ };
+ /** Set the minimum pixel ratio for the shader */
+ setMinPixelRatio = (newMinPixelRatio = 2) => {
+ this.minPixelRatio = newMinPixelRatio;
+ this.handleResize();
+ };
+ /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */
+ setUniforms = (newUniforms) => {
+ this.setUniformValues(newUniforms);
+ this.providedUniforms = { ...this.providedUniforms, ...newUniforms };
+ this.render(performance.now());
+ };
+ handleDocumentVisibilityChange = () => {
+ this.updateCurrentSpeed();
+ };
+ /** Dispose of the shader mount, cleaning up all of the WebGL resources */
+ dispose = () => {
+ this.hasBeenDisposed = true;
+ if (this.rafId !== null) {
+ cancelAnimationFrame(this.rafId);
+ this.rafId = null;
+ }
+ if (this.gl && this.program) {
+ this.textures.forEach((texture) => {
+ this.gl.deleteTexture(texture);
+ });
+ this.textures.clear();
+ this.gl.deleteProgram(this.program);
+ this.program = null;
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);
+ this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
+ this.gl.getError();
+ }
+ if (this.resizeObserver) {
+ this.resizeObserver.disconnect();
+ this.resizeObserver = null;
+ }
+ if (this.intersectionObserver) {
+ this.intersectionObserver.disconnect();
+ this.intersectionObserver = null;
+ }
+ visualViewport?.removeEventListener("resize", this.handleVisualViewportChange);
+ this.ownerDocument.removeEventListener("visibilitychange", this.handleDocumentVisibilityChange);
+ this.uniformLocations = {};
+ this.canvasElement.remove();
+ delete this.parentElement.paperShaderMount;
+ };
+}
+function createShader(gl, type, source) {
+ const shader = gl.createShader(type);
+ if (!shader) return null;
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ console.error("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
+ gl.deleteShader(shader);
+ return null;
+ }
+ return shader;
+}
+function createProgram(gl, vertexShaderSource2, fragmentShaderSource) {
+ const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);
+ const precision = format ? format.precision : null;
+ if (precision && precision < 23) {
+ vertexShaderSource2 = vertexShaderSource2.replace(/precision\s+(lowp|mediump)\s+float;/g, "precision highp float;");
+ fragmentShaderSource = fragmentShaderSource.replace(/precision\s+(lowp|mediump)\s+float/g, "precision highp float").replace(/\b(uniform|varying|attribute)\s+(lowp|mediump)\s+(\w+)/g, "$1 highp $3");
+ }
+ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource2);
+ const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
+ if (!vertexShader || !fragmentShader) return null;
+ const program = gl.createProgram();
+ if (!program) return null;
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ gl.linkProgram(program);
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ console.error("Unable to initialize the shader program: " + gl.getProgramInfoLog(program));
+ gl.deleteProgram(program);
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+ return null;
+ }
+ gl.detachShader(program, vertexShader);
+ gl.detachShader(program, fragmentShader);
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+ return program;
+}
+const defaultStyle = `@layer paper-shaders {
+ :where([data-paper-shader]) {
+ isolation: isolate;
+ position: relative;
+
+ & canvas {
+ contain: strict;
+ display: block;
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+ width: 100%;
+ height: 100%;
+ border-radius: inherit;
+ corner-shape: inherit;
+ }
+ }
+}`;
+function isPaperShaderElement(element) {
+ return "paperShaderMount" in element;
+}
+function isSafari() {
+ const ua = navigator.userAgent.toLowerCase();
+ return ua.includes("safari") && !ua.includes("chrome") && !ua.includes("android");
+}
+function bestGuessBrowserZoom(doc) {
+ const viewportScale = visualViewport?.scale ?? 1;
+ const viewportWidth = visualViewport?.width ?? window.innerWidth;
+ const scrollbarWidth = window.innerWidth - doc.documentElement.clientWidth;
+ const innerWidth = viewportScale * viewportWidth + scrollbarWidth;
+ const ratio = outerWidth / innerWidth;
+ const zoomPercentageRounded = Math.round(100 * ratio);
+ if (zoomPercentageRounded % 5 === 0) {
+ return zoomPercentageRounded / 100;
+ }
+ if (zoomPercentageRounded === 33) {
+ return 1 / 3;
+ }
+ if (zoomPercentageRounded === 67) {
+ return 2 / 3;
+ }
+ if (zoomPercentageRounded === 133) {
+ return 4 / 3;
+ }
+ return ratio;
+}
+export {
+ ShaderMount,
+ isPaperShaderElement
+};
+//# sourceMappingURL=shader-mount.js.map
diff --git a/public/vendor/paper-shaders/shader-mount.js.map b/public/vendor/paper-shaders/shader-mount.js.map
new file mode 100644
index 0000000..3e2d6f3
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-mount.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../src/shader-mount.ts"],
+ "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 = {};\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 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 /** Actual speed used that accounts for visibility: we pause the shader if the tab is hidden or the element out of the viewport */\n private currentSpeed = 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 /** Names of the uniforms that should have mipmaps generated for them */\n private mipmaps: string[] = [];\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 = new Map();\n private minPixelRatio;\n private maxPixelCount;\n private isSafari = isSafari();\n private uniformCache: Record = {};\n private textureUnitMap: Map = new Map();\n private ownerDocument: Document;\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 /** Names of the uniforms that should have mipmaps generated for them */\n mipmaps: string[] = []\n ) {\n // nodeType check instead of `instanceof` to work across document boundaries (iframes, PiP windows)\n if (parentElement?.nodeType === 1) {\n this.parentElement = parentElement as PaperShaderElement;\n } else {\n throw new Error('Paper Shaders: parent element must be an HTMLElement');\n }\n\n this.ownerDocument = parentElement.ownerDocument;\n\n if (!this.ownerDocument.querySelector('style[data-paper-shader]')) {\n const styleElement = this.ownerDocument.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shader', '');\n this.ownerDocument.head.prepend(styleElement);\n }\n\n // Create the canvas element and mount it into the provided element\n const canvasElement = this.ownerDocument.createElement('canvas');\n this.canvasElement = canvasElement;\n this.parentElement.prepend(canvasElement);\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n this.mipmaps = mipmaps;\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 // Set up the visual viewport change listener to handle zoom changes (pinch zoom and classic browser zoom)\n visualViewport?.addEventListener('resize', this.handleVisualViewportChange);\n // Set up the intersection observer to pause animation when the element is scrolled out of view\n this.setupIntersectionObserver();\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 // Listen for document visibility changes to pause the shader when the tab is hidden\n this.ownerDocument.addEventListener('visibilitychange', this.handleDocumentVisibilityChange);\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 = {\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 private parentDevicePixelWidth = 0;\n private parentDevicePixelHeight = 0;\n private devicePixelsSupported = false;\n\n private intersectionObserver: IntersectionObserver | null = null;\n private isInViewport = true;\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(([entry]) => {\n if (entry?.borderBoxSize[0]) {\n const physicalPixelSize = entry.devicePixelContentBoxSize?.[0];\n\n if (physicalPixelSize !== undefined) {\n this.devicePixelsSupported = true;\n this.parentDevicePixelWidth = physicalPixelSize.inlineSize;\n this.parentDevicePixelHeight = physicalPixelSize.blockSize;\n }\n\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 };\n\n private setupIntersectionObserver = () => {\n // we check element's own window to support shaders used within iframe/PiP elements\n const view = this.ownerDocument.defaultView;\n if (!view?.IntersectionObserver) return;\n\n this.intersectionObserver = new view.IntersectionObserver(([entry]) => {\n this.isInViewport = entry?.isIntersecting ?? true;\n this.updateCurrentSpeed();\n });\n\n this.intersectionObserver.observe(this.parentElement);\n };\n\n // Visual viewport resize handler, mainly used to react to browser zoom changes.\n // Resize observer by itself does not react to pinch zoom, and although it usually\n // reacts to classic browser zoom, it's not guaranteed in edge cases.\n // Since timing between visual viewport changes and resize observer is complex\n // and because we'd like to know the device pixel sizes of elements, we just restart\n // the observer to get a guaranteed fresh callback regardless if it would have triggered or not.\n private handleVisualViewportChange = () => {\n this.resizeObserver?.disconnect();\n this.setupResizeObserver();\n\n // In case of debugging timing, from here on:\n // - animation frame 1: a paint after the visual viewport resize\n // - animation frame 2: a paint after the resize observer has been handled, if it was ever triggered\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 // Aim to render at least as many pixels as physically displayed\n // This will overshoot when the user zooms out, but that's acceptable\n\n let targetPixelWidth = 0;\n let targetPixelHeight = 0;\n\n // If window.devicePixelRatio is below 1, it's safe to say the browser is just zoomed out\n // We can use 1 as the minimum value not to upscale it needlessly to meet the min pixel ratio param\n const dpr = Math.max(1, window.devicePixelRatio);\n const pinchZoom = visualViewport?.scale ?? 1;\n\n if (this.devicePixelsSupported) {\n // Use the real pixel size if we know it, plus meet the min pixel ratio requirement and add in pinch zoom\n const scaleToMeetMinPixelRatio = Math.max(1, this.minPixelRatio / dpr);\n targetPixelWidth = this.parentDevicePixelWidth * scaleToMeetMinPixelRatio * pinchZoom;\n targetPixelHeight = this.parentDevicePixelHeight * scaleToMeetMinPixelRatio * pinchZoom;\n } else {\n // Otherwise try to approximate the element size in device pixels using devicePixelRatio.\n // (devicePixelRatio is imprecise and element's width/height may be fractional CSS sizes, not real pixels).\n let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom;\n\n if (this.isSafari) {\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 //\n // In Safari we need to factor in the zoom level manually in order to set the target resolution.\n // To avoid sidebars upscaling the target resolution, set a minimum zoom level of 1.\n // This will render at higher resolution when zoomed out, but that's fine.\n // (We mostly care about maintaining good quality when zoomed in).\n const zoomLevel = bestGuessBrowserZoom(this.ownerDocument);\n targetRenderScale *= Math.max(1, zoomLevel);\n }\n\n // Rounding the client width/height since they may be fractional in CSS layout values\n targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale;\n targetPixelHeight = Math.round(this.parentHeight) * targetRenderScale;\n }\n\n // Prevent the total rendered pixel count from exceeding maxPixelCount\n const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);\n const scaleToMeetMaxPixelCount = Math.min(1, maxPixelCountHeadroom);\n const newWidth = Math.round(targetPixelWidth * scaleToMeetMaxPixelCount);\n const newHeight = Math.round(targetPixelHeight * scaleToMeetMaxPixelCount);\n const newRenderScale = newWidth / Math.round(this.parentWidth);\n\n if (\n this.canvasElement.width !== newWidth ||\n this.canvasElement.height !== newHeight ||\n this.renderScale !== newRenderScale // Usually, only render scale changes 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.currentSpeed !== 0) {\n this.currentFrame += dt * this.currentSpeed;\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.currentSpeed !== 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\n // Generate mipmaps if the uniform is in the mipmaps list\n if (this.mipmaps.includes(uniformName)) {\n this.gl.generateMipmap(this.gl.TEXTURE_2D);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);\n }\n\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 = 1): void => {\n // Set the new animation speed\n this.speed = newSpeed;\n this.updateCurrentSpeed();\n };\n\n /** Apply the target speed, pausing (0) while the tab is hidden or the element is out of the viewport */\n private updateCurrentSpeed = (): void => {\n this.setCurrentSpeed(this.ownerDocument.hidden || !this.isInViewport ? 0 : this.speed);\n };\n\n private setCurrentSpeed = (newSpeed: number): void => {\n this.currentSpeed = 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 private handleDocumentVisibilityChange = () => {\n this.updateCurrentSpeed();\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 if (this.intersectionObserver) {\n this.intersectionObserver.disconnect();\n this.intersectionObserver = null;\n }\n\n visualViewport?.removeEventListener('resize', this.handleVisualViewportChange);\n this.ownerDocument.removeEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n\n this.uniformLocations = {};\n\n // Remove the shader from the div wrapper element\n this.canvasElement.remove();\n // Free up the reference to self to enable garbage collection\n delete this.parentElement.paperShaderMount;\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 `` 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
= {\n name: string;\n params: Required;\n};\n\nexport type ImageShaderPreset = {\n name: string;\n /**\n * Params for the shader excluding the image.\n * Image is excluded as it isn't considered a preset,\n * e.g. when switching between presets it shouldn't switch the image.\n *\n * While we exclude images from presets they should still be set with a default prop value so the code-first usage of shaders remains great.\n */\n params: Required>;\n};\n\nfunction isSafari() {\n const ua = navigator.userAgent.toLowerCase();\n return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('android');\n}\n\n// Zoom level can be estimated comparing the browser's outerWidth and the viewport width.\n// It's nowhere near perfect because it's affected by the presence of browser sidebars,\n// like a vertical web inspector or Arc's sidebar. Also, both outerWidth and innerWidth\n// are integers, which would almost never give us a perfect ratio at face values.\n//\n// Still, this is pretty accurate in the vast majority of cases.\n//\n// Note 1:\n// 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//\n// Note 2:\n// Opening a sidebar in Safari like web inspector or bookmarks will throw off the zoom\n// level detection and result in a larger target resolution. Not a concern in real-world usage\n// with Safari, but we'd rather not try to detect zoom levels with other browsers\n// (e.g. Arc always has a sidebar, which affects outerWidth vs visualViewport.width).\nfunction bestGuessBrowserZoom(doc: Document) {\n const viewportScale = visualViewport?.scale ?? 1;\n const viewportWidth = visualViewport?.width ?? window.innerWidth;\n const scrollbarWidth = window.innerWidth - doc.documentElement.clientWidth;\n const innerWidth = viewportScale * viewportWidth + scrollbarWidth;\n\n // outerWidth and innerWidth are always integers so we won't often get the original zoom ratio\n // E.g. given a 125% zoom, outerWidth = 1657, innerWidth = 1325, 1657 / 1325 = 1.2505660377\n // We check for common zoom levels and return the closest one if found.\n\n const ratio = outerWidth / innerWidth;\n const zoomPercentageRounded = Math.round(100 * ratio);\n\n // All zoom levels divisible by 5%\n if (zoomPercentageRounded % 5 === 0) {\n return zoomPercentageRounded / 100;\n }\n\n // 33% zoom\n if (zoomPercentageRounded === 33) {\n return 1 / 3;\n }\n\n // 67% zoom\n if (zoomPercentageRounded === 67) {\n return 2 / 3;\n }\n\n // 133% zoom\n if (zoomPercentageRounded === 133) {\n return 4 / 3;\n }\n\n return ratio;\n}\n"],
+ "mappings": "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",
+ "names": ["vertexShaderSource"]
+}
diff --git a/public/vendor/paper-shaders/shader-sizing.d.ts b/public/vendor/paper-shaders/shader-sizing.d.ts
new file mode 100644
index 0000000..5640031
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-sizing.d.ts
@@ -0,0 +1,30 @@
+export interface ShaderSizingUniforms {
+ u_fit: (typeof ShaderFitOptions)[ShaderFit];
+ u_scale: number;
+ u_rotation: number;
+ u_originX: number;
+ u_originY: number;
+ u_offsetX: number;
+ u_offsetY: number;
+ u_worldWidth: number;
+ u_worldHeight: number;
+}
+export interface ShaderSizingParams {
+ fit?: 'none' | 'contain' | 'cover';
+ scale?: number;
+ rotation?: number;
+ originX?: number;
+ originY?: number;
+ offsetX?: number;
+ offsetY?: number;
+ worldWidth?: number;
+ worldHeight?: number;
+}
+export declare const defaultObjectSizing: Required;
+export declare const defaultPatternSizing: Required;
+export declare const ShaderFitOptions: {
+ readonly none: 0;
+ readonly contain: 1;
+ readonly cover: 2;
+};
+export type ShaderFit = keyof typeof ShaderFitOptions;
diff --git a/public/vendor/paper-shaders/shader-sizing.js b/public/vendor/paper-shaders/shader-sizing.js
new file mode 100644
index 0000000..bf7a798
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-sizing.js
@@ -0,0 +1,38 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+const defaultObjectSizing = {
+ fit: "contain",
+ scale: 1,
+ rotation: 0,
+ offsetX: 0,
+ offsetY: 0,
+ originX: 0.5,
+ originY: 0.5,
+ worldWidth: 0,
+ worldHeight: 0
+};
+const defaultPatternSizing = {
+ fit: "none",
+ scale: 1,
+ rotation: 0,
+ offsetX: 0,
+ offsetY: 0,
+ originX: 0.5,
+ originY: 0.5,
+ worldWidth: 0,
+ worldHeight: 0
+};
+const ShaderFitOptions = {
+ none: 0,
+ contain: 1,
+ cover: 2
+};
+export {
+ ShaderFitOptions,
+ defaultObjectSizing,
+ defaultPatternSizing
+};
+//# sourceMappingURL=shader-sizing.js.map
diff --git a/public/vendor/paper-shaders/shader-sizing.js.map b/public/vendor/paper-shaders/shader-sizing.js.map
new file mode 100644
index 0000000..a082fe9
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-sizing.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../src/shader-sizing.ts"],
+ "sourcesContent": ["export 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 = {\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 = {\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"],
+ "mappings": ";;;;;AAwBO,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;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shader-utils.d.ts b/public/vendor/paper-shaders/shader-utils.d.ts
new file mode 100644
index 0000000..07a242b
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-utils.d.ts
@@ -0,0 +1,10 @@
+export declare const declarePI = "\n#define TWO_PI 6.28318530718\n#define PI 3.14159265358979323846\n";
+export declare const rotation2 = "\nvec2 rotate(vec2 uv, float th) {\n return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;\n}\n";
+export declare const proceduralHash11 = "\n float hash11(float p) {\n p = fract(p * 0.3183099) + 0.1;\n p *= p + 19.19;\n return fract(p * p);\n }\n";
+export declare const proceduralHash21 = "\n float hash21(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p + 19.19);\n return fract(p.x * p.y);\n }\n";
+export declare const proceduralHash22 = "\n vec2 hash22(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p.yx + 19.19);\n return fract(vec2(p.x * p.y, p.x + p.y));\n }\n";
+export declare const textureRandomizerR = "\n float randomR(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).r;\n }\n";
+export declare const textureRandomizerGB = "\n vec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n }\n";
+export declare const colorBandingFix = "\n color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n";
+export declare const simplexNoise = "\nvec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }\nfloat snoise(vec2 v) {\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0));\n vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)), 0.0);\n m = m * m;\n m = m * m;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n";
+export declare const fiberNoise = "\nfloat fiberRandom(vec2 p) {\n vec2 uv = floor(p) / 100.;\n return texture(u_noiseTexture, fract(uv)).b;\n}\n\nfloat fiberValueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = fiberRandom(i);\n float b = fiberRandom(i + vec2(1.0, 0.0));\n float c = fiberRandom(i + vec2(0.0, 1.0));\n float d = fiberRandom(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 fiberNoiseFbm(in vec2 n, vec2 seedOffset) {\n float total = 0.0, amplitude = 1.;\n for (int i = 0; i < 4; i++) {\n n = rotate(n, .7);\n total += fiberValueNoise(n + seedOffset) * amplitude;\n n *= 2.;\n amplitude *= 0.6;\n }\n return total;\n}\n\nfloat fiberNoise(vec2 uv, vec2 seedOffset) {\n float epsilon = 0.001;\n float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset);\n float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset);\n float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset);\n float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset);\n return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon);\n}\n";
diff --git a/public/vendor/paper-shaders/shader-utils.js b/public/vendor/paper-shaders/shader-utils.js
new file mode 100644
index 0000000..262fcd4
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-utils.js
@@ -0,0 +1,131 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+const declarePI = `
+#define TWO_PI 6.28318530718
+#define PI 3.14159265358979323846
+`;
+const rotation2 = `
+vec2 rotate(vec2 uv, float th) {
+ return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;
+}
+`;
+const proceduralHash11 = `
+ float hash11(float p) {
+ p = fract(p * 0.3183099) + 0.1;
+ p *= p + 19.19;
+ return fract(p * p);
+ }
+`;
+const proceduralHash21 = `
+ float hash21(vec2 p) {
+ p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;
+ p += dot(p, p + 19.19);
+ return fract(p.x * p.y);
+ }
+`;
+const proceduralHash22 = `
+ vec2 hash22(vec2 p) {
+ p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;
+ p += dot(p, p.yx + 19.19);
+ return fract(vec2(p.x * p.y, p.x + p.y));
+ }
+`;
+const textureRandomizerR = `
+ float randomR(vec2 p) {
+ vec2 uv = floor(p) / 100. + .5;
+ return texture(u_noiseTexture, fract(uv)).r;
+ }
+`;
+const textureRandomizerGB = `
+ vec2 randomGB(vec2 p) {
+ vec2 uv = floor(p) / 100. + .5;
+ return texture(u_noiseTexture, fract(uv)).gb;
+ }
+`;
+const colorBandingFix = `
+ color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);
+`;
+const simplexNoise = `
+vec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }
+float snoise(vec2 v) {
+ const vec4 C = vec4(0.211324865405187, 0.366025403784439,
+ -0.577350269189626, 0.024390243902439);
+ vec2 i = floor(v + dot(v, C.yy));
+ vec2 x0 = v - i + dot(i, C.xx);
+ vec2 i1;
+ i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
+ vec4 x12 = x0.xyxy + C.xxzz;
+ x12.xy -= i1;
+ i = mod(i, 289.0);
+ vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))
+ + i.x + vec3(0.0, i1.x, 1.0));
+ vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),
+ dot(x12.zw, x12.zw)), 0.0);
+ m = m * m;
+ m = m * m;
+ vec3 x = 2.0 * fract(p * C.www) - 1.0;
+ vec3 h = abs(x) - 0.5;
+ vec3 ox = floor(x + 0.5);
+ vec3 a0 = x - ox;
+ m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
+ vec3 g;
+ g.x = a0.x * x0.x + h.x * x0.y;
+ g.yz = a0.yz * x12.xz + h.yz * x12.yw;
+ return 130.0 * dot(m, g);
+}
+`;
+const fiberNoise = `
+float fiberRandom(vec2 p) {
+ vec2 uv = floor(p) / 100.;
+ return texture(u_noiseTexture, fract(uv)).b;
+}
+
+float fiberValueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = fiberRandom(i);
+ float b = fiberRandom(i + vec2(1.0, 0.0));
+ float c = fiberRandom(i + vec2(0.0, 1.0));
+ float d = fiberRandom(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float fiberNoiseFbm(in vec2 n, vec2 seedOffset) {
+ float total = 0.0, amplitude = 1.;
+ for (int i = 0; i < 4; i++) {
+ n = rotate(n, .7);
+ total += fiberValueNoise(n + seedOffset) * amplitude;
+ n *= 2.;
+ amplitude *= 0.6;
+ }
+ return total;
+}
+
+float fiberNoise(vec2 uv, vec2 seedOffset) {
+ float epsilon = 0.001;
+ float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset);
+ float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset);
+ float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset);
+ float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset);
+ return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon);
+}
+`;
+export {
+ colorBandingFix,
+ declarePI,
+ fiberNoise,
+ proceduralHash11,
+ proceduralHash21,
+ proceduralHash22,
+ rotation2,
+ simplexNoise,
+ textureRandomizerGB,
+ textureRandomizerR
+};
+//# sourceMappingURL=shader-utils.js.map
diff --git a/public/vendor/paper-shaders/shader-utils.js.map b/public/vendor/paper-shaders/shader-utils.js.map
new file mode 100644
index 0000000..d0cdc67
--- /dev/null
+++ b/public/vendor/paper-shaders/shader-utils.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../src/shader-utils.ts"],
+ "sourcesContent": ["// language=GLSL\nexport const declarePI = `\n#define TWO_PI 6.28318530718\n#define PI 3.14159265358979323846\n`;\n\n// language=GLSL\nexport const rotation2 = `\nvec2 rotate(vec2 uv, float th) {\n return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;\n}\n`;\n\n// language=GLSL\nexport const proceduralHash11 = `\n float hash11(float p) {\n p = fract(p * 0.3183099) + 0.1;\n p *= p + 19.19;\n return fract(p * p);\n }\n`;\n\n// language=GLSL\nexport const proceduralHash21 = `\n float hash21(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p + 19.19);\n return fract(p.x * p.y);\n }\n`;\n\n// language=GLSL\nexport const proceduralHash22 = `\n vec2 hash22(vec2 p) {\n p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;\n p += dot(p, p.yx + 19.19);\n return fract(vec2(p.x * p.y, p.x + p.y));\n }\n`;\n\n// language=GLSL\nexport const textureRandomizerR = `\n float randomR(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).r;\n }\n`;\n\n// language=GLSL\nexport const textureRandomizerGB = `\n vec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n }\n`;\n\n// language=GLSL\nexport const colorBandingFix = `\n color += 1. / 256. * (fract(sin(dot(.014 * gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n`;\n\n// language=GLSL\nexport const simplexNoise = `\nvec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }\nfloat snoise(vec2 v) {\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0));\n vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)), 0.0);\n m = m * m;\n m = m * m;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n`;\n\n// language=GLSL\nexport const fiberNoise = `\nfloat fiberRandom(vec2 p) {\n vec2 uv = floor(p) / 100.;\n return texture(u_noiseTexture, fract(uv)).b;\n}\n\nfloat fiberValueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = fiberRandom(i);\n float b = fiberRandom(i + vec2(1.0, 0.0));\n float c = fiberRandom(i + vec2(0.0, 1.0));\n float d = fiberRandom(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 fiberNoiseFbm(in vec2 n, vec2 seedOffset) {\n float total = 0.0, amplitude = 1.;\n for (int i = 0; i < 4; i++) {\n n = rotate(n, .7);\n total += fiberValueNoise(n + seedOffset) * amplitude;\n n *= 2.;\n amplitude *= 0.6;\n }\n return total;\n}\n\nfloat fiberNoise(vec2 uv, vec2 seedOffset) {\n float epsilon = 0.001;\n float n1 = fiberNoiseFbm(uv + vec2(epsilon, 0.0), seedOffset);\n float n2 = fiberNoiseFbm(uv - vec2(epsilon, 0.0), seedOffset);\n float n3 = fiberNoiseFbm(uv + vec2(0.0, epsilon), seedOffset);\n float n4 = fiberNoiseFbm(uv - vec2(0.0, epsilon), seedOffset);\n return length(vec2(n1 - n2, n3 - n4)) / (2.0 * epsilon);\n}\n`;\n"],
+ "mappings": ";;;;;AACO,MAAM,YAAY;AAAA;AAAA;AAAA;AAMlB,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAOlB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ3B,MAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAQ5B,MAAM,kBAAkB;AAAA;AAAA;AAKxB,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BrB,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/color-panels.d.ts b/public/vendor/paper-shaders/shaders/color-panels.d.ts
new file mode 100644
index 0000000..20868f1
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/color-panels.d.ts
@@ -0,0 +1,70 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const colorPanelsMeta: {
+ readonly maxColorCount: 7;
+};
+/**
+ * Pseudo-3D semi-transparent panels rotating around a central axis
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_scale (float): Overall zoom level, used for anti-aliasing calculations
+ * - u_colors (vec4[]): Up to 7 RGBA colors used to color the panels
+ * - u_colorsCount (float): Number of active colors
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_density (float): Angle between every 2 panels (0.25 to 7)
+ * - u_angle1 (float): Skew angle applied to all panes (-1 to 1)
+ * - u_angle2 (float): Skew angle applied to all panes (-1 to 1)
+ * - u_length (float): Panel length relative to total height (0 to 3)
+ * - u_edges (bool): Color highlight on the panels edges
+ * - u_blur (float): Side blur, 0 for sharp edges (0 to 0.5)
+ * - u_fadeIn (float): Transparency near central axis (0 to 1)
+ * - u_fadeOut (float): Transparency near viewer (0 to 1)
+ * - u_gradient (float): Color mixing within a panel, 0 = solid, 1 = gradient (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const colorPanelsFragmentShader: string;
+export interface ColorPanelsUniforms extends ShaderSizingUniforms {
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_colorBack: [number, number, number, number];
+ u_angle1: number;
+ u_angle2: number;
+ u_length: number;
+ u_edges: boolean;
+ u_blur: number;
+ u_fadeIn: number;
+ u_fadeOut: number;
+ u_density: number;
+ u_gradient: number;
+}
+export interface ColorPanelsParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ colorBack?: string;
+ angle1?: number;
+ angle2?: number;
+ length?: number;
+ edges?: boolean;
+ blur?: number;
+ fadeIn?: number;
+ fadeOut?: number;
+ density?: number;
+ gradient?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/color-panels.js b/public/vendor/paper-shaders/shaders/color-panels.js
new file mode 100644
index 0000000..ed8fcbd
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/color-panels.js
@@ -0,0 +1,224 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, colorBandingFix } from "../shader-utils.js";
+const colorPanelsMeta = {
+ maxColorCount: 7
+};
+const colorPanelsFragmentShader = `#version 300 es
+precision lowp float;
+
+uniform float u_time;
+uniform mediump float u_scale;
+
+uniform vec4 u_colors[${colorPanelsMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform vec4 u_colorBack;
+uniform float u_density;
+uniform float u_angle1;
+uniform float u_angle2;
+uniform float u_length;
+uniform bool u_edges;
+uniform float u_blur;
+uniform float u_fadeIn;
+uniform float u_fadeOut;
+uniform float u_gradient;
+
+in vec2 v_objectUV;
+
+out vec4 fragColor;
+
+${declarePI}
+
+const float zLimit = .5;
+
+vec2 getPanel(float angle, vec2 uv, float invLength, float aa) {
+ float sinA = sin(angle);
+ float cosA = cos(angle);
+
+ float denom = sinA - uv.y * cosA;
+ if (abs(denom) < .01) return vec2(0.);
+
+ float z = uv.y / denom;
+
+ if (z <= 0. || z > zLimit) return vec2(0.);
+
+ float zRatio = z / zLimit;
+ float panelMap = 1. - zRatio;
+ float x = uv.x * (cosA * z + 1.) * invLength;
+
+ float zOffset = zRatio - .5;
+ float left = -.5 + zOffset * u_angle1;
+ float right = .5 - zOffset * u_angle2;
+ float blurX = aa + 2. * panelMap * u_blur;
+
+ float leftEdge1 = left - blurX;
+ float leftEdge2 = left + .25 * blurX;
+ float rightEdge1 = right - .25 * blurX;
+ float rightEdge2 = right + blurX;
+
+ float panel = smoothstep(leftEdge1, leftEdge2, x) * (1.0 - smoothstep(rightEdge1, rightEdge2, x));
+ panel *= mix(0., panel, smoothstep(0., .01 / max(u_scale, 1e-6), panelMap));
+
+ float midScreen = abs(sinA);
+ if (u_edges == true) {
+ panelMap = mix(.99, panelMap, panel * clamp(panelMap / (.15 * (1. - pow(midScreen, .1))), 0.0, 1.0));
+ } else if (midScreen < .07) {
+ panel *= (midScreen * 15.);
+ }
+
+ return vec2(panel, panelMap);
+}
+
+vec4 blendColor(vec4 colorA, float panelMask, float panelMap) {
+ float fade = 1. - smoothstep(.97 - .97 * u_fadeIn, 1., panelMap);
+
+ fade *= smoothstep(-.2 * (1. - u_fadeOut), u_fadeOut, panelMap);
+
+ vec3 blendedRGB = mix(vec3(0.), colorA.rgb, fade);
+ float blendedAlpha = mix(0., colorA.a, fade);
+
+ return vec4(blendedRGB, blendedAlpha) * panelMask;
+}
+
+void main() {
+ vec2 uv = v_objectUV;
+ uv *= 1.25;
+
+ float t = .02 * u_time;
+ t = fract(t);
+ bool reverseTime = (t < 0.5);
+
+ vec3 color = vec3(0.);
+ float opacity = 0.;
+
+ float aa = .005 / u_scale;
+ int colorsCount = int(u_colorsCount);
+
+ vec4 premultipliedColors[${colorPanelsMeta.maxColorCount}];
+ for (int i = 0; i < ${colorPanelsMeta.maxColorCount}; i++) {
+ if (i >= colorsCount) break;
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ premultipliedColors[i] = c;
+ }
+
+ float invLength = 1.5 / max(u_length, .001);
+
+ float totalColorWeight = 0.;
+ int panelsNumber = 12;
+
+ float densityNormalizer = 1.;
+ if (colorsCount == 4) {
+ panelsNumber = 16;
+ densityNormalizer = 1.34;
+ } else if (colorsCount == 5) {
+ panelsNumber = 20;
+ densityNormalizer = 1.67;
+ } else if (colorsCount == 7) {
+ panelsNumber = 14;
+ densityNormalizer = 1.17;
+ }
+
+ float fPanelsNumber = float(panelsNumber);
+
+ float totalPanelsShape = 0.;
+ float panelGrad = 1. - clamp(u_gradient, 0., 1.);
+
+ for (int set = 0; set < 2; set++) {
+ bool isForward = (set == 0 && !reverseTime) || (set == 1 && reverseTime);
+ if (!isForward) continue;
+
+ for (int i = 0; i <= 20; i++) {
+ if (i >= panelsNumber) break;
+
+ int idx = panelsNumber - 1 - i;
+
+ float offset = float(idx) / fPanelsNumber;
+ if (set == 1) {
+ offset += .5;
+ }
+
+ float densityFract = densityNormalizer * fract(t + offset);
+ float angleNorm = densityFract / u_density;
+ if (densityFract >= .5 || angleNorm >= .3) continue;
+
+ float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);
+ float smoothAngle = clamp((.3 - angleNorm) / .05, 0., 1.);
+ if (smoothDensity * smoothAngle < .001) continue;
+
+ if (angleNorm > .5) {
+ angleNorm = 0.5;
+ }
+ vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);
+ if (panel[0] <= .001) continue;
+ float panelMask = panel[0] * smoothDensity * smoothAngle;
+ float panelMap = panel[1];
+
+ int colorIdx = idx % colorsCount;
+ int nextColorIdx = (idx + 1) % colorsCount;
+
+ vec4 colorA = premultipliedColors[colorIdx];
+ vec4 colorB = premultipliedColors[nextColorIdx];
+
+ colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));
+ vec4 blended = blendColor(colorA, panelMask, panelMap);
+ color = blended.rgb + color * (1. - blended.a);
+ opacity = blended.a + opacity * (1. - blended.a);
+ }
+
+
+ for (int i = 0; i <= 20; i++) {
+ if (i >= panelsNumber) break;
+
+ int idx = panelsNumber - 1 - i;
+
+ float offset = float(idx) / fPanelsNumber;
+ if (set == 0) {
+ offset += .5;
+ }
+
+ float densityFract = densityNormalizer * fract(-t + offset);
+ float angleNorm = -densityFract / u_density;
+ if (densityFract >= .5 || angleNorm < -.3) continue;
+
+ float smoothDensity = clamp((.5 - densityFract) / .1, 0., 1.) * clamp(densityFract / .01, 0., 1.);
+ float smoothAngle = clamp((angleNorm + .3) / .05, 0., 1.);
+ if (smoothDensity * smoothAngle < .001) continue;
+
+ vec2 panel = getPanel(angleNorm * TWO_PI + PI, uv, invLength, aa);
+ float panelMask = panel[0] * smoothDensity * smoothAngle;
+ if (panelMask <= .001) continue;
+ float panelMap = panel[1];
+
+ int colorIdx = (colorsCount - (idx % colorsCount)) % colorsCount;
+ if (colorIdx < 0) colorIdx += colorsCount;
+ int nextColorIdx = (colorIdx + 1) % colorsCount;
+
+ vec4 colorA = premultipliedColors[colorIdx];
+ vec4 colorB = premultipliedColors[nextColorIdx];
+
+ colorA = mix(colorA, colorB, max(0., smoothstep(.0, .45, panelMap) - panelGrad));
+ vec4 blended = blendColor(colorA, panelMask, panelMap);
+ color = blended.rgb + color * (1. - blended.a);
+ opacity = blended.a + opacity * (1. - blended.a);
+ }
+ }
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1.0 - opacity);
+ opacity = opacity + u_colorBack.a * (1.0 - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ colorPanelsFragmentShader,
+ colorPanelsMeta
+};
+//# sourceMappingURL=color-panels.js.map
diff --git a/public/vendor/paper-shaders/shaders/color-panels.js.map b/public/vendor/paper-shaders/shaders/color-panels.js.map
new file mode 100644
index 0000000..286797e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/color-panels.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/color-panels.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { 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 semi-transparent panels rotating around a central axis\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 7 RGBA colors used to color the panels\n * - u_colorsCount (float): Number of active colors\n * - u_colorBack (vec4): Background color in RGBA\n * - u_density (float): Angle between every 2 panels (0.25 to 7)\n * - u_angle1 (float): Skew angle applied to all panes (-1 to 1)\n * - u_angle2 (float): Skew angle applied to all panes (-1 to 1)\n * - u_length (float): Panel length relative to total height (0 to 3)\n * - u_edges (bool): Color highlight on the panels edges\n * - u_blur (float): Side blur, 0 for sharp edges (0 to 0.5)\n * - u_fadeIn (float): Transparency near central axis (0 to 1)\n * - u_fadeOut (float): Transparency near viewer (0 to 1)\n * - u_gradient (float): Color mixing within a panel, 0 = solid, 1 = gradient (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\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\nin vec2 v_objectUV;\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 / max(u_scale, 1e-6), 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 = 1. - smoothstep(.97 - .97 * u_fadeIn, 1., panelMap);\n\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 / max(u_length, .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"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,uBAAuB;AAEpC,MAAM,kBAAkB;AAAA,EAC7B,eAAe;AACjB;AAwCO,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMxB,gBAAgB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBpD,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAmEiB,gBAAgB,aAAc;AAAA,wBACnC,gBAAgB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiHlD,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/dithering.d.ts b/public/vendor/paper-shaders/shaders/dithering.d.ts
new file mode 100644
index 0000000..d9f8dc8
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dithering.d.ts
@@ -0,0 +1,62 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Animated 2-color dithering over multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere).
+ *
+ * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep
+ * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any
+ * transforms, so scaling/rotating only affects the underlying pattern shape.
+ * No vertex shader outputs (v_objectUV, v_patternUV, etc.) are used.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorFront (vec4): Foreground (ink) color in RGBA
+ * - u_shape (float): Shape pattern type (1 = simplex, 2 = warp, 3 = dots, 4 = wave, 5 = ripple, 6 = swirl, 7 = sphere)
+ * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)
+ * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)
+ *
+ * */
+export declare const ditheringFragmentShader: string;
+export interface DitheringUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colorFront: [number, number, number, number];
+ u_shape: (typeof DitheringShapes)[DitheringShape];
+ u_type: (typeof DitheringTypes)[DitheringType];
+ u_pxSize: number;
+}
+export interface DitheringParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colorFront?: string;
+ shape?: DitheringShape;
+ type?: DitheringType;
+ size?: number;
+}
+export declare const DitheringShapes: {
+ readonly simplex: 1;
+ readonly warp: 2;
+ readonly dots: 3;
+ readonly wave: 4;
+ readonly ripple: 5;
+ readonly swirl: 6;
+ readonly sphere: 7;
+};
+export type DitheringShape = keyof typeof DitheringShapes;
+export declare const DitheringTypes: {
+ readonly random: 1;
+ readonly '2x2': 2;
+ readonly '4x4': 3;
+ readonly '8x8': 4;
+};
+export type DitheringType = keyof typeof DitheringTypes;
diff --git a/public/vendor/paper-shaders/shaders/dithering.js b/public/vendor/paper-shaders/shaders/dithering.js
new file mode 100644
index 0000000..9802517
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dithering.js
@@ -0,0 +1,271 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {
+} from "../shader-sizing.js";
+import { simplexNoise, declarePI, proceduralHash11, proceduralHash21 } from "../shader-utils.js";
+const ditheringFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform vec2 u_resolution;
+uniform float u_pixelRatio;
+uniform float u_originX;
+uniform float u_originY;
+uniform float u_worldWidth;
+uniform float u_worldHeight;
+uniform float u_fit;
+uniform float u_scale;
+uniform float u_rotation;
+uniform float u_offsetX;
+uniform float u_offsetY;
+
+uniform float u_pxSize;
+uniform vec4 u_colorBack;
+uniform vec4 u_colorFront;
+uniform float u_shape;
+uniform float u_type;
+
+out vec4 fragColor;
+
+${simplexNoise}
+${declarePI}
+${proceduralHash11}
+${proceduralHash21}
+
+float getSimplexNoise(vec2 uv, float t) {
+ float noise = .5 * snoise(uv - vec2(0., .3 * t));
+ noise += .5 * snoise(2. * uv + vec2(0., .32 * t));
+
+ return noise;
+}
+
+const int bayer2x2[4] = int[4](0, 2, 3, 1);
+const int bayer4x4[16] = int[16](
+0, 8, 2, 10,
+12, 4, 14, 6,
+3, 11, 1, 9,
+15, 7, 13, 5
+);
+
+const int bayer8x8[64] = int[64](
+0, 32, 8, 40, 2, 34, 10, 42,
+48, 16, 56, 24, 50, 18, 58, 26,
+12, 44, 4, 36, 14, 46, 6, 38,
+60, 28, 52, 20, 62, 30, 54, 22,
+3, 35, 11, 43, 1, 33, 9, 41,
+51, 19, 59, 27, 49, 17, 57, 25,
+15, 47, 7, 39, 13, 45, 5, 37,
+63, 31, 55, 23, 61, 29, 53, 21
+);
+
+float getBayerValue(vec2 uv, int size) {
+ ivec2 pos = ivec2(fract(uv / float(size)) * float(size));
+ int index = pos.y * size + pos.x;
+
+ if (size == 2) {
+ return float(bayer2x2[index]) / 4.0;
+ } else if (size == 4) {
+ return float(bayer4x4[index]) / 16.0;
+ } else if (size == 8) {
+ return float(bayer8x8[index]) / 64.0;
+ }
+ return 0.0;
+}
+
+
+void main() {
+ float t = .5 * u_time;
+
+ float pxSize = u_pxSize * u_pixelRatio;
+ vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;
+ pxSizeUV /= pxSize;
+ vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;
+ vec2 normalizedUV = canvasPixelizedUV / u_resolution;
+
+ vec2 ditheringNoiseUV = canvasPixelizedUV;
+ vec2 shapeUV = normalizedUV;
+
+ vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
+ vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
+ givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
+ float r = u_rotation * PI / 180.;
+ mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
+ vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
+
+ float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;
+ vec2 boxSize = vec2(
+ (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
+ (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
+ );
+
+ if (u_shape > 3.5) {
+ vec2 objectBoxSize = vec2(0.);
+ // fit = none
+ objectBoxSize.x = min(boxSize.x, boxSize.y);
+ if (u_fit == 1.) { // fit = contain
+ objectBoxSize.x = min(u_resolution.x, u_resolution.y);
+ } else if (u_fit == 2.) { // fit = cover
+ objectBoxSize.x = max(u_resolution.x, u_resolution.y);
+ }
+ objectBoxSize.y = objectBoxSize.x;
+ vec2 objectWorldScale = u_resolution.xy / objectBoxSize;
+
+ shapeUV *= objectWorldScale;
+ shapeUV += boxOrigin * (objectWorldScale - 1.);
+ shapeUV += vec2(-u_offsetX, u_offsetY);
+ shapeUV /= u_scale;
+ shapeUV = graphicRotation * shapeUV;
+ } else {
+ vec2 patternBoxSize = vec2(0.);
+ // fit = none
+ patternBoxSize.x = patternBoxRatio * min(boxSize.x / patternBoxRatio, boxSize.y);
+ float patternWorldNoFitBoxWidth = patternBoxSize.x;
+ if (u_fit == 1.) { // fit = contain
+ patternBoxSize.x = patternBoxRatio * min(u_resolution.x / patternBoxRatio, u_resolution.y);
+ } else if (u_fit == 2.) { // fit = cover
+ patternBoxSize.x = patternBoxRatio * max(u_resolution.x / patternBoxRatio, u_resolution.y);
+ }
+ patternBoxSize.y = patternBoxSize.x / patternBoxRatio;
+ vec2 patternWorldScale = u_resolution.xy / patternBoxSize;
+
+ shapeUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;
+ shapeUV += boxOrigin;
+ shapeUV -= boxOrigin / patternWorldScale;
+ shapeUV *= u_resolution.xy;
+ shapeUV /= u_pixelRatio;
+ if (u_fit > 0.) {
+ shapeUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);
+ }
+ shapeUV /= u_scale;
+ shapeUV = graphicRotation * shapeUV;
+ shapeUV += boxOrigin / patternWorldScale;
+ shapeUV -= boxOrigin;
+ shapeUV += .5;
+ }
+
+ float shape = 0.;
+ if (u_shape < 1.5) {
+ // Simplex noise
+ shapeUV *= .001;
+
+ shape = 0.5 + 0.5 * getSimplexNoise(shapeUV, t);
+ shape = smoothstep(0.3, 0.9, shape);
+
+ } else if (u_shape < 2.5) {
+ // Warp
+ shapeUV *= .003;
+
+ for (float i = 1.0; i < 6.0; i++) {
+ shapeUV.x += 0.6 / i * cos(i * 2.5 * shapeUV.y + t);
+ shapeUV.y += 0.6 / i * cos(i * 1.5 * shapeUV.x + t);
+ }
+
+ shape = .15 / max(0.001, abs(sin(t - shapeUV.y - shapeUV.x)));
+ shape = smoothstep(0.02, 1., shape);
+
+ } else if (u_shape < 3.5) {
+ // Dots
+ shapeUV *= .05;
+
+ float stripeIdx = floor(2. * shapeUV.x / TWO_PI);
+ float rand = hash11(stripeIdx * 10.);
+ rand = sign(rand - .5) * pow(.1 + abs(rand), .4);
+ shape = sin(shapeUV.x) * cos(shapeUV.y - 5. * rand * t);
+ shape = pow(abs(shape), 6.);
+
+ } else if (u_shape < 4.5) {
+ // Sine wave
+ shapeUV *= 4.;
+
+ float wave = cos(.5 * shapeUV.x - 2. * t) * sin(1.5 * shapeUV.x + t) * (.75 + .25 * cos(3. * t));
+ shape = 1. - smoothstep(-1., 1., shapeUV.y + wave);
+
+ } else if (u_shape < 5.5) {
+ // Ripple
+
+ float dist = length(shapeUV);
+ float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;
+ shape = waves;
+
+ } else if (u_shape < 6.5) {
+ // Swirl
+
+ float l = length(shapeUV);
+ float angle = 6. * atan(shapeUV.y, shapeUV.x) + 4. * t;
+ float twist = 1.2;
+ float offset = 1. / pow(max(l, 1e-6), twist) + angle / TWO_PI;
+ float mid = smoothstep(0., 1., pow(l, twist));
+ shape = mix(0., fract(offset), mid);
+
+ } else {
+ // Sphere
+ shapeUV *= 2.;
+
+ float d = 1. - pow(length(shapeUV), 2.);
+ vec3 pos = vec3(shapeUV, sqrt(max(0., d)));
+ vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));
+ shape = .5 + .5 * dot(lightPos, pos);
+ shape *= step(0., d);
+ }
+
+
+ int type = int(floor(u_type));
+ float dithering = 0.0;
+
+ switch (type) {
+ case 1: {
+ dithering = step(hash21(ditheringNoiseUV), shape);
+ } break;
+ case 2:
+ dithering = getBayerValue(pxSizeUV, 2);
+ break;
+ case 3:
+ dithering = getBayerValue(pxSizeUV, 4);
+ break;
+ default :
+ dithering = getBayerValue(pxSizeUV, 8);
+ break;
+ }
+
+ dithering -= .5;
+ float res = step(.5, shape + dithering);
+
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+
+ vec3 color = fgColor * res;
+ float opacity = fgOpacity * res;
+
+ color += bgColor * (1. - opacity);
+ opacity += bgOpacity * (1. - opacity);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const DitheringShapes = {
+ simplex: 1,
+ warp: 2,
+ dots: 3,
+ wave: 4,
+ ripple: 5,
+ swirl: 6,
+ sphere: 7
+};
+const DitheringTypes = {
+ "random": 1,
+ "2x2": 2,
+ "4x4": 3,
+ "8x8": 4
+};
+export {
+ DitheringShapes,
+ DitheringTypes,
+ ditheringFragmentShader
+};
+//# sourceMappingURL=dithering.js.map
diff --git a/public/vendor/paper-shaders/shaders/dithering.js.map b/public/vendor/paper-shaders/shaders/dithering.js.map
new file mode 100644
index 0000000..322a46e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dithering.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/dithering.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { simplexNoise, declarePI, proceduralHash11, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Animated 2-color dithering over multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere).\n *\n * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep\n * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any\n * transforms, so scaling/rotating only affects the underlying pattern shape.\n * No vertex shader outputs (v_objectUV, v_patternUV, etc.) are used.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorFront (vec4): Foreground (ink) color in RGBA\n * - u_shape (float): Shape pattern type (1 = simplex, 2 = warp, 3 = dots, 4 = wave, 5 = ripple, 6 = swirl, 7 = sphere)\n * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)\n * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)\n *\n * */\n\n// language=GLSL\nexport const ditheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform float u_pxSize;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_shape;\nuniform float u_type;\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](\n0, 8, 2, 10,\n12, 4, 14, 6,\n3, 11, 1, 9,\n15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n0, 32, 8, 40, 2, 34, 10, 42,\n48, 16, 56, 24, 50, 18, 58, 26,\n12, 44, 4, 36, 14, 46, 6, 38,\n60, 28, 52, 20, 62, 30, 54, 22,\n3, 35, 11, 43, 1, 33, 9, 41,\n51, 19, 59, 27, 49, 17, 57, 25,\n15, 47, 7, 39, 13, 45, 5, 37,\n63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(fract(uv / float(size)) * 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 float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;\n pxSizeUV /= pxSize;\n vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;\n vec2 normalizedUV = canvasPixelizedUV / u_resolution;\n\n vec2 ditheringNoiseUV = canvasPixelizedUV;\n vec2 shapeUV = normalizedUV;\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 * PI / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 boxSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n \n if (u_shape > 3.5) {\n vec2 objectBoxSize = vec2(0.);\n // fit = none\n objectBoxSize.x = min(boxSize.x, boxSize.y);\n if (u_fit == 1.) { // fit = contain\n objectBoxSize.x = min(u_resolution.x, u_resolution.y);\n } else if (u_fit == 2.) { // fit = cover\n objectBoxSize.x = max(u_resolution.x, u_resolution.y);\n }\n objectBoxSize.y = objectBoxSize.x;\n vec2 objectWorldScale = u_resolution.xy / objectBoxSize;\n\n shapeUV *= objectWorldScale;\n shapeUV += boxOrigin * (objectWorldScale - 1.);\n shapeUV += vec2(-u_offsetX, u_offsetY);\n shapeUV /= u_scale;\n shapeUV = graphicRotation * shapeUV;\n } else {\n vec2 patternBoxSize = vec2(0.);\n // fit = none\n patternBoxSize.x = patternBoxRatio * min(boxSize.x / patternBoxRatio, boxSize.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 shapeUV += vec2(-u_offsetX, u_offsetY) / patternWorldScale;\n shapeUV += boxOrigin;\n shapeUV -= boxOrigin / patternWorldScale;\n shapeUV *= u_resolution.xy;\n shapeUV /= u_pixelRatio;\n if (u_fit > 0.) {\n shapeUV *= (patternWorldNoFitBoxWidth / patternBoxSize.x);\n }\n shapeUV /= u_scale;\n shapeUV = graphicRotation * shapeUV;\n shapeUV += boxOrigin / patternWorldScale;\n shapeUV -= boxOrigin;\n shapeUV += .5;\n }\n\n float shape = 0.;\n if (u_shape < 1.5) {\n // Simplex noise\n shapeUV *= .001;\n\n shape = 0.5 + 0.5 * getSimplexNoise(shapeUV, t);\n shape = smoothstep(0.3, 0.9, shape);\n\n } else if (u_shape < 2.5) {\n // Warp\n shapeUV *= .003;\n\n for (float i = 1.0; i < 6.0; i++) {\n shapeUV.x += 0.6 / i * cos(i * 2.5 * shapeUV.y + t);\n shapeUV.y += 0.6 / i * cos(i * 1.5 * shapeUV.x + t);\n }\n\n shape = .15 / max(0.001, abs(sin(t - shapeUV.y - shapeUV.x)));\n shape = smoothstep(0.02, 1., shape);\n\n } else if (u_shape < 3.5) {\n // Dots\n shapeUV *= .05;\n\n float stripeIdx = floor(2. * shapeUV.x / TWO_PI);\n float rand = hash11(stripeIdx * 10.);\n rand = sign(rand - .5) * pow(.1 + abs(rand), .4);\n shape = sin(shapeUV.x) * cos(shapeUV.y - 5. * rand * t);\n shape = pow(abs(shape), 6.);\n\n } else if (u_shape < 4.5) {\n // Sine wave\n shapeUV *= 4.;\n\n float wave = cos(.5 * shapeUV.x - 2. * t) * sin(1.5 * shapeUV.x + t) * (.75 + .25 * cos(3. * t));\n shape = 1. - smoothstep(-1., 1., shapeUV.y + wave);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n float dist = length(shapeUV);\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(shapeUV);\n float angle = 6. * atan(shapeUV.y, shapeUV.x) + 4. * t;\n float twist = 1.2;\n float offset = 1. / pow(max(l, 1e-6), 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 shapeUV *= 2.;\n\n float d = 1. - pow(length(shapeUV), 2.);\n vec3 pos = vec3(shapeUV, sqrt(max(0., 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(ditheringNoiseUV), shape);\n } break;\n case 2:\n dithering = getBayerValue(pxSizeUV, 2);\n break;\n case 3:\n dithering = getBayerValue(pxSizeUV, 4);\n break;\n default :\n dithering = getBayerValue(pxSizeUV, 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 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 size?: 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"],
+ "mappings": ";;;;;AACA;AAAA,OAGO;AACP,SAAS,cAAc,WAAW,kBAAkB,wBAAwB;AAgCrE,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyB5C,YAAa;AAAA,EACb,SAAU;AAAA,EACV,gBAAiB;AAAA,EACjB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuOb,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;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/dot-grid.d.ts b/public/vendor/paper-shaders/shaders/dot-grid.d.ts
new file mode 100644
index 0000000..31d5d35
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dot-grid.d.ts
@@ -0,0 +1,65 @@
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Static grid pattern made of circles, diamonds, squares or triangles.
+ *
+ * Fragment shader uniforms:
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorFill (vec4): Shape fill color in RGBA
+ * - u_colorStroke (vec4): Shape stroke color in RGBA
+ * - u_dotSize (float): Base size of each shape in pixels (1 to 100)
+ * - u_gapX (float): Pattern horizontal spacing in pixels (2 to 500)
+ * - u_gapY (float): Pattern vertical spacing in pixels (2 to 500)
+ * - u_strokeWidth (float): Outline stroke width in pixels (0 to 50)
+ * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1)
+ * - u_opacityRange (float): Random variation in shape opacity, 0 = opaque, higher = semi-transparent (0 to 1)
+ * - u_shape (float): Shape type (0 = circle, 1 = diamond, 2 = square, 3 = triangle)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with scale, rotation and offset applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const dotGridFragmentShader: string;
+export interface DotGridUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colorFill: [number, number, number, number];
+ u_colorStroke: [number, number, number, number];
+ u_dotSize: number;
+ u_gapX: number;
+ u_gapY: number;
+ u_strokeWidth: number;
+ u_sizeRange: number;
+ u_opacityRange: number;
+ u_shape: (typeof DotGridShapes)[DotGridShape];
+}
+export interface DotGridParams extends ShaderSizingParams {
+ colorBack?: string;
+ colorFill?: string;
+ colorStroke?: string;
+ size?: number;
+ gapX?: number;
+ gapY?: number;
+ strokeWidth?: number;
+ sizeRange?: number;
+ opacityRange?: number;
+ shape?: DotGridShape;
+}
+export declare const DotGridShapes: {
+ readonly circle: 0;
+ readonly diamond: 1;
+ readonly square: 2;
+ readonly triangle: 3;
+};
+export type DotGridShape = keyof typeof DotGridShapes;
diff --git a/public/vendor/paper-shaders/shaders/dot-grid.js b/public/vendor/paper-shaders/shaders/dot-grid.js
new file mode 100644
index 0000000..e657564
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dot-grid.js
@@ -0,0 +1,110 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, simplexNoise } from "../shader-utils.js";
+const dotGridFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorFill;
+uniform vec4 u_colorStroke;
+uniform float u_dotSize;
+uniform float u_gapX;
+uniform float u_gapY;
+uniform float u_strokeWidth;
+uniform float u_sizeRange;
+uniform float u_opacityRange;
+uniform float u_shape;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${simplexNoise}
+
+float polygon(vec2 p, float N, float rot) {
+ float a = atan(p.x, p.y) + rot;
+ float r = TWO_PI / float(N);
+
+ return cos(floor(.5 + a / r) * r - a) * length(p);
+}
+
+void main() {
+
+ // x100 is a default multiplier between vertex and fragmant shaders
+ // we use it to avoid UV presision issues
+ vec2 shape_uv = 100. * v_patternUV;
+
+ vec2 gap = max(abs(vec2(u_gapX, u_gapY)), vec2(1e-6));
+ vec2 grid = fract(shape_uv / gap) + 1e-4;
+ vec2 grid_idx = floor(shape_uv / gap);
+ float sizeRandomizer = .5 + .8 * snoise(2. * vec2(grid_idx.x * 100., grid_idx.y));
+ float opacity_randomizer = .5 + .7 * snoise(2. * vec2(grid_idx.y, grid_idx.x));
+
+ vec2 center = vec2(0.5) - 1e-3;
+ vec2 p = (grid - center) * vec2(u_gapX, u_gapY);
+
+ float baseSize = u_dotSize * (1. - sizeRandomizer * u_sizeRange);
+ float strokeWidth = u_strokeWidth * (1. - sizeRandomizer * u_sizeRange);
+
+ float dist;
+ if (u_shape < 0.5) {
+ // Circle
+ dist = length(p);
+ } else if (u_shape < 1.5) {
+ // Diamond
+ strokeWidth *= 1.5;
+ dist = polygon(1.5 * p, 4., .25 * PI);
+ } else if (u_shape < 2.5) {
+ // Square
+ dist = polygon(1.03 * p, 4., 1e-3);
+ } else {
+ // Triangle
+ strokeWidth *= 1.5;
+ p = p * 2. - 1.;
+ p *= .9;
+ p.y = 1. - p.y;
+ p.y -= .75 * baseSize;
+ dist = polygon(p, 3., 1e-3);
+ }
+
+ float edgeWidth = fwidth(dist);
+ float shapeOuter = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist - strokeWidth);
+ float shapeInner = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist);
+ float stroke = shapeOuter - shapeInner;
+
+ float dotOpacity = max(0., 1. - opacity_randomizer * u_opacityRange);
+ stroke *= dotOpacity;
+ shapeInner *= dotOpacity;
+
+ stroke *= u_colorStroke.a;
+ shapeInner *= u_colorFill.a;
+
+ vec3 color = vec3(0.);
+ color += stroke * u_colorStroke.rgb;
+ color += shapeInner * u_colorFill.rgb;
+ color += (1. - shapeInner - stroke) * u_colorBack.rgb * u_colorBack.a;
+
+ float opacity = 0.;
+ opacity += stroke;
+ opacity += shapeInner;
+ opacity += (1. - opacity) * u_colorBack.a;
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const DotGridShapes = {
+ circle: 0,
+ diamond: 1,
+ square: 2,
+ triangle: 3
+};
+export {
+ DotGridShapes,
+ dotGridFragmentShader
+};
+//# sourceMappingURL=dot-grid.js.map
diff --git a/public/vendor/paper-shaders/shaders/dot-grid.js.map b/public/vendor/paper-shaders/shaders/dot-grid.js.map
new file mode 100644
index 0000000..3de1213
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dot-grid.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/dot-grid.ts"],
+ "sourcesContent": ["import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, simplexNoise } from '../shader-utils.js';\n\n/**\n * Static grid pattern made of circles, diamonds, squares or triangles.\n *\n * Fragment shader uniforms:\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorFill (vec4): Shape fill color in RGBA\n * - u_colorStroke (vec4): Shape stroke color in RGBA\n * - u_dotSize (float): Base size of each shape in pixels (1 to 100)\n * - u_gapX (float): Pattern horizontal spacing in pixels (2 to 500)\n * - u_gapY (float): Pattern vertical spacing in pixels (2 to 500)\n * - u_strokeWidth (float): Outline stroke width in pixels (0 to 50)\n * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1)\n * - u_opacityRange (float): Random variation in shape opacity, 0 = opaque, higher = semi-transparent (0 to 1)\n * - u_shape (float): Shape type (0 = circle, 1 = diamond, 2 = square, 3 = triangle)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with scale, rotation and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const dotGridFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFill;\nuniform vec4 u_colorStroke;\nuniform float u_dotSize;\nuniform float u_gapX;\nuniform float u_gapY;\nuniform float u_strokeWidth;\nuniform float u_sizeRange;\nuniform float u_opacityRange;\nuniform float u_shape;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n\nfloat polygon(vec2 p, float N, float rot) {\n float a = atan(p.x, p.y) + rot;\n float r = TWO_PI / float(N);\n\n return cos(floor(.5 + a / r) * r - a) * length(p);\n}\n\nvoid main() {\n\n // x100 is a default multiplier between vertex and fragmant shaders\n // we use it to avoid UV presision issues\n vec2 shape_uv = 100. * v_patternUV;\n\n vec2 gap = max(abs(vec2(u_gapX, u_gapY)), vec2(1e-6));\n vec2 grid = fract(shape_uv / gap) + 1e-4;\n vec2 grid_idx = floor(shape_uv / gap);\n float sizeRandomizer = .5 + .8 * snoise(2. * vec2(grid_idx.x * 100., grid_idx.y));\n float opacity_randomizer = .5 + .7 * snoise(2. * vec2(grid_idx.y, grid_idx.x));\n\n vec2 center = vec2(0.5) - 1e-3;\n vec2 p = (grid - center) * vec2(u_gapX, u_gapY);\n\n float baseSize = u_dotSize * (1. - sizeRandomizer * u_sizeRange);\n float strokeWidth = u_strokeWidth * (1. - sizeRandomizer * u_sizeRange);\n\n float dist;\n if (u_shape < 0.5) {\n // Circle\n dist = length(p);\n } else if (u_shape < 1.5) {\n // Diamond\n strokeWidth *= 1.5;\n dist = polygon(1.5 * p, 4., .25 * PI);\n } else if (u_shape < 2.5) {\n // Square\n dist = polygon(1.03 * p, 4., 1e-3);\n } else {\n // Triangle\n strokeWidth *= 1.5;\n p = p * 2. - 1.;\n p *= .9;\n p.y = 1. - p.y;\n p.y -= .75 * baseSize;\n dist = polygon(p, 3., 1e-3);\n }\n\n float edgeWidth = fwidth(dist);\n float shapeOuter = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist - strokeWidth);\n float shapeInner = 1. - smoothstep(baseSize - edgeWidth, baseSize + edgeWidth, dist);\n float stroke = shapeOuter - shapeInner;\n\n float dotOpacity = max(0., 1. - opacity_randomizer * u_opacityRange);\n stroke *= dotOpacity;\n shapeInner *= dotOpacity;\n\n stroke *= u_colorStroke.a;\n shapeInner *= u_colorFill.a;\n\n vec3 color = vec3(0.);\n color += stroke * u_colorStroke.rgb;\n color += shapeInner * u_colorFill.rgb;\n color += (1. - shapeInner - stroke) * u_colorBack.rgb * u_colorBack.a;\n\n float opacity = 0.;\n opacity += stroke;\n opacity += shapeInner;\n opacity += (1. - opacity) * u_colorBack.a;\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DotGridUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFill: [number, number, number, number];\n u_colorStroke: [number, number, number, number];\n u_dotSize: number;\n u_gapX: number;\n u_gapY: number;\n u_strokeWidth: number;\n u_sizeRange: number;\n u_opacityRange: number;\n u_shape: (typeof DotGridShapes)[DotGridShape];\n}\n\nexport interface DotGridParams extends ShaderSizingParams {\n colorBack?: string;\n colorFill?: string;\n colorStroke?: string;\n size?: number;\n gapX?: number;\n gapY?: number;\n strokeWidth?: number;\n sizeRange?: number;\n opacityRange?: number;\n shape?: DotGridShape;\n}\n\nexport const DotGridShapes = {\n circle: 0,\n diamond: 1,\n square: 2,\n triangle: 3,\n} as const;\n\nexport type DotGridShape = keyof typeof DotGridShapes;\n"],
+ "mappings": ";;;;;AAAA,eAAmE;AACnE,SAAS,WAAW,oBAAoB;AAoCjC,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkB1C,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoGT,MAAM,gBAAgB;AAAA,EAC3B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AACZ;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/dot-orbit.d.ts b/public/vendor/paper-shaders/shaders/dot-orbit.d.ts
new file mode 100644
index 0000000..ef3818b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dot-orbit.d.ts
@@ -0,0 +1,57 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const dotOrbitMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * Animated multi-color dots pattern with each dot orbiting around its cell center.
+ * Supports up to 10 colors and various shape and motion controls.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 10 base colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2×N, etc. (1 to 4)
+ * - u_size (float): Dot radius relative to cell size (0 to 1)
+ * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1)
+ * - u_spreading (float): Maximum orbit distance around cell center (0 to 1)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const dotOrbitFragmentShader: string;
+export interface DotOrbitUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_size: number;
+ u_sizeRange: number;
+ u_spreading: number;
+ u_stepsPerColor: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface DotOrbitParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ size?: number;
+ sizeRange?: number;
+ spreading?: number;
+ stepsPerColor?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/dot-orbit.js b/public/vendor/paper-shaders/shaders/dot-orbit.js
new file mode 100644
index 0000000..edee2e7
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dot-orbit.js
@@ -0,0 +1,123 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, textureRandomizerR, textureRandomizerGB } from "../shader-utils.js";
+const dotOrbitMeta = {
+ maxColorCount: 10
+};
+const dotOrbitFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${dotOrbitMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_stepsPerColor;
+uniform float u_size;
+uniform float u_sizeRange;
+uniform float u_spreading;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${textureRandomizerR}
+${textureRandomizerGB}
+
+
+vec3 voronoiShape(vec2 uv, float time) {
+ vec2 i_uv = floor(uv);
+ vec2 f_uv = fract(uv);
+
+ float spreading = .25 * clamp(u_spreading, 0., 1.);
+
+ float minDist = 1.;
+ vec2 randomizer = vec2(0.);
+ for (int y = -1; y <= 1; y++) {
+ for (int x = -1; x <= 1; x++) {
+ vec2 tileOffset = vec2(float(x), float(y));
+ vec2 rand = randomGB(i_uv + tileOffset);
+ vec2 cellCenter = vec2(.5 + 1e-4);
+ cellCenter += spreading * cos(time + TWO_PI * rand);
+ cellCenter -= .5;
+ cellCenter = rotate(cellCenter, randomR(vec2(rand.x, rand.y)) + .1 * time);
+ cellCenter += .5;
+ float dist = length(tileOffset + cellCenter - f_uv);
+ if (dist < minDist) {
+ minDist = dist;
+ randomizer = rand;
+ }
+ }
+ }
+
+ return vec3(minDist, randomizer);
+}
+
+void main() {
+
+ vec2 shape_uv = v_patternUV;
+ shape_uv *= 1.5;
+
+ const float firstFrameOffset = -10.;
+ float t = u_time + firstFrameOffset;
+
+ vec3 voronoi = voronoiShape(shape_uv, t) + 1e-4;
+
+ float radius = .25 * clamp(u_size, 0., 1.) - .5 * clamp(u_sizeRange, 0., 1.) * voronoi[2];
+ float dist = voronoi[0];
+ float edgeWidth = fwidth(dist);
+ float dots = 1. - smoothstep(radius - edgeWidth, radius + edgeWidth, dist);
+
+ float shape = voronoi[1];
+
+ float mixer = shape * (u_colorsCount - 1.);
+ mixer = (shape - .5 / u_colorsCount) * u_colorsCount;
+ float steps = max(1., u_stepsPerColor);
+
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+ for (int i = 1; i < ${dotOrbitMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+ float localT = clamp(mixer - float(i - 1), 0.0, 1.0);
+ localT = round(localT * steps) / steps;
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, localT);
+ }
+
+ if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {
+ float localT = mixer + 1.;
+ if (mixer > (u_colorsCount - 1.)) {
+ localT = mixer - (u_colorsCount - 1.);
+ }
+ localT = round(localT * steps) / steps;
+ vec4 cFst = u_colors[0];
+ cFst.rgb *= cFst.a;
+ vec4 cLast = u_colors[int(u_colorsCount - 1.)];
+ cLast.rgb *= cLast.a;
+ gradient = mix(cLast, cFst, localT);
+ }
+
+ vec3 color = gradient.rgb * dots;
+ float opacity = gradient.a * dots;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1. - opacity);
+ opacity = opacity + u_colorBack.a * (1. - opacity);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ dotOrbitFragmentShader,
+ dotOrbitMeta
+};
+//# sourceMappingURL=dot-orbit.js.map
diff --git a/public/vendor/paper-shaders/shaders/dot-orbit.js.map b/public/vendor/paper-shaders/shaders/dot-orbit.js.map
new file mode 100644
index 0000000..e0a18c9
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/dot-orbit.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/dot-orbit.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, textureRandomizerR, textureRandomizerGB } from '../shader-utils.js';\n\nexport const dotOrbitMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Animated multi-color dots pattern with each dot orbiting around its cell center.\n * Supports up to 10 colors and various shape and motion controls.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 base colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2\u00D7N, etc. (1 to 4)\n * - u_size (float): Dot radius relative to cell size (0 to 1)\n * - u_sizeRange (float): Random variation in shape size, 0 = uniform, higher = random up to base size (0 to 1)\n * - u_spreading (float): Maximum orbit distance around cell center (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const dotOrbitFragmentShader: 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[${ dotOrbitMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_spreading;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ textureRandomizerR }\n${ textureRandomizerGB }\n\n\nvec3 voronoiShape(vec2 uv, float time) {\n vec2 i_uv = floor(uv);\n vec2 f_uv = fract(uv);\n\n float spreading = .25 * clamp(u_spreading, 0., 1.);\n\n float minDist = 1.;\n vec2 randomizer = vec2(0.);\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 tileOffset = vec2(float(x), float(y));\n vec2 rand = randomGB(i_uv + tileOffset);\n vec2 cellCenter = vec2(.5 + 1e-4);\n cellCenter += spreading * cos(time + TWO_PI * rand);\n cellCenter -= .5;\n cellCenter = rotate(cellCenter, randomR(vec2(rand.x, rand.y)) + .1 * time);\n cellCenter += .5;\n float dist = length(tileOffset + cellCenter - f_uv);\n if (dist < minDist) {\n minDist = dist;\n randomizer = rand;\n }\n }\n }\n\n return vec3(minDist, randomizer);\n}\n\nvoid main() {\n\n vec2 shape_uv = v_patternUV;\n shape_uv *= 1.5;\n\n const float firstFrameOffset = -10.;\n float t = u_time + firstFrameOffset;\n\n vec3 voronoi = voronoiShape(shape_uv, t) + 1e-4;\n\n float radius = .25 * clamp(u_size, 0., 1.) - .5 * clamp(u_sizeRange, 0., 1.) * voronoi[2];\n float dist = voronoi[0];\n float edgeWidth = fwidth(dist);\n float dots = 1. - smoothstep(radius - edgeWidth, radius + edgeWidth, dist);\n\n float shape = voronoi[1];\n\n float mixer = shape * (u_colorsCount - 1.);\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ dotOrbitMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0.0, 1.0);\n localT = round(localT * steps) / steps;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localT = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localT = mixer - (u_colorsCount - 1.);\n }\n localT = round(localT * steps) / steps;\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localT);\n }\n\n vec3 color = gradient.rgb * dots;\n float opacity = gradient.a * dots;\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 fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface DotOrbitUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_size: number;\n u_sizeRange: number;\n u_spreading: number;\n u_stepsPerColor: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface DotOrbitParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n size?: number;\n sizeRange?: number;\n spreading?: number;\n stepsPerColor?: number;\n}\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,WAAW,oBAAoB,2BAA2B;AAEvE,MAAM,eAAe;AAAA,EAC1B,eAAe;AACjB;AAoCO,MAAM,yBAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQrB,aAAa,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjD,SAAU;AAAA,EACV,SAAU;AAAA,EACV,kBAAmB;AAAA,EACnB,mBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAsDE,aAAa,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/fluted-glass.d.ts b/public/vendor/paper-shaders/shaders/fluted-glass.d.ts
new file mode 100644
index 0000000..18dc387
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/fluted-glass.d.ts
@@ -0,0 +1,114 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Fluted glass image filter that transforms an image into streaked, ribbed distortions,
+ * giving a mix of clarity and obscurity.
+ *
+ * Fragment shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_image (sampler2D): Source image texture
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorShadow (vec4): Shadows color in RGBA
+ * - u_colorHighlight (vec4): Highlights color in RGBA
+ * - u_shadows (float): Color gradient added over image and background, following distortion shape (0 to 1)
+ * - u_highlights (float): Thin strokes along distortion shape, useful for antialiasing on small grid (0 to 1)
+ * - u_size (float): Size of the distortion shape grid (0 to 1)
+ * - u_shape (float): Grid shape (1 = lines, 2 = linesIrregular, 3 = wave, 4 = zigzag, 5 = pattern)
+ * - u_angle (float): Direction of the grid relative to the image in degrees (0 to 180)
+ * - u_distortionShape (float): Shape of distortion (1 = prism, 2 = lens, 3 = contour, 4 = cascade, 5 = flat)
+ * - u_distortion (float): Power of distortion applied within each stripe (0 to 1)
+ * - u_shift (float): Texture shift in direction opposite to the grid (-1 to 1)
+ * - u_stretch (float): Extra distortion along the grid lines (0 to 1)
+ * - u_blur (float): One-directional blur over the image and extra blur around edges (0 to 1)
+ * - u_edges (float): Glass distortion and softness on the image edges (0 to 1)
+ * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1)
+ * - u_marginRight (float): Distance from the right edge to the effect (0 to 1)
+ * - u_marginTop (float): Distance from the top edge to the effect (0 to 1)
+ * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1)
+ * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)
+ * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const flutedGlassFragmentShader: string;
+export interface FlutedGlassUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string | undefined;
+ u_colorBack: [number, number, number, number];
+ u_colorShadow: [number, number, number, number];
+ u_colorHighlight: [number, number, number, number];
+ u_shadows: number;
+ u_size: number;
+ u_angle: number;
+ u_distortion: number;
+ u_shift: number;
+ u_blur: number;
+ u_edges: number;
+ u_marginLeft: number;
+ u_marginRight: number;
+ u_marginTop: number;
+ u_marginBottom: number;
+ u_stretch: number;
+ u_distortionShape: (typeof GlassDistortionShapes)[GlassDistortionShape];
+ u_highlights: number;
+ u_shape: (typeof GlassGridShapes)[GlassGridShape];
+ u_grainMixer: number;
+ u_grainOverlay: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface FlutedGlassParams extends ShaderSizingParams, ShaderMotionParams {
+ image?: HTMLImageElement | string;
+ colorBack?: string;
+ colorShadow?: string;
+ colorHighlight?: string;
+ shadows?: number;
+ size?: number;
+ angle?: number;
+ distortion?: number;
+ shift?: number;
+ blur?: number;
+ edges?: number;
+ margin?: number;
+ marginLeft?: number;
+ marginRight?: number;
+ marginTop?: number;
+ marginBottom?: number;
+ stretch?: number;
+ distortionShape?: GlassDistortionShape;
+ highlights?: number;
+ shape?: GlassGridShape;
+ grainMixer?: number;
+ grainOverlay?: number;
+}
+export declare const GlassGridShapes: {
+ readonly lines: 1;
+ readonly linesIrregular: 2;
+ readonly wave: 3;
+ readonly zigzag: 4;
+ readonly pattern: 5;
+};
+export declare const GlassDistortionShapes: {
+ readonly prism: 1;
+ readonly lens: 2;
+ readonly contour: 3;
+ readonly cascade: 4;
+ readonly flat: 5;
+};
+export type GlassDistortionShape = keyof typeof GlassDistortionShapes;
+export type GlassGridShape = keyof typeof GlassGridShapes;
diff --git a/public/vendor/paper-shaders/shaders/fluted-glass.js b/public/vendor/paper-shaders/shaders/fluted-glass.js
new file mode 100644
index 0000000..5f4a788
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/fluted-glass.js
@@ -0,0 +1,358 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
+const flutedGlassFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec2 u_resolution;
+uniform float u_pixelRatio;
+uniform float u_rotation;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorShadow;
+uniform vec4 u_colorHighlight;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform float u_size;
+uniform float u_shadows;
+uniform float u_angle;
+uniform float u_stretch;
+uniform float u_shape;
+uniform float u_distortion;
+uniform float u_highlights;
+uniform float u_distortionShape;
+uniform float u_shift;
+uniform float u_blur;
+uniform float u_edges;
+uniform float u_marginLeft;
+uniform float u_marginRight;
+uniform float u_marginTop;
+uniform float u_marginBottom;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+
+in vec2 v_imageUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${proceduralHash21}
+
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = hash21(i);
+ float b = hash21(i + vec2(1.0, 0.0));
+ float c = hash21(i + vec2(0.0, 1.0));
+ float d = hash21(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float getUvFrame(vec2 uv, float softness) {
+ float aax = 2. * fwidth(uv.x);
+ float aay = 2. * fwidth(uv.y);
+ float left = smoothstep(0., aax + softness, uv.x);
+ float right = 1. - smoothstep(1. - softness - aax, 1., uv.x);
+ float bottom = smoothstep(0., aay + softness, uv.y);
+ float top = 1. - smoothstep(1. - softness - aay, 1., uv.y);
+ return left * right * bottom * top;
+}
+
+const int MAX_RADIUS = 50;
+vec4 samplePremultiplied(sampler2D tex, vec2 uv) {
+ vec4 c = texture(tex, uv);
+ c.rgb *= c.a;
+ return c;
+}
+vec4 getBlur(sampler2D tex, vec2 uv, vec2 texelSize, vec2 dir, float sigma) {
+ if (sigma <= .5) return texture(tex, uv);
+ int radius = int(min(float(MAX_RADIUS), ceil(3.0 * sigma)));
+
+ float twoSigma2 = 2.0 * sigma * sigma;
+ float gaussianNorm = 1.0 / sqrt(TWO_PI * sigma * sigma);
+
+ vec4 sum = samplePremultiplied(tex, uv) * gaussianNorm;
+ float weightSum = gaussianNorm;
+
+ for (int i = 1; i <= MAX_RADIUS; i++) {
+ if (i > radius) break;
+
+ float x = float(i);
+ float w = exp(-(x * x) / twoSigma2) * gaussianNorm;
+
+ vec2 offset = dir * texelSize * x;
+ vec4 s1 = samplePremultiplied(tex, uv + offset);
+ vec4 s2 = samplePremultiplied(tex, uv - offset);
+
+ sum += (s1 + s2) * w;
+ weightSum += 2.0 * w;
+ }
+
+ vec4 result = sum / weightSum;
+ if (result.a > 0.) {
+ result.rgb /= result.a;
+ }
+
+ return result;
+}
+
+vec2 rotateAspect(vec2 p, float a, float aspect) {
+ p.x *= aspect;
+ p = rotate(p, a);
+ p.x /= aspect;
+ return p;
+}
+
+float smoothFract(float x) {
+ float f = fract(x);
+ float w = fwidth(x);
+
+ float edge = abs(f - 0.5) - 0.5;
+ float band = smoothstep(-w, w, edge);
+
+ return mix(f, 1.0 - f, band);
+}
+
+void main() {
+
+ float patternRotation = -u_angle * PI / 180.;
+ float patternSize = mix(200., 5., u_size);
+
+ vec2 uv = v_imageUV;
+
+ vec2 uvMask = gl_FragCoord.xy / u_resolution.xy;
+ vec2 sw = vec2(.005);
+ vec4 margins = vec4(u_marginLeft, u_marginTop, u_marginRight, u_marginBottom);
+ float mask =
+ smoothstep(margins[0], margins[0] + sw.x, uvMask.x + sw.x) *
+ smoothstep(margins[2], margins[2] + sw.x, 1.0 - uvMask.x + sw.x) *
+ smoothstep(margins[1], margins[1] + sw.y, uvMask.y + sw.y) *
+ smoothstep(margins[3], margins[3] + sw.y, 1.0 - uvMask.y + sw.y);
+ float maskOuter =
+ smoothstep(margins[0] - sw.x, margins[0], uvMask.x + sw.x) *
+ smoothstep(margins[2] - sw.x, margins[2], 1.0 - uvMask.x + sw.x) *
+ smoothstep(margins[1] - sw.y, margins[1], uvMask.y + sw.y) *
+ smoothstep(margins[3] - sw.y, margins[3], 1.0 - uvMask.y + sw.y);
+ float maskStroke = maskOuter - mask;
+ float maskInner =
+ smoothstep(margins[0] - 2. * sw.x, margins[0], uvMask.x) *
+ smoothstep(margins[2] - 2. * sw.x, margins[2], 1.0 - uvMask.x) *
+ smoothstep(margins[1] - 2. * sw.y, margins[1], uvMask.y) *
+ smoothstep(margins[3] - 2. * sw.y, margins[3], 1.0 - uvMask.y);
+ float maskStrokeInner = maskInner - mask;
+
+ uv -= .5;
+ uv *= patternSize;
+ uv = rotateAspect(uv, patternRotation, u_imageAspectRatio);
+
+ float curve = 0.;
+ float patternY = uv.y / u_imageAspectRatio;
+ if (u_shape > 4.5) {
+ // pattern
+ curve = .5 + .5 * sin(.5 * PI * uv.x) * cos(.5 * PI * patternY);
+ } else if (u_shape > 3.5) {
+ // zigzag
+ curve = 10. * abs(fract(.1 * patternY) - .5);
+ } else if (u_shape > 2.5) {
+ // wave
+ curve = 4. * sin(.23 * patternY);
+ } else if (u_shape > 1.5) {
+ // lines irregular
+ curve = .5 + .5 * sin(.5 * uv.x) * sin(1.7 * uv.x);
+ } else {
+ // lines
+ }
+
+ vec2 UvToFract = uv + curve;
+ vec2 fractOrigUV = fract(uv);
+ vec2 floorOrigUV = floor(uv);
+
+ float x = smoothFract(UvToFract.x);
+ float xNonSmooth = fract(UvToFract.x) + .0001;
+
+ float highlightsWidth = 2. * max(.001, fwidth(UvToFract.x));
+ highlightsWidth += 2. * maskStrokeInner;
+ float highlights = smoothstep(0., highlightsWidth, xNonSmooth);
+ highlights *= smoothstep(1., 1. - highlightsWidth, xNonSmooth);
+ highlights = 1. - highlights;
+ highlights *= u_highlights;
+ highlights = clamp(highlights, 0., 1.);
+ highlights *= mask;
+
+ float shadows = pow(x, 1.3);
+ float distortion = 0.;
+ float fadeX = 1.;
+ float frameFade = 0.;
+
+ float aa = fwidth(xNonSmooth);
+ aa = max(aa, fwidth(uv.x));
+ aa = max(aa, fwidth(UvToFract.x));
+ aa = max(aa, .0001);
+
+ if (u_distortionShape == 1.) {
+ distortion = -pow(1.5 * x, 3.);
+ distortion += (.5 - u_shift);
+
+ frameFade = pow(1.5 * x, 3.);
+ aa = max(.2, aa);
+ aa += mix(.2, 0., u_size);
+ fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);
+ distortion = mix(.5, distortion, fadeX);
+ } else if (u_distortionShape == 2.) {
+ distortion = 2. * pow(x, 2.);
+ distortion -= (.5 + u_shift);
+
+ frameFade = pow(abs(x - .5), 4.);
+ aa = max(.2, aa);
+ aa += mix(.2, 0., u_size);
+ fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);
+ distortion = mix(.5, distortion, fadeX);
+ frameFade = mix(1., frameFade, .5 * fadeX);
+ } else if (u_distortionShape == 3.) {
+ distortion = pow(2. * (xNonSmooth - .5), 6.);
+ distortion -= .25;
+ distortion -= u_shift;
+
+ frameFade = 1. - 2. * pow(abs(x - .4), 2.);
+ aa = .15;
+ aa += mix(.1, 0., u_size);
+ fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);
+ frameFade = mix(1., frameFade, fadeX);
+
+ } else if (u_distortionShape == 4.) {
+ x = xNonSmooth;
+ distortion = sin((x + .25) * TWO_PI);
+ shadows = .5 + .5 * asin(distortion) / (.5 * PI);
+ distortion *= .5;
+ distortion -= u_shift;
+ frameFade = .5 + .5 * sin(x * TWO_PI);
+ } else if (u_distortionShape == 5.) {
+ distortion -= pow(abs(x), .2) * x;
+ distortion += .33;
+ distortion -= 3. * u_shift;
+ distortion *= .33;
+
+ frameFade = .3 * (smoothstep(.0, 1., x));
+ shadows = pow(x, 2.5);
+
+ aa = max(.1, aa);
+ aa += mix(.1, 0., u_size);
+ fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);
+ distortion *= fadeX;
+ }
+
+ vec2 dudx = dFdx(v_imageUV);
+ vec2 dudy = dFdy(v_imageUV);
+ vec2 grainUV = v_imageUV - .5;
+ grainUV *= (.8 / vec2(length(dudx), length(dudy)));
+ grainUV += .5;
+ float grain = valueNoise(grainUV);
+ grain = smoothstep(.4, .7, grain);
+ grain *= u_grainMixer;
+ distortion = mix(distortion, 0., grain);
+
+ shadows = min(shadows, 1.);
+ shadows += maskStrokeInner;
+ shadows *= mask;
+ shadows = min(shadows, 1.);
+ shadows *= pow(u_shadows, 2.);
+ shadows = clamp(shadows, 0., 1.);
+
+ distortion *= 3. * u_distortion;
+ frameFade *= u_distortion;
+
+ fractOrigUV.x += distortion;
+ floorOrigUV = rotateAspect(floorOrigUV, -patternRotation, u_imageAspectRatio);
+ fractOrigUV = rotateAspect(fractOrigUV, -patternRotation, u_imageAspectRatio);
+
+ uv = (floorOrigUV + fractOrigUV) / patternSize;
+ uv += pow(maskStroke, 4.);
+
+ uv += vec2(.5);
+
+ uv = mix(v_imageUV, uv, smoothstep(0., .7, mask));
+ float blur = mix(0., 50., u_blur);
+ blur = mix(0., blur, smoothstep(.5, 1., mask));
+
+ float edgeDistortion = mix(.0, .04, u_edges);
+ edgeDistortion += .06 * frameFade * u_edges;
+ edgeDistortion *= mask;
+ float frame = getUvFrame(uv, edgeDistortion);
+
+ float stretch = 1. - smoothstep(0., .5, xNonSmooth) * smoothstep(1., 1. - .5, xNonSmooth);
+ stretch = pow(stretch, 2.);
+ stretch *= mask;
+ stretch *= getUvFrame(uv, .1 + .05 * mask * frameFade);
+ uv.y = mix(uv.y, .5, u_stretch * stretch);
+
+ vec4 image = getBlur(u_image, uv, 1. / u_resolution / u_pixelRatio, vec2(0., 1.), blur);
+ image.rgb *= image.a;
+ vec4 backColor = u_colorBack;
+ backColor.rgb *= backColor.a;
+ vec4 highlightColor = u_colorHighlight;
+ highlightColor.rgb *= highlightColor.a;
+ vec4 shadowColor = u_colorShadow;
+
+ vec3 color = highlightColor.rgb * highlights;
+ float opacity = highlightColor.a * highlights;
+
+ shadows = mix(shadows * shadowColor.a, 0., highlights);
+ color = mix(color, shadowColor.rgb * shadowColor.a, .5 * shadows);
+ color += .5 * pow(shadows, .5) * shadowColor.rgb;
+ opacity += shadows;
+ color = clamp(color, vec3(0.), vec3(1.));
+ opacity = clamp(opacity, 0., 1.);
+
+ color += image.rgb * (1. - opacity) * frame;
+ opacity += image.a * (1. - opacity) * frame;
+
+ color += backColor.rgb * (1. - opacity);
+ opacity += backColor.a * (1. - opacity);
+
+ float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));
+ grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
+ grainOverlay = pow(grainOverlay, 1.3);
+
+ float grainOverlayV = grainOverlay * 2. - 1.;
+ vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
+ float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
+ grainOverlayStrength = pow(grainOverlayStrength, .8);
+ grainOverlayStrength *= mask;
+ color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);
+
+ opacity += .5 * grainOverlayStrength;
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const GlassGridShapes = {
+ lines: 1,
+ linesIrregular: 2,
+ wave: 3,
+ zigzag: 4,
+ pattern: 5
+};
+const GlassDistortionShapes = {
+ prism: 1,
+ lens: 2,
+ contour: 3,
+ cascade: 4,
+ flat: 5
+};
+export {
+ GlassDistortionShapes,
+ GlassGridShapes,
+ flutedGlassFragmentShader
+};
+//# sourceMappingURL=fluted-glass.js.map
diff --git a/public/vendor/paper-shaders/shaders/fluted-glass.js.map b/public/vendor/paper-shaders/shaders/fluted-glass.js.map
new file mode 100644
index 0000000..888b1ca
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/fluted-glass.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/fluted-glass.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Fluted glass image filter that transforms an image into streaked, ribbed distortions,\n * giving a mix of clarity and obscurity.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorShadow (vec4): Shadows color in RGBA\n * - u_colorHighlight (vec4): Highlights color in RGBA\n * - u_shadows (float): Color gradient added over image and background, following distortion shape (0 to 1)\n * - u_highlights (float): Thin strokes along distortion shape, useful for antialiasing on small grid (0 to 1)\n * - u_size (float): Size of the distortion shape grid (0 to 1)\n * - u_shape (float): Grid shape (1 = lines, 2 = linesIrregular, 3 = wave, 4 = zigzag, 5 = pattern)\n * - u_angle (float): Direction of the grid relative to the image in degrees (0 to 180)\n * - u_distortionShape (float): Shape of distortion (1 = prism, 2 = lens, 3 = contour, 4 = cascade, 5 = flat)\n * - u_distortion (float): Power of distortion applied within each stripe (0 to 1)\n * - u_shift (float): Texture shift in direction opposite to the grid (-1 to 1)\n * - u_stretch (float): Extra distortion along the grid lines (0 to 1)\n * - u_blur (float): One-directional blur over the image and extra blur around edges (0 to 1)\n * - u_edges (float): Glass distortion and softness on the image edges (0 to 1)\n * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1)\n * - u_marginRight (float): Distance from the right edge to the effect (0 to 1)\n * - u_marginTop (float): Distance from the top edge to the effect (0 to 1)\n * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const flutedGlassFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_rotation;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorShadow;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_size;\nuniform float u_shadows;\nuniform float u_angle;\nuniform float u_stretch;\nuniform float u_shape;\nuniform float u_distortion;\nuniform float u_highlights;\nuniform float u_distortionShape;\nuniform float u_shift;\nuniform float u_blur;\nuniform float u_edges;\nuniform float u_marginLeft;\nuniform float u_marginRight;\nuniform float u_marginTop;\nuniform float u_marginBottom;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(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 getUvFrame(vec2 uv, float softness) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n float left = smoothstep(0., aax + softness, uv.x);\n float right = 1. - smoothstep(1. - softness - aax, 1., uv.x);\n float bottom = smoothstep(0., aay + softness, uv.y);\n float top = 1. - smoothstep(1. - softness - aay, 1., uv.y);\n return left * right * bottom * top;\n}\n\nconst int MAX_RADIUS = 50;\nvec4 samplePremultiplied(sampler2D tex, vec2 uv) {\n vec4 c = texture(tex, uv);\n c.rgb *= c.a;\n return c;\n}\nvec4 getBlur(sampler2D tex, vec2 uv, vec2 texelSize, vec2 dir, float sigma) {\n if (sigma <= .5) return texture(tex, uv);\n int radius = int(min(float(MAX_RADIUS), ceil(3.0 * sigma)));\n\n float twoSigma2 = 2.0 * sigma * sigma;\n float gaussianNorm = 1.0 / sqrt(TWO_PI * sigma * sigma);\n\n vec4 sum = samplePremultiplied(tex, uv) * gaussianNorm;\n float weightSum = gaussianNorm;\n\n for (int i = 1; i <= MAX_RADIUS; i++) {\n if (i > radius) break;\n\n float x = float(i);\n float w = exp(-(x * x) / twoSigma2) * gaussianNorm;\n\n vec2 offset = dir * texelSize * x;\n vec4 s1 = samplePremultiplied(tex, uv + offset);\n vec4 s2 = samplePremultiplied(tex, uv - offset);\n\n sum += (s1 + s2) * w;\n weightSum += 2.0 * w;\n }\n\n vec4 result = sum / weightSum;\n if (result.a > 0.) {\n result.rgb /= result.a;\n }\n\n return result;\n}\n\nvec2 rotateAspect(vec2 p, float a, float aspect) {\n p.x *= aspect;\n p = rotate(p, a);\n p.x /= aspect;\n return p;\n}\n\nfloat smoothFract(float x) {\n float f = fract(x);\n float w = fwidth(x);\n\n float edge = abs(f - 0.5) - 0.5;\n float band = smoothstep(-w, w, edge);\n\n return mix(f, 1.0 - f, band);\n}\n\nvoid main() {\n\n float patternRotation = -u_angle * PI / 180.;\n float patternSize = mix(200., 5., u_size);\n\n vec2 uv = v_imageUV;\n\n vec2 uvMask = gl_FragCoord.xy / u_resolution.xy;\n vec2 sw = vec2(.005);\n vec4 margins = vec4(u_marginLeft, u_marginTop, u_marginRight, u_marginBottom);\n float mask =\n smoothstep(margins[0], margins[0] + sw.x, uvMask.x + sw.x) *\n smoothstep(margins[2], margins[2] + sw.x, 1.0 - uvMask.x + sw.x) *\n smoothstep(margins[1], margins[1] + sw.y, uvMask.y + sw.y) *\n smoothstep(margins[3], margins[3] + sw.y, 1.0 - uvMask.y + sw.y);\n float maskOuter =\n smoothstep(margins[0] - sw.x, margins[0], uvMask.x + sw.x) *\n smoothstep(margins[2] - sw.x, margins[2], 1.0 - uvMask.x + sw.x) *\n smoothstep(margins[1] - sw.y, margins[1], uvMask.y + sw.y) *\n smoothstep(margins[3] - sw.y, margins[3], 1.0 - uvMask.y + sw.y);\n float maskStroke = maskOuter - mask;\n float maskInner =\n smoothstep(margins[0] - 2. * sw.x, margins[0], uvMask.x) *\n smoothstep(margins[2] - 2. * sw.x, margins[2], 1.0 - uvMask.x) *\n smoothstep(margins[1] - 2. * sw.y, margins[1], uvMask.y) *\n smoothstep(margins[3] - 2. * sw.y, margins[3], 1.0 - uvMask.y);\n float maskStrokeInner = maskInner - mask;\n\n uv -= .5;\n uv *= patternSize;\n uv = rotateAspect(uv, patternRotation, u_imageAspectRatio);\n\n float curve = 0.;\n float patternY = uv.y / u_imageAspectRatio;\n if (u_shape > 4.5) {\n // pattern\n curve = .5 + .5 * sin(.5 * PI * uv.x) * cos(.5 * PI * patternY);\n } else if (u_shape > 3.5) {\n // zigzag\n curve = 10. * abs(fract(.1 * patternY) - .5);\n } else if (u_shape > 2.5) {\n // wave\n curve = 4. * sin(.23 * patternY);\n } else if (u_shape > 1.5) {\n // lines irregular\n curve = .5 + .5 * sin(.5 * uv.x) * sin(1.7 * uv.x);\n } else {\n // lines\n }\n\n vec2 UvToFract = uv + curve;\n vec2 fractOrigUV = fract(uv);\n vec2 floorOrigUV = floor(uv);\n\n float x = smoothFract(UvToFract.x);\n float xNonSmooth = fract(UvToFract.x) + .0001;\n\n float highlightsWidth = 2. * max(.001, fwidth(UvToFract.x));\n highlightsWidth += 2. * maskStrokeInner;\n float highlights = smoothstep(0., highlightsWidth, xNonSmooth);\n highlights *= smoothstep(1., 1. - highlightsWidth, xNonSmooth);\n highlights = 1. - highlights;\n highlights *= u_highlights;\n highlights = clamp(highlights, 0., 1.);\n highlights *= mask;\n\n float shadows = pow(x, 1.3);\n float distortion = 0.;\n float fadeX = 1.;\n float frameFade = 0.;\n\n float aa = fwidth(xNonSmooth);\n aa = max(aa, fwidth(uv.x));\n aa = max(aa, fwidth(UvToFract.x));\n aa = max(aa, .0001);\n\n if (u_distortionShape == 1.) {\n distortion = -pow(1.5 * x, 3.);\n distortion += (.5 - u_shift);\n\n frameFade = pow(1.5 * x, 3.);\n aa = max(.2, aa);\n aa += mix(.2, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n distortion = mix(.5, distortion, fadeX);\n } else if (u_distortionShape == 2.) {\n distortion = 2. * pow(x, 2.);\n distortion -= (.5 + u_shift);\n\n frameFade = pow(abs(x - .5), 4.);\n aa = max(.2, aa);\n aa += mix(.2, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n distortion = mix(.5, distortion, fadeX);\n frameFade = mix(1., frameFade, .5 * fadeX);\n } else if (u_distortionShape == 3.) {\n distortion = pow(2. * (xNonSmooth - .5), 6.);\n distortion -= .25;\n distortion -= u_shift;\n\n frameFade = 1. - 2. * pow(abs(x - .4), 2.);\n aa = .15;\n aa += mix(.1, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n frameFade = mix(1., frameFade, fadeX);\n\n } else if (u_distortionShape == 4.) {\n x = xNonSmooth;\n distortion = sin((x + .25) * TWO_PI);\n shadows = .5 + .5 * asin(distortion) / (.5 * PI);\n distortion *= .5;\n distortion -= u_shift;\n frameFade = .5 + .5 * sin(x * TWO_PI);\n } else if (u_distortionShape == 5.) {\n distortion -= pow(abs(x), .2) * x;\n distortion += .33;\n distortion -= 3. * u_shift;\n distortion *= .33;\n\n frameFade = .3 * (smoothstep(.0, 1., x));\n shadows = pow(x, 2.5);\n\n aa = max(.1, aa);\n aa += mix(.1, 0., u_size);\n fadeX = smoothstep(0., aa, xNonSmooth) * smoothstep(1., 1. - aa, xNonSmooth);\n distortion *= fadeX;\n }\n\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n vec2 grainUV = v_imageUV - .5;\n grainUV *= (.8 / vec2(length(dudx), length(dudy)));\n grainUV += .5;\n float grain = valueNoise(grainUV);\n grain = smoothstep(.4, .7, grain);\n grain *= u_grainMixer;\n distortion = mix(distortion, 0., grain);\n\n shadows = min(shadows, 1.);\n shadows += maskStrokeInner;\n shadows *= mask;\n shadows = min(shadows, 1.);\n shadows *= pow(u_shadows, 2.);\n shadows = clamp(shadows, 0., 1.);\n\n distortion *= 3. * u_distortion;\n frameFade *= u_distortion;\n\n fractOrigUV.x += distortion;\n floorOrigUV = rotateAspect(floorOrigUV, -patternRotation, u_imageAspectRatio);\n fractOrigUV = rotateAspect(fractOrigUV, -patternRotation, u_imageAspectRatio);\n\n uv = (floorOrigUV + fractOrigUV) / patternSize;\n uv += pow(maskStroke, 4.);\n\n uv += vec2(.5);\n\n uv = mix(v_imageUV, uv, smoothstep(0., .7, mask));\n float blur = mix(0., 50., u_blur);\n blur = mix(0., blur, smoothstep(.5, 1., mask));\n\n float edgeDistortion = mix(.0, .04, u_edges);\n edgeDistortion += .06 * frameFade * u_edges;\n edgeDistortion *= mask;\n float frame = getUvFrame(uv, edgeDistortion);\n\n float stretch = 1. - smoothstep(0., .5, xNonSmooth) * smoothstep(1., 1. - .5, xNonSmooth);\n stretch = pow(stretch, 2.);\n stretch *= mask;\n stretch *= getUvFrame(uv, .1 + .05 * mask * frameFade);\n uv.y = mix(uv.y, .5, u_stretch * stretch);\n\n vec4 image = getBlur(u_image, uv, 1. / u_resolution / u_pixelRatio, vec2(0., 1.), blur);\n image.rgb *= image.a;\n vec4 backColor = u_colorBack;\n backColor.rgb *= backColor.a;\n vec4 highlightColor = u_colorHighlight;\n highlightColor.rgb *= highlightColor.a;\n vec4 shadowColor = u_colorShadow;\n\n vec3 color = highlightColor.rgb * highlights;\n float opacity = highlightColor.a * highlights;\n\n shadows = mix(shadows * shadowColor.a, 0., highlights);\n color = mix(color, shadowColor.rgb * shadowColor.a, .5 * shadows);\n color += .5 * pow(shadows, .5) * shadowColor.rgb;\n opacity += shadows;\n color = clamp(color, vec3(0.), vec3(1.));\n opacity = clamp(opacity, 0., 1.);\n\n color += image.rgb * (1. - opacity) * frame;\n opacity += image.a * (1. - opacity) * frame;\n\n color += backColor.rgb * (1. - opacity);\n opacity += backColor.a * (1. - opacity);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n grainOverlayStrength *= mask;\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface FlutedGlassUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorBack: [number, number, number, number];\n u_colorShadow: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_shadows: number;\n u_size: number;\n u_angle: number;\n u_distortion: number;\n u_shift: number;\n u_blur: number;\n u_edges: number;\n u_marginLeft: number;\n u_marginRight: number;\n u_marginTop: number;\n u_marginBottom: number;\n u_stretch: number;\n u_distortionShape: (typeof GlassDistortionShapes)[GlassDistortionShape];\n u_highlights: number;\n u_shape: (typeof GlassGridShapes)[GlassGridShape];\n u_grainMixer: number;\n u_grainOverlay: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface FlutedGlassParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorShadow?: string;\n colorHighlight?: string;\n shadows?: number;\n size?: number;\n angle?: number;\n distortion?: number;\n shift?: number;\n blur?: number;\n edges?: number;\n margin?: number;\n marginLeft?: number;\n marginRight?: number;\n marginTop?: number;\n marginBottom?: number;\n stretch?: number;\n distortionShape?: GlassDistortionShape;\n highlights?: number;\n shape?: GlassGridShape;\n grainMixer?: number;\n grainOverlay?: number;\n}\n\nexport const GlassGridShapes = {\n lines: 1,\n linesIrregular: 2,\n wave: 3,\n zigzag: 4,\n pattern: 5,\n} as const;\n\nexport const GlassDistortionShapes = {\n prism: 1,\n lens: 2,\n contour: 3,\n cascade: 4,\n flat: 5,\n} as const;\n\nexport type GlassDistortionShape = keyof typeof GlassDistortionShapes;\nexport type GlassGridShape = keyof typeof GlassGridShapes;\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,wBAAwB;AAmDhD,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoC9C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwVb,MAAM,kBAAkB;AAAA,EAC7B,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,MAAM,wBAAwB;AAAA,EACnC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AACR;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/gem-smoke.d.ts b/public/vendor/paper-shaders/shaders/gem-smoke.d.ts
new file mode 100644
index 0000000..eaca83e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/gem-smoke.d.ts
@@ -0,0 +1,94 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const gemSmokeMeta: {
+ readonly maxColorCount: 6;
+};
+/**
+ * Animated color fields placed over uploaded logo shape; gives the illusion of smoky noise
+ * behind the glassy shape.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = alpha)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colors (vec4[]): Up to 6 smoke colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_innerDistortion (float): Power of smoke distortion inside the input shape (0 to 1)
+ * - u_outerDistortion (float): Power of smoke distortion outside the input shape (0 to 1)
+ * - u_outerGlow (float): Visibility of smoke shape outside the input shape (0 to 1)
+ * - u_innerGlow (float): Visibility of smoke shape inside the input shape (0 to 1)
+ * - u_colorInner (vec4): Additional color inside the input shape, mixing with smoke (RGBA)
+ * - u_offset (float): Vertical offset of smoke inside the shape (-1 to 1)
+ * - u_angle (float): Smoke direction in degrees (0 to 360)
+ * - u_size (float): Size of smoke shape relative to the image box (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
+ * - v_objectUV (vec2): Normalized UV coordinates with scale, rotation, and offset applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const gemSmokeFragmentShader: string;
+export declare const POISSON_CONFIG_OPTIMIZED: {
+ measurePerformance: boolean;
+ workingSize: number;
+ iterations: number;
+};
+export declare function toProcessedGemSmoke(file: File | string): Promise<{
+ imageData: ImageData;
+ pngBlob: Blob;
+}>;
+export interface GemSmokeUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_image: HTMLImageElement | string | undefined;
+ u_innerDistortion: number;
+ u_outerDistortion: number;
+ u_outerGlow: number;
+ u_innerGlow: number;
+ u_colorInner: [number, number, number, number];
+ u_offset: number;
+ u_angle: number;
+ u_size: number;
+ u_shape: (typeof GemSmokeShapes)[GemSmokeShape];
+ u_isImage: boolean;
+}
+export interface GemSmokeParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ colorBack?: string;
+ image?: HTMLImageElement | string | undefined;
+ innerDistortion?: number;
+ outerDistortion?: number;
+ outerGlow?: number;
+ innerGlow?: number;
+ colorInner?: string;
+ offset?: number;
+ angle?: number;
+ size?: number;
+ shape?: GemSmokeShape;
+}
+export declare const GemSmokeShapes: {
+ readonly none: 0;
+ readonly circle: 1;
+ readonly daisy: 2;
+ readonly diamond: 3;
+ readonly metaballs: 4;
+};
+export type GemSmokeShape = keyof typeof GemSmokeShapes;
diff --git a/public/vendor/paper-shaders/shaders/gem-smoke.js b/public/vendor/paper-shaders/shaders/gem-smoke.js
new file mode 100644
index 0000000..327958c
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/gem-smoke.js
@@ -0,0 +1,585 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import { rotation2, declarePI } from "../shader-utils.js";
+const gemSmokeMeta = {
+ maxColorCount: 6
+};
+const gemSmokeFragmentShader = `#version 300 es
+precision mediump float;
+
+in mediump vec2 v_imageUV;
+in mediump vec2 v_objectUV;
+in mediump vec2 v_responsiveUV;
+in mediump vec2 v_responsiveBoxGivenSize;
+out vec4 fragColor;
+
+// Image
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+// Canvas
+uniform vec2 u_resolution;
+uniform float u_time;
+
+// Colors
+uniform vec4 u_colors[${gemSmokeMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform vec4 u_colorBack;
+uniform vec4 u_colorInner;
+
+// Effect controls
+uniform float u_innerDistortion;
+uniform float u_outerDistortion;
+uniform float u_outerGlow;
+uniform float u_innerGlow;
+uniform float u_offset;
+uniform float u_angle;
+uniform float u_size;
+
+// Shape controls
+uniform float u_shape;
+uniform bool u_isImage;
+
+${declarePI}
+${rotation2}
+
+// 9x9 Gaussian blur on R and G channels
+vec2 gaussBlur9x9RG(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius) {
+ vec2 texel = 1.0 / vec2(textureSize(tex, 0));
+ vec2 r = max(radius, 0.0) * texel;
+ // Pascal's row 8: sum = 256, 2D norm = 65536
+ const float k[9] = float[9](1.0, 8.0, 28.0, 56.0, 70.0, 56.0, 28.0, 8.0, 1.0);
+ vec2 sum = vec2(0.0);
+
+ for (int j = -4; j <= 4; ++j) {
+ float wy = k[j + 4];
+ for (int i = -4; i <= 4; ++i) {
+ float w = k[i + 4] * wy;
+ vec2 off = vec2(float(i) * r.x, float(j) * r.y);
+ sum += w * texture(tex, uv + off).rg;
+ }
+ }
+
+ return sum / 65536.0;
+}
+
+float sst(float a, float b, float x) {
+ return smoothstep(a, b, x);
+}
+
+void main() {
+ float time = u_time;
+
+ float roundness = 0.;
+ float imgAlpha = 0.;
+
+ if (u_isImage == true) {
+ // Image sampling (UV scaled inward to account for padding)
+ vec2 imageUV = v_imageUV;
+ imageUV -= .5;
+ imageUV *= .95;
+ imageUV += .5;
+
+ vec2 dudx = dFdx(v_imageUV);
+ vec2 dudy = dFdy(v_imageUV);
+
+ // Blurred image: x = roundness, y = alpha
+ vec2 blurred = gaussBlur9x9RG(u_image, imageUV, dudx, dudy, 10.);
+ roundness = 1. - blurred.x;
+ vec2 texelA = 1.0 / vec2(textureSize(u_image, 0));
+ const float k3[3] = float[3](1.0, 2.0, 1.0);
+ for (int j = -1; j <= 1; ++j) {
+ for (int i = -1; i <= 1; ++i) {
+ imgAlpha += k3[i + 1] * k3[j + 1] * texture(u_image, imageUV + vec2(float(i) * texelA.x, float(j) * texelA.y)).g;
+ }
+ }
+ imgAlpha /= 16.0;
+ } else {
+ vec2 uv = v_objectUV + .5;
+ uv.y = 1. - uv.y;
+ float edge = 0.;
+
+ if (u_shape < 1.) {
+ // full-fill on canvas
+ vec2 borderUV = v_responsiveUV + .5;
+ vec2 mask = min(borderUV, 1. - borderUV);
+ vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));
+ float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
+ float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
+ maskX = pow(maskX, .25);
+ maskY = pow(maskY, .25);
+ edge = clamp(1. - maskX * maskY, 0., 1.);
+ } else if (u_shape < 2.) {
+ // circle
+ vec2 shapeUV = uv - .5;
+ shapeUV *= .67;
+ edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);
+ } else if (u_shape < 3.) {
+ // daisy
+ vec2 shapeUV = uv - .5;
+ shapeUV *= 1.68;
+
+ float r = length(shapeUV) * 2.;
+ float a = atan(shapeUV.y, shapeUV.x) + .2;
+ r *= (1. + .05 * sin(3. * a + 2. * time));
+ float f = abs(cos(a * 3.));
+ edge = smoothstep(f, f + .7, r);
+ edge *= edge;
+ } else if (u_shape < 4.) {
+ // diamond
+ vec2 shapeUV = uv - .5;
+ shapeUV = rotate(shapeUV, .25 * PI);
+ shapeUV *= 1.42;
+ shapeUV += .5;
+ vec2 mask = min(shapeUV, 1. - shapeUV);
+ vec2 pixel_thickness = vec2(.15);
+ float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
+ float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
+ maskX = pow(maskX, .25);
+ maskY = pow(maskY, .25);
+ edge = clamp(1. - maskX * maskY, 0., 1.);
+ } else if (u_shape < 5.) {
+ // metaballs
+ vec2 shapeUV = uv - .5;
+ shapeUV *= 1.3;
+ edge = 0.;
+ for (int i = 0; i < 5; i++) {
+ float fi = float(i);
+ float speed = 1.5 + 2./3. * sin(fi * 12.345);
+ float angle = -fi * 1.5;
+ vec2 dir1 = vec2(cos(angle), sin(angle));
+ vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));
+ vec2 traj = .4 * (dir1 * sin(time * speed + fi * 1.23) + dir2 * cos(time * (speed * 0.7) + fi * 2.17));
+ float d = length(shapeUV + traj);
+ edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);
+ }
+ edge = 1. - smoothstep(.65, .9, edge);
+ edge = pow(edge, 4.);
+ }
+
+ imgAlpha = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);
+ roundness = 1. - edge;
+ }
+
+// Smoke UV setup
+ vec2 smokeUV = v_objectUV;
+ smokeUV = rotate(smokeUV, u_angle * PI / 180.);
+ smokeUV *= mix(4., 1., u_size);
+
+ // Two swirl paths: inner (shape-masked) and outer (free), each with independent distortion
+ vec2 innerUV = smokeUV;
+ vec2 outerUV = smokeUV;
+
+ // Vertical displacement \u2014 applied independently to inner and outer
+ innerUV.y += u_innerDistortion * (1. - sst(0., 1., length(.4 * innerUV)));
+ innerUV.y -= .4 * u_innerDistortion;
+ innerUV.y += .7 * u_offset * roundness;
+
+ outerUV.y += u_outerDistortion * (1. - sst(0., 1., length(.4 * outerUV)));
+ outerUV.y -= .4 * u_outerDistortion;
+
+ float innerSwirl = u_innerDistortion * roundness;
+ float outerSwirl = u_outerDistortion;
+
+ for (int i = 1; i < 5; i++) {
+ float fi = float(i);
+
+ float stretchIn = max(length(dFdx(innerUV)), length(dFdy(innerUV)));
+ float dampenIn = 1. / (1. + stretchIn * 8.);
+ float sIn = innerSwirl * dampenIn;
+ innerUV.x += sIn / fi * cos(time + fi * 2.9 * innerUV.y);
+ innerUV.y += sIn / fi * cos(time + fi * 1.5 * innerUV.x);
+
+ float stretchOut = max(length(dFdx(outerUV)), length(dFdy(outerUV)));
+ float dampenOut = 1. / (1. + stretchOut * 8.);
+ float sOut = outerSwirl * dampenOut;
+ outerUV.x += sOut / fi * cos(time + fi * 2.9 * outerUV.y);
+ outerUV.y += sOut / fi * cos(time + fi * 1.5 * outerUV.x);
+ }
+
+ // Smoke shapes from swirl fields
+ float innerShape = exp(-1.5 * dot(innerUV, innerUV));
+ float outerShape = exp(-1.5 * dot(outerUV, outerUV));
+
+ // Visibility masks
+ float outerMask = pow(u_outerGlow, 2.) * (1. - imgAlpha);
+ float innerMask = (.01 + .99 * u_innerGlow) * imgAlpha;
+
+ innerShape *= innerMask;
+ outerShape *= outerMask;
+
+ // Color gradient
+ float mixer = (innerShape + outerShape) * u_colorsCount;
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+
+ float smokeMask = 0.;
+ for (int i = 1; i < ${gemSmokeMeta.maxColorCount + 1}; i++) {
+ if (i > int(u_colorsCount)) break;
+
+ float m = sst(0., 1., clamp(mixer - float(i - 1), 0., 1.));
+ if (i == 1) smokeMask = m;
+
+ vec4 c = u_colors[i - 1];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, m);
+ }
+
+ // Compositing (premultiplied alpha, front-to-back)
+ vec3 color = gradient.rgb * smokeMask;
+ float opacity = gradient.a * smokeMask;
+
+ float innerOpacity = u_colorInner.a * imgAlpha;
+ vec3 innerColor = u_colorInner.rgb * innerOpacity;
+ color += innerColor * (1.0 - opacity);
+ opacity += innerOpacity * (1.0 - opacity);
+
+ vec3 backColor = u_colorBack.rgb * u_colorBack.a;
+ color += backColor * (1.0 - opacity);
+ opacity += u_colorBack.a * (1.0 - opacity);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const POISSON_CONFIG_OPTIMIZED = {
+ measurePerformance: false,
+ // Set to true to see performance metrics
+ workingSize: 512,
+ // Size to solve Poisson at (will upscale to original size)
+ iterations: 32
+ // SOR converges ~2-20x faster than standard Gauss-Seidel
+};
+function toProcessedGemSmoke(file) {
+ const canvas = document.createElement("canvas");
+ const ctx = canvas.getContext("2d");
+ const isBlob = typeof file === "string" && file.startsWith("blob:");
+ return new Promise((resolve, reject) => {
+ if (!file || !ctx) {
+ reject(new Error("Invalid file or canvas context"));
+ return;
+ }
+ const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get("Content-Type"));
+ const img = new Image();
+ img.crossOrigin = "anonymous";
+ const totalStartTime = performance.now();
+ img.onload = async () => {
+ let isSVG;
+ const blobContentType = await blobContentTypePromise;
+ if (blobContentType) {
+ isSVG = blobContentType === "image/svg+xml";
+ } else if (typeof file === "string") {
+ isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml");
+ } else {
+ isSVG = file.type === "image/svg+xml";
+ }
+ let originalWidth = img.width || img.naturalWidth;
+ let originalHeight = img.height || img.naturalHeight;
+ if (isSVG) {
+ const svgMaxSize = 4096;
+ const aspectRatio = originalWidth / originalHeight;
+ if (originalWidth > originalHeight) {
+ originalWidth = svgMaxSize;
+ originalHeight = svgMaxSize / aspectRatio;
+ } else {
+ originalHeight = svgMaxSize;
+ originalWidth = svgMaxSize * aspectRatio;
+ }
+ img.width = originalWidth;
+ img.height = originalHeight;
+ }
+ const minDimension = Math.min(originalWidth, originalHeight);
+ const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;
+ const scaleFactor = targetSize / minDimension;
+ const width = Math.round(originalWidth * scaleFactor);
+ const height = Math.round(originalHeight * scaleFactor);
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ console.log(`[Processing Mode]`);
+ console.log(` Original: ${originalWidth}\xD7${originalHeight}`);
+ console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);
+ if (scaleFactor < 1) {
+ console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`);
+ }
+ }
+ canvas.width = originalWidth;
+ canvas.height = originalHeight;
+ const paddingSize = 0.025;
+ const padX = Math.ceil(width * paddingSize);
+ const padY = Math.ceil(height * paddingSize);
+ const imgW = width - 2 * padX;
+ const imgH = height - 2 * padY;
+ const shapeCanvas = document.createElement("canvas");
+ shapeCanvas.width = width;
+ shapeCanvas.height = height;
+ const shapeCtx = shapeCanvas.getContext("2d");
+ shapeCtx.drawImage(img, padX, padY, imgW, imgH);
+ const startMask = performance.now();
+ const shapeImageData = shapeCtx.getImageData(0, 0, width, height);
+ const data = shapeImageData.data;
+ const shapeMask = new Uint8Array(width * height);
+ const boundaryMask = new Uint8Array(width * height);
+ let shapePixelCount = 0;
+ for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {
+ const a = data[i + 3];
+ const isShape = a === 0 ? 0 : 1;
+ shapeMask[idx] = isShape;
+ shapePixelCount += isShape;
+ }
+ const boundaryIndices = [];
+ const interiorIndices = [];
+ for (let y = 0; y < height; y++) {
+ for (let x = 0; x < width; x++) {
+ const idx = y * width + x;
+ if (!shapeMask[idx]) continue;
+ let isBoundary = false;
+ if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
+ isBoundary = true;
+ } else {
+ isBoundary = !shapeMask[idx - 1] || // left
+ !shapeMask[idx + 1] || // right
+ !shapeMask[idx - width] || // top
+ !shapeMask[idx + width] || // bottom
+ !shapeMask[idx - width - 1] || // top-left
+ !shapeMask[idx - width + 1] || // top-right
+ !shapeMask[idx + width - 1] || // bottom-left
+ !shapeMask[idx + width + 1];
+ }
+ if (isBoundary) {
+ boundaryMask[idx] = 1;
+ boundaryIndices.push(idx);
+ } else {
+ interiorIndices.push(idx);
+ }
+ }
+ }
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);
+ console.log(
+ ` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)`
+ );
+ console.log(` Interior pixels: ${interiorIndices.length}`);
+ console.log(` Boundary pixels: ${boundaryIndices.length}`);
+ }
+ const sparseData = buildSparseData(
+ shapeMask,
+ boundaryMask,
+ new Uint32Array(interiorIndices),
+ new Uint32Array(boundaryIndices),
+ width,
+ height
+ );
+ const startSolve = performance.now();
+ const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);
+ }
+ let maxVal = 0;
+ let finalImageData;
+ for (let i = 0; i < interiorIndices.length; i++) {
+ const idx = interiorIndices[i];
+ if (u[idx] > maxVal) maxVal = u[idx];
+ }
+ const tempCanvas = document.createElement("canvas");
+ tempCanvas.width = width;
+ tempCanvas.height = height;
+ const tempCtx = tempCanvas.getContext("2d");
+ const tempImg = tempCtx.createImageData(width, height);
+ for (let y = 0; y < height; y++) {
+ for (let x = 0; x < width; x++) {
+ const idx = y * width + x;
+ const px = idx * 4;
+ if (!shapeMask[idx]) {
+ tempImg.data[px] = 255;
+ tempImg.data[px + 1] = 255;
+ tempImg.data[px + 2] = 255;
+ tempImg.data[px + 3] = 0;
+ } else {
+ const poissonRatio = u[idx] / maxVal;
+ let gray = 255 * (1 - poissonRatio);
+ tempImg.data[px] = gray;
+ tempImg.data[px + 1] = gray;
+ tempImg.data[px + 2] = gray;
+ tempImg.data[px + 3] = 255;
+ }
+ }
+ }
+ tempCtx.putImageData(tempImg, 0, 0);
+ ctx.imageSmoothingEnabled = true;
+ ctx.imageSmoothingQuality = "high";
+ ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);
+ const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);
+ const origPadX = Math.ceil(originalWidth * paddingSize);
+ const origPadY = Math.ceil(originalHeight * paddingSize);
+ const originalCanvas = document.createElement("canvas");
+ originalCanvas.width = originalWidth;
+ originalCanvas.height = originalHeight;
+ const originalCtx = originalCanvas.getContext("2d");
+ originalCtx.drawImage(img, origPadX, origPadY, originalWidth - 2 * origPadX, originalHeight - 2 * origPadY);
+ const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
+ for (let i = 0; i < outImg.data.length; i += 4) {
+ const a = originalData.data[i + 3];
+ const upscaledAlpha = outImg.data[i + 3];
+ if (a === 0) {
+ outImg.data[i] = 255;
+ outImg.data[i + 1] = 0;
+ } else {
+ outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i];
+ outImg.data[i + 1] = a;
+ }
+ outImg.data[i + 2] = 255;
+ outImg.data[i + 3] = 255;
+ }
+ ctx.putImageData(outImg, 0, 0);
+ finalImageData = outImg;
+ canvas.toBlob((blob) => {
+ if (!blob) {
+ reject(new Error("Failed to create PNG blob"));
+ return;
+ }
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ const totalTime = performance.now() - totalStartTime;
+ console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);
+ if (scaleFactor < 1) {
+ const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5);
+ console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);
+ console.log(
+ `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)`
+ );
+ }
+ }
+ resolve({
+ imageData: finalImageData,
+ pngBlob: blob
+ });
+ }, "image/png");
+ };
+ img.onerror = () => reject(new Error("Failed to load image"));
+ img.src = typeof file === "string" ? file : URL.createObjectURL(file);
+ });
+}
+function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) {
+ const pixelCount = interiorPixels.length;
+ const neighborIndices = new Int32Array(pixelCount * 4);
+ for (let i = 0; i < pixelCount; i++) {
+ const idx = interiorPixels[i];
+ const x = idx % width;
+ const y = Math.floor(idx / width);
+ neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;
+ neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;
+ neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;
+ neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;
+ }
+ return {
+ interiorPixels,
+ boundaryPixels,
+ pixelCount,
+ neighborIndices
+ };
+}
+function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) {
+ const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;
+ const C = 0.01;
+ const u = new Float32Array(width * height);
+ const { interiorPixels, neighborIndices, pixelCount } = sparseData;
+ const startTime = performance.now();
+ const omega = 1.9;
+ const redPixels = [];
+ const blackPixels = [];
+ for (let i = 0; i < pixelCount; i++) {
+ const idx = interiorPixels[i];
+ const x = idx % width;
+ const y = Math.floor(idx / width);
+ if ((x + y) % 2 === 0) {
+ redPixels.push(i);
+ } else {
+ blackPixels.push(i);
+ }
+ }
+ for (let iter = 0; iter < ITERATIONS; iter++) {
+ for (const i of redPixels) {
+ const idx = interiorPixels[i];
+ const eastIdx = neighborIndices[i * 4 + 0];
+ const westIdx = neighborIndices[i * 4 + 1];
+ const northIdx = neighborIndices[i * 4 + 2];
+ const southIdx = neighborIndices[i * 4 + 3];
+ let sumN = 0;
+ if (eastIdx >= 0) sumN += u[eastIdx];
+ if (westIdx >= 0) sumN += u[westIdx];
+ if (northIdx >= 0) sumN += u[northIdx];
+ if (southIdx >= 0) sumN += u[southIdx];
+ const newValue = (C + sumN) / 4;
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
+ }
+ for (const i of blackPixels) {
+ const idx = interiorPixels[i];
+ const eastIdx = neighborIndices[i * 4 + 0];
+ const westIdx = neighborIndices[i * 4 + 1];
+ const northIdx = neighborIndices[i * 4 + 2];
+ const southIdx = neighborIndices[i * 4 + 3];
+ let sumN = 0;
+ if (eastIdx >= 0) sumN += u[eastIdx];
+ if (westIdx >= 0) sumN += u[westIdx];
+ if (northIdx >= 0) sumN += u[northIdx];
+ if (southIdx >= 0) sumN += u[southIdx];
+ const newValue = (C + sumN) / 4;
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
+ }
+ }
+ const tmp = new Float32Array(width * height);
+ for (let smooth = 0; smooth < 3; smooth++) {
+ tmp.set(u);
+ for (let i = 0; i < pixelCount; i++) {
+ const idx = interiorPixels[i];
+ const eastIdx = neighborIndices[i * 4 + 0];
+ const westIdx = neighborIndices[i * 4 + 1];
+ const northIdx = neighborIndices[i * 4 + 2];
+ const southIdx = neighborIndices[i * 4 + 3];
+ let sum = 0;
+ let count = 0;
+ if (eastIdx >= 0) {
+ sum += tmp[eastIdx];
+ count++;
+ }
+ if (westIdx >= 0) {
+ sum += tmp[westIdx];
+ count++;
+ }
+ if (northIdx >= 0) {
+ sum += tmp[northIdx];
+ count++;
+ }
+ if (southIdx >= 0) {
+ sum += tmp[southIdx];
+ count++;
+ }
+ u[idx] = count > 0 ? (tmp[idx] + sum / count) * 0.5 : tmp[idx];
+ }
+ }
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ const elapsed = performance.now() - startTime;
+ console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);
+ console.log(` Working size: ${width}\xD7${height}`);
+ console.log(` Iterations: ${ITERATIONS}`);
+ console.log(` Time: ${elapsed.toFixed(2)}ms`);
+ console.log(` Interior pixels processed: ${pixelCount}`);
+ console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`);
+ }
+ return u;
+}
+const GemSmokeShapes = {
+ none: 0,
+ circle: 1,
+ daisy: 2,
+ diamond: 3,
+ metaballs: 4
+};
+export {
+ GemSmokeShapes,
+ POISSON_CONFIG_OPTIMIZED,
+ gemSmokeFragmentShader,
+ gemSmokeMeta,
+ toProcessedGemSmoke
+};
+//# sourceMappingURL=gem-smoke.js.map
diff --git a/public/vendor/paper-shaders/shaders/gem-smoke.js.map b/public/vendor/paper-shaders/shaders/gem-smoke.js.map
new file mode 100644
index 0000000..cec8dac
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/gem-smoke.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/gem-smoke.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI } from '../shader-utils.js';\n\nexport const gemSmokeMeta = {\n maxColorCount: 6,\n} as const;\n\n/**\n * Animated color fields placed over uploaded logo shape; gives the illusion of smoky noise\n * behind the glassy shape.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = alpha)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colors (vec4[]): Up to 6 smoke colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_colorBack (vec4): Background color in RGBA\n * - u_innerDistortion (float): Power of smoke distortion inside the input shape (0 to 1)\n * - u_outerDistortion (float): Power of smoke distortion outside the input shape (0 to 1)\n * - u_outerGlow (float): Visibility of smoke shape outside the input shape (0 to 1)\n * - u_innerGlow (float): Visibility of smoke shape inside the input shape (0 to 1)\n * - u_colorInner (vec4): Additional color inside the input shape, mixing with smoke (RGBA)\n * - u_offset (float): Vertical offset of smoke inside the shape (-1 to 1)\n * - u_angle (float): Smoke direction in degrees (0 to 360)\n * - u_size (float): Size of smoke shape relative to the image box (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n * - v_objectUV (vec2): Normalized UV coordinates with scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const gemSmokeFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nin mediump vec2 v_imageUV;\nin mediump vec2 v_objectUV;\nin mediump vec2 v_responsiveUV;\nin mediump vec2 v_responsiveBoxGivenSize;\nout vec4 fragColor;\n\n// Image\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\n// Canvas\nuniform vec2 u_resolution;\nuniform float u_time;\n\n// Colors\nuniform vec4 u_colors[${gemSmokeMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorInner;\n\n// Effect controls\nuniform float u_innerDistortion;\nuniform float u_outerDistortion;\nuniform float u_outerGlow;\nuniform float u_innerGlow;\nuniform float u_offset;\nuniform float u_angle;\nuniform float u_size;\n\n// Shape controls\nuniform float u_shape;\nuniform bool u_isImage;\n\n${ declarePI }\n${ rotation2 }\n\n// 9x9 Gaussian blur on R and G channels\nvec2 gaussBlur9x9RG(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = max(radius, 0.0) * texel;\n // Pascal's row 8: sum = 256, 2D norm = 65536\n const float k[9] = float[9](1.0, 8.0, 28.0, 56.0, 70.0, 56.0, 28.0, 8.0, 1.0);\n vec2 sum = vec2(0.0);\n\n for (int j = -4; j <= 4; ++j) {\n float wy = k[j + 4];\n for (int i = -4; i <= 4; ++i) {\n float w = k[i + 4] * wy;\n vec2 off = vec2(float(i) * r.x, float(j) * r.y);\n sum += w * texture(tex, uv + off).rg;\n }\n }\n\n return sum / 65536.0;\n}\n\nfloat sst(float a, float b, float x) {\n return smoothstep(a, b, x);\n}\n\nvoid main() {\n float time = u_time;\n\n float roundness = 0.;\n float imgAlpha = 0.;\n\n if (u_isImage == true) {\n // Image sampling (UV scaled inward to account for padding)\n vec2 imageUV = v_imageUV;\n imageUV -= .5;\n imageUV *= .95;\n imageUV += .5;\n\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n\n // Blurred image: x = roundness, y = alpha\n vec2 blurred = gaussBlur9x9RG(u_image, imageUV, dudx, dudy, 10.);\n roundness = 1. - blurred.x;\n vec2 texelA = 1.0 / vec2(textureSize(u_image, 0));\n const float k3[3] = float[3](1.0, 2.0, 1.0);\n for (int j = -1; j <= 1; ++j) {\n for (int i = -1; i <= 1; ++i) {\n imgAlpha += k3[i + 1] * k3[j + 1] * texture(u_image, imageUV + vec2(float(i) * texelA.x, float(j) * texelA.y)).g;\n }\n }\n imgAlpha /= 16.0;\n } else {\n vec2 uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n float edge = 0.;\n\n if (u_shape < 1.) {\n // full-fill on canvas\n vec2 borderUV = v_responsiveUV + .5;\n vec2 mask = min(borderUV, 1. - borderUV);\n vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n } else if (u_shape < 2.) {\n // circle\n vec2 shapeUV = uv - .5;\n shapeUV *= .67;\n edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);\n } else if (u_shape < 3.) {\n // daisy\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.68;\n\n float r = length(shapeUV) * 2.;\n float a = atan(shapeUV.y, shapeUV.x) + .2;\n r *= (1. + .05 * sin(3. * a + 2. * time));\n float f = abs(cos(a * 3.));\n edge = smoothstep(f, f + .7, r);\n edge *= edge;\n } else if (u_shape < 4.) {\n // diamond\n vec2 shapeUV = uv - .5;\n shapeUV = rotate(shapeUV, .25 * PI);\n shapeUV *= 1.42;\n shapeUV += .5;\n vec2 mask = min(shapeUV, 1. - shapeUV);\n vec2 pixel_thickness = vec2(.15);\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n } else if (u_shape < 5.) {\n // metaballs\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.3;\n edge = 0.;\n for (int i = 0; i < 5; i++) {\n float fi = float(i);\n float speed = 1.5 + 2./3. * sin(fi * 12.345);\n float angle = -fi * 1.5;\n vec2 dir1 = vec2(cos(angle), sin(angle));\n vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));\n vec2 traj = .4 * (dir1 * sin(time * speed + fi * 1.23) + dir2 * cos(time * (speed * 0.7) + fi * 2.17));\n float d = length(shapeUV + traj);\n edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);\n }\n edge = 1. - smoothstep(.65, .9, edge);\n edge = pow(edge, 4.);\n }\n\n imgAlpha = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);\n roundness = 1. - edge;\n }\n\n// Smoke UV setup\n vec2 smokeUV = v_objectUV;\n smokeUV = rotate(smokeUV, u_angle * PI / 180.);\n smokeUV *= mix(4., 1., u_size);\n\n // Two swirl paths: inner (shape-masked) and outer (free), each with independent distortion\n vec2 innerUV = smokeUV;\n vec2 outerUV = smokeUV;\n\n // Vertical displacement \u2014 applied independently to inner and outer\n innerUV.y += u_innerDistortion * (1. - sst(0., 1., length(.4 * innerUV)));\n innerUV.y -= .4 * u_innerDistortion;\n innerUV.y += .7 * u_offset * roundness;\n\n outerUV.y += u_outerDistortion * (1. - sst(0., 1., length(.4 * outerUV)));\n outerUV.y -= .4 * u_outerDistortion;\n\n float innerSwirl = u_innerDistortion * roundness;\n float outerSwirl = u_outerDistortion;\n\n for (int i = 1; i < 5; i++) {\n float fi = float(i);\n\n float stretchIn = max(length(dFdx(innerUV)), length(dFdy(innerUV)));\n float dampenIn = 1. / (1. + stretchIn * 8.);\n float sIn = innerSwirl * dampenIn;\n innerUV.x += sIn / fi * cos(time + fi * 2.9 * innerUV.y);\n innerUV.y += sIn / fi * cos(time + fi * 1.5 * innerUV.x);\n\n float stretchOut = max(length(dFdx(outerUV)), length(dFdy(outerUV)));\n float dampenOut = 1. / (1. + stretchOut * 8.);\n float sOut = outerSwirl * dampenOut;\n outerUV.x += sOut / fi * cos(time + fi * 2.9 * outerUV.y);\n outerUV.y += sOut / fi * cos(time + fi * 1.5 * outerUV.x);\n }\n\n // Smoke shapes from swirl fields\n float innerShape = exp(-1.5 * dot(innerUV, innerUV));\n float outerShape = exp(-1.5 * dot(outerUV, outerUV));\n\n // Visibility masks\n float outerMask = pow(u_outerGlow, 2.) * (1. - imgAlpha);\n float innerMask = (.01 + .99 * u_innerGlow) * imgAlpha;\n\n innerShape *= innerMask;\n outerShape *= outerMask;\n\n // Color gradient\n float mixer = (innerShape + outerShape) * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n\n float smokeMask = 0.;\n for (int i = 1; i < ${gemSmokeMeta.maxColorCount + 1}; i++) {\n if (i > int(u_colorsCount)) break;\n\n float m = sst(0., 1., clamp(mixer - float(i - 1), 0., 1.));\n if (i == 1) smokeMask = m;\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n // Compositing (premultiplied alpha, front-to-back)\n vec3 color = gradient.rgb * smokeMask;\n float opacity = gradient.a * smokeMask;\n\n float innerOpacity = u_colorInner.a * imgAlpha;\n vec3 innerColor = u_colorInner.rgb * innerOpacity;\n color += innerColor * (1.0 - opacity);\n opacity += innerOpacity * (1.0 - opacity);\n\n vec3 backColor = u_colorBack.rgb * u_colorBack.a;\n color += backColor * (1.0 - opacity);\n opacity += u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\n// Configuration for Poisson solver\nexport const POISSON_CONFIG_OPTIMIZED = {\n measurePerformance: false, // Set to true to see performance metrics\n workingSize: 512, // Size to solve Poisson at (will upscale to original size)\n iterations: 32, // SOR converges ~2-20x faster than standard Gauss-Seidel\n};\n\n// Precomputed pixel data for sparse processing\ninterface SparsePixelData {\n interiorPixels: Uint32Array; // Indices of interior pixels\n boundaryPixels: Uint32Array; // Indices of boundary pixels\n pixelCount: number;\n // Neighbor indices for each interior pixel (4 neighbors per pixel)\n // Layout: [east, west, north, south] for each pixel\n neighborIndices: Int32Array;\n}\n\nexport function toProcessedGemSmoke(file: File | string): Promise<{ imageData: ImageData; pngBlob: Blob }> {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const isBlob = typeof file === 'string' && file.startsWith('blob:');\n\n return new Promise((resolve, reject) => {\n if (!file || !ctx) {\n reject(new Error('Invalid file or canvas context'));\n return;\n }\n\n const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get('Content-Type'));\n const img = new Image();\n img.crossOrigin = 'anonymous';\n const totalStartTime = performance.now();\n\n img.onload = async () => {\n // Force SVG to load at a high fidelity size if it's an SVG\n let isSVG;\n\n const blobContentType = await blobContentTypePromise;\n\n if (blobContentType) {\n isSVG = blobContentType === 'image/svg+xml';\n } else if (typeof file === 'string') {\n isSVG = file.endsWith('.svg') || file.startsWith('data:image/svg+xml');\n } else {\n isSVG = file.type === 'image/svg+xml';\n }\n\n let originalWidth = img.width || img.naturalWidth;\n let originalHeight = img.height || img.naturalHeight;\n\n if (isSVG) {\n // Scale SVG to max dimension while preserving aspect ratio\n const svgMaxSize = 4096;\n const aspectRatio = originalWidth / originalHeight;\n\n if (originalWidth > originalHeight) {\n originalWidth = svgMaxSize;\n originalHeight = svgMaxSize / aspectRatio;\n } else {\n originalHeight = svgMaxSize;\n originalWidth = svgMaxSize * aspectRatio;\n }\n\n img.width = originalWidth;\n img.height = originalHeight;\n }\n\n // Always scale to working resolution for consistency\n const minDimension = Math.min(originalWidth, originalHeight);\n const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;\n\n // Calculate scale to fit within workingSize\n const scaleFactor = targetSize / minDimension;\n const width = Math.round(originalWidth * scaleFactor);\n const height = Math.round(originalHeight * scaleFactor);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Processing Mode]`);\n console.log(` Original: ${originalWidth}\u00D7${originalHeight}`);\n console.log(` Working: ${width}\u00D7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);\n if (scaleFactor < 1) {\n console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\u00D7`);\n }\n }\n\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n\n const paddingSize = 0.025;\n const padX = Math.ceil(width * paddingSize);\n const padY = Math.ceil(height * paddingSize);\n const imgW = width - 2 * padX;\n const imgH = height - 2 * padY;\n\n // \u2500\u2500 1. Shape canvas (working res): image centered with padding \u2500\u2500\n const shapeCanvas = document.createElement('canvas');\n shapeCanvas.width = width;\n shapeCanvas.height = height;\n\n const shapeCtx = shapeCanvas.getContext('2d')!;\n shapeCtx.drawImage(img, padX, padY, imgW, imgH);\n\n // 1) Build optimized masks using TypedArrays\n const startMask = performance.now();\n\n const shapeImageData = shapeCtx.getImageData(0, 0, width, height);\n const data = shapeImageData.data;\n\n // Use Uint8Array for masks (1 byte per pixel vs 8+ bytes for boolean array)\n const shapeMask = new Uint8Array(width * height);\n const boundaryMask = new Uint8Array(width * height);\n\n // First pass: identify shape pixels\n let shapePixelCount = 0;\n for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {\n const a = data[i + 3];\n const isShape = a === 0 ? 0 : 1;\n shapeMask[idx] = isShape;\n shapePixelCount += isShape;\n }\n\n // 2) Optimized boundary detection using sparse approach\n // Only check shape pixels, not all pixels\n const boundaryIndices: number[] = [];\n const interiorIndices: number[] = [];\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n if (!shapeMask[idx]) continue;\n\n // Check if pixel is on boundary (optimized: early exit)\n let isBoundary = false;\n\n // Check 4-connected neighbors first (most common case)\n if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {\n isBoundary = true;\n } else {\n // Check all 8 neighbors (including diagonals) for comprehensive boundary detection\n isBoundary =\n !shapeMask[idx - 1] || // left\n !shapeMask[idx + 1] || // right\n !shapeMask[idx - width] || // top\n !shapeMask[idx + width] || // bottom\n !shapeMask[idx - width - 1] || // top-left\n !shapeMask[idx - width + 1] || // top-right\n !shapeMask[idx + width - 1] || // bottom-left\n !shapeMask[idx + width + 1]; // bottom-right\n }\n\n if (isBoundary) {\n boundaryMask[idx] = 1;\n boundaryIndices.push(idx);\n } else {\n interiorIndices.push(idx);\n }\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);\n console.log(\n ` Shape pixels: ${shapePixelCount} / ${width * height} (${((shapePixelCount / (width * height)) * 100).toFixed(1)}%)`\n );\n console.log(` Interior pixels: ${interiorIndices.length}`);\n console.log(` Boundary pixels: ${boundaryIndices.length}`);\n }\n\n // 3) Precompute sparse data structure for solver\n const sparseData = buildSparseData(\n shapeMask,\n boundaryMask,\n new Uint32Array(interiorIndices),\n new Uint32Array(boundaryIndices),\n width,\n height\n );\n\n // 4) Solve Poisson equation with optimized sparse solver\n const startSolve = performance.now();\n const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);\n }\n\n // 5) Generate output image\n let maxVal = 0;\n let finalImageData: ImageData;\n\n // Only check shape pixels for max value\n for (let i = 0; i < interiorIndices.length; i++) {\n const idx = interiorIndices[i]!;\n if (u[idx]! > maxVal) maxVal = u[idx]!;\n }\n\n // Create roundness image at working resolution\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = width;\n tempCanvas.height = height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n const tempImg = tempCtx.createImageData(width, height);\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const px = idx * 4;\n\n if (!shapeMask[idx]) {\n tempImg.data[px] = 255;\n tempImg.data[px + 1] = 255;\n tempImg.data[px + 2] = 255;\n tempImg.data[px + 3] = 0; // Alpha = 0 for background\n } else {\n const poissonRatio = u[idx]! / maxVal;\n let gray = 255 * (1 - poissonRatio);\n tempImg.data[px] = gray;\n tempImg.data[px + 1] = gray;\n tempImg.data[px + 2] = gray;\n tempImg.data[px + 3] = 255; // Alpha = 255 for shape\n }\n }\n }\n tempCtx.putImageData(tempImg, 0, 0);\n\n // Upscale to original resolution with smooth interpolation\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);\n\n // Now get the upscaled image data for final output\n const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Re-apply edges from original resolution with anti-aliasing\n // This ensures edges are pixel-perfect while roundness is smooth\n const origPadX = Math.ceil(originalWidth * paddingSize);\n const origPadY = Math.ceil(originalHeight * paddingSize);\n const originalCanvas = document.createElement('canvas');\n originalCanvas.width = originalWidth;\n originalCanvas.height = originalHeight;\n const originalCtx = originalCanvas.getContext('2d')!;\n originalCtx.drawImage(img, origPadX, origPadY, originalWidth - 2 * origPadX, originalHeight - 2 * origPadY);\n const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Process each pixel: Red channel = roundness, Alpha channel = original alpha\n for (let i = 0; i < outImg.data.length; i += 4) {\n const a = originalData.data[i + 3]!;\n // Use only alpha to determine background vs shape\n const upscaledAlpha = outImg.data[i + 3]!;\n if (a === 0) {\n // Background pixel\n outImg.data[i] = 255;\n outImg.data[i + 1] = 0;\n } else {\n // Red channel carries the roundness\n // Check if upscale missed this pixel by looking at alpha channel\n // If upscaled alpha is 0, the low-res version thought this was background\n outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]!; // roundness or 0\n outImg.data[i + 1] = a; // original alpha\n }\n\n // Unused channels fixed\n outImg.data[i + 2] = 255;\n outImg.data[i + 3] = 255;\n }\n\n ctx.putImageData(outImg, 0, 0);\n finalImageData = outImg;\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const totalTime = performance.now() - totalStartTime;\n console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);\n if (scaleFactor < 1) {\n const estimatedFullResTime = totalTime * Math.pow((originalWidth * originalHeight) / (width * height), 1.5);\n console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);\n console.log(\n `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\u00D7 faster)`\n );\n }\n }\n\n resolve({\n imageData: finalImageData,\n pngBlob: blob,\n });\n }, 'image/png');\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\nfunction buildSparseData(\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n interiorPixels: Uint32Array,\n boundaryPixels: Uint32Array,\n width: number,\n height: number\n): SparsePixelData {\n const pixelCount = interiorPixels.length;\n\n // Build neighbor indices for sparse processing\n // For each interior pixel, store indices of its 4 neighbors\n // Use -1 for out-of-bounds or non-shape neighbors\n const neighborIndices = new Int32Array(pixelCount * 4);\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n // East neighbor\n neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;\n // West neighbor\n neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;\n // North neighbor\n neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;\n // South neighbor\n neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;\n }\n\n return {\n interiorPixels,\n boundaryPixels,\n pixelCount,\n neighborIndices,\n };\n}\n\nfunction solvePoissonSparse(\n sparseData: SparsePixelData,\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n width: number,\n height: number\n): Float32Array {\n // This controls how smooth the falloff roundness will be and extend into the shape\n const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;\n\n // Keep C constant - only iterations control roundness spread\n const C = 0.01;\n\n const u = new Float32Array(width * height);\n const { interiorPixels, neighborIndices, pixelCount } = sparseData;\n\n // Performance tracking\n const startTime = performance.now();\n\n // Red-Black SOR for better symmetry with fewer iterations\n // omega between 1.8-1.95 typically gives best convergence for Poisson\n const omega = 1.9;\n\n // Pre-classify pixels as red or black for efficient processing\n const redPixels: number[] = [];\n const blackPixels: number[] = [];\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n if ((x + y) % 2 === 0) {\n redPixels.push(i);\n } else {\n blackPixels.push(i);\n }\n }\n\n for (let iter = 0; iter < ITERATIONS; iter++) {\n // Red pass: update red pixels\n for (const i of redPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n\n // Black pass: update black pixels\n for (const i of blackPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n }\n\n // Jacobi smoothing passes to remove Red-Black checkerboard artifacts\n const tmp = new Float32Array(width * height);\n for (let smooth = 0; smooth < 3; smooth++) {\n tmp.set(u);\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n let sum = 0;\n let count = 0;\n if (eastIdx >= 0) { sum += tmp[eastIdx]!; count++; }\n if (westIdx >= 0) { sum += tmp[westIdx]!; count++; }\n if (northIdx >= 0) { sum += tmp[northIdx]!; count++; }\n if (southIdx >= 0) { sum += tmp[southIdx]!; count++; }\n\n u[idx] = count > 0 ? (tmp[idx]! + sum / count) * 0.5 : tmp[idx]!;\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const elapsed = performance.now() - startTime;\n\n console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);\n console.log(` Working size: ${width}\u00D7${height}`);\n console.log(` Iterations: ${ITERATIONS}`);\n console.log(` Time: ${elapsed.toFixed(2)}ms`);\n console.log(` Interior pixels processed: ${pixelCount}`);\n console.log(` Speed: ${((ITERATIONS * pixelCount) / (elapsed * 1000)).toFixed(2)} Mpixels/sec`);\n }\n\n return u;\n}\n\nexport interface GemSmokeUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_image: HTMLImageElement | string | undefined;\n u_innerDistortion: number;\n u_outerDistortion: number;\n u_outerGlow: number;\n u_innerGlow: number;\n u_colorInner: [number, number, number, number];\n u_offset: number;\n u_angle: number;\n u_size: number;\n u_shape: (typeof GemSmokeShapes)[GemSmokeShape];\n u_isImage: boolean;\n}\n\nexport interface GemSmokeParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n colorBack?: string;\n image?: HTMLImageElement | string | undefined;\n innerDistortion?: number;\n outerDistortion?: number;\n outerGlow?: number;\n innerGlow?: number;\n colorInner?: string;\n offset?: number;\n angle?: number;\n size?: number;\n shape?: GemSmokeShape;\n}\n\nexport const GemSmokeShapes = {\n none: 0,\n circle: 1,\n daisy: 2,\n diamond: 3,\n metaballs: 4,\n} as const;\n\nexport type GemSmokeShape = keyof typeof GemSmokeShapes;\n"],
+ "mappings": "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",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/god-rays.d.ts b/public/vendor/paper-shaders/shaders/god-rays.d.ts
new file mode 100644
index 0000000..860ffd5
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/god-rays.d.ts
@@ -0,0 +1,67 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const godRaysMeta: {
+ readonly maxColorCount: 5;
+};
+/**
+ * Animated rays of light radiating from the center, blended with up to 5 colors.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorBloom (vec4): Color overlay blended with the rays in RGBA
+ * - u_colors (vec4[]): Up to 5 ray colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_bloom (float): Strength of the bloom/overlay effect, 0 = alpha blend, 1 = additive blend (0 to 1)
+ * - u_intensity (float): Visibility/strength of the rays (0 to 1)
+ * - u_density (float): The number of rays (0 to 1)
+ * - u_spotty (float): The length of the rays, higher = more spots/shorter rays (0 to 1)
+ * - u_midSize (float): Size of the circular glow shape in the center (0 to 1)
+ * - u_midIntensity (float): Brightness/intensity of the central glow (0 to 1)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * The rays are adjustable by size, density, brightness and center glow.
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const godRaysFragmentShader: string;
+export interface GodRaysUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colorBloom: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_spotty: number;
+ u_midSize: number;
+ u_midIntensity: number;
+ u_density: number;
+ u_intensity: number;
+ u_bloom: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface GodRaysParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colorBloom?: string;
+ colors?: string[];
+ spotty?: number;
+ midSize?: number;
+ midIntensity?: number;
+ density?: number;
+ intensity?: number;
+ bloom?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/god-rays.js b/public/vendor/paper-shaders/shaders/god-rays.js
new file mode 100644
index 0000000..a4c3891
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/god-rays.js
@@ -0,0 +1,133 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, textureRandomizerR, colorBandingFix, proceduralHash11 } from "../shader-utils.js";
+const godRaysMeta = {
+ maxColorCount: 5
+};
+const godRaysFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorBloom;
+uniform vec4 u_colors[${godRaysMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_density;
+uniform float u_spotty;
+uniform float u_midSize;
+uniform float u_midIntensity;
+uniform float u_intensity;
+uniform float u_bloom;
+
+in vec2 v_objectUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${textureRandomizerR}
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = randomR(i);
+ float b = randomR(i + vec2(1.0, 0.0));
+ float c = randomR(i + vec2(0.0, 1.0));
+ float d = randomR(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+${proceduralHash11}
+
+float raysShape(vec2 uv, float r, float freq, float intensity, float radius) {
+ float a = atan(uv.y, uv.x);
+ vec2 left = vec2(a * freq, r);
+ vec2 right = vec2(fract(a / TWO_PI) * TWO_PI * freq, r);
+ float n_left = pow(valueNoise(left), intensity);
+ float n_right = pow(valueNoise(right), intensity);
+ float shape = mix(n_right, n_left, smoothstep(-.15, .15, uv.x));
+ return shape;
+}
+
+void main() {
+ vec2 shape_uv = v_objectUV;
+
+ float t = .2 * u_time;
+
+ float radius = length(shape_uv);
+ float spots = 6.5 * abs(u_spotty);
+
+ float intensity = 4. - 3. * clamp(u_intensity, 0., 1.);
+
+ float delta = 1. - smoothstep(0., 1., radius);
+
+ float midSize = 10. * abs(u_midSize);
+ float ms_lo = 0.02 * midSize;
+ float ms_hi = max(midSize, 1e-6);
+ float middleShape = pow(u_midIntensity, 0.3) * (1. - smoothstep(ms_lo, ms_hi, 3.0 * radius));
+ middleShape = pow(middleShape, 5.0);
+
+ vec3 accumColor = vec3(0.0);
+ float accumAlpha = 0.0;
+
+ for (int i = 0; i < ${godRaysMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+
+ vec2 rotatedUV = rotate(shape_uv, float(i) + 1.0);
+
+ float r1 = radius * (1.0 + 0.4 * float(i)) - 3.0 * t;
+ float r2 = 0.5 * radius * (1.0 + spots) - 2.0 * t;
+ float density = 6. * u_density + step(.5, u_density) * pow(4.5 * (u_density - .5), 4.);
+ float f = mix(1.0, 3.0 + 0.5 * float(i), hash11(float(i) * 15.)) * density;
+
+ float ray = raysShape(rotatedUV, r1, 5.0 * f, intensity, radius);
+ ray *= raysShape(rotatedUV, r2, 4.0 * f, intensity, radius);
+ ray += (1. + 4. * ray) * middleShape;
+ ray = clamp(ray, 0.0, 1.0);
+
+ float srcAlpha = u_colors[i].a * ray;
+ vec3 srcColor = u_colors[i].rgb * srcAlpha;
+
+ vec3 alphaBlendColor = accumColor + (1.0 - accumAlpha) * srcColor;
+ float alphaBlendAlpha = accumAlpha + (1.0 - accumAlpha) * srcAlpha;
+
+ vec3 addBlendColor = accumColor + srcColor;
+ float addBlendAlpha = accumAlpha + srcAlpha;
+
+ accumColor = mix(alphaBlendColor, addBlendColor, u_bloom);
+ accumAlpha = mix(alphaBlendAlpha, addBlendAlpha, u_bloom);
+ }
+
+ float overlayAlpha = u_colorBloom.a;
+ vec3 overlayColor = u_colorBloom.rgb * overlayAlpha;
+
+ vec3 colorWithOverlay = accumColor + accumAlpha * overlayColor;
+ accumColor = mix(accumColor, colorWithOverlay, u_bloom);
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+
+ vec3 color = accumColor + (1. - accumAlpha) * bgColor;
+ float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;
+ color = clamp(color, 0., 1.);
+ opacity = clamp(opacity, 0., 1.);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ godRaysFragmentShader,
+ godRaysMeta
+};
+//# sourceMappingURL=god-rays.js.map
diff --git a/public/vendor/paper-shaders/shaders/god-rays.js.map b/public/vendor/paper-shaders/shaders/god-rays.js.map
new file mode 100644
index 0000000..a6a5bea
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/god-rays.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/god-rays.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, textureRandomizerR, colorBandingFix, proceduralHash11 } from '../shader-utils.js';\n\nexport const godRaysMeta = {\n maxColorCount: 5,\n} as const;\n\n/**\n * Animated rays of light radiating from the center, blended with up to 5 colors.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorBloom (vec4): Color overlay blended with the rays in RGBA\n * - u_colors (vec4[]): Up to 5 ray colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_bloom (float): Strength of the bloom/overlay effect, 0 = alpha blend, 1 = additive blend (0 to 1)\n * - u_intensity (float): Visibility/strength of the rays (0 to 1)\n * - u_density (float): The number of rays (0 to 1)\n * - u_spotty (float): The length of the rays, higher = more spots/shorter rays (0 to 1)\n * - u_midSize (float): Size of the circular glow shape in the center (0 to 1)\n * - u_midIntensity (float): Brightness/intensity of the central glow (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * The rays are adjustable by size, density, brightness and center glow.\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const godRaysFragmentShader: 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_colorBloom;\nuniform vec4 u_colors[${ godRaysMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_density;\nuniform float u_spotty;\nuniform float u_midSize;\nuniform float u_midIntensity;\nuniform float u_intensity;\nuniform float u_bloom;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\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}\n\n${ proceduralHash11 }\n\nfloat raysShape(vec2 uv, float r, float freq, float intensity, float radius) {\n float a = atan(uv.y, uv.x);\n vec2 left = vec2(a * freq, r);\n vec2 right = vec2(fract(a / TWO_PI) * TWO_PI * freq, r);\n float n_left = pow(valueNoise(left), intensity);\n float n_right = pow(valueNoise(right), intensity);\n float shape = mix(n_right, n_left, smoothstep(-.15, .15, uv.x));\n return shape;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = .2 * u_time;\n\n float radius = length(shape_uv);\n float spots = 6.5 * abs(u_spotty);\n\n float intensity = 4. - 3. * clamp(u_intensity, 0., 1.);\n\n float delta = 1. - smoothstep(0., 1., radius);\n\n float midSize = 10. * abs(u_midSize);\n float ms_lo = 0.02 * midSize;\n float ms_hi = max(midSize, 1e-6);\n float middleShape = pow(u_midIntensity, 0.3) * (1. - smoothstep(ms_lo, ms_hi, 3.0 * radius));\n middleShape = pow(middleShape, 5.0);\n\n vec3 accumColor = vec3(0.0);\n float accumAlpha = 0.0;\n\n for (int i = 0; i < ${ godRaysMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 rotatedUV = rotate(shape_uv, float(i) + 1.0);\n\n float r1 = radius * (1.0 + 0.4 * float(i)) - 3.0 * t;\n float r2 = 0.5 * radius * (1.0 + spots) - 2.0 * t;\n float density = 6. * u_density + step(.5, u_density) * pow(4.5 * (u_density - .5), 4.);\n float f = mix(1.0, 3.0 + 0.5 * float(i), hash11(float(i) * 15.)) * density;\n\n float ray = raysShape(rotatedUV, r1, 5.0 * f, intensity, radius);\n ray *= raysShape(rotatedUV, r2, 4.0 * f, intensity, radius);\n ray += (1. + 4. * ray) * middleShape;\n ray = clamp(ray, 0.0, 1.0);\n\n float srcAlpha = u_colors[i].a * ray;\n vec3 srcColor = u_colors[i].rgb * srcAlpha;\n\n vec3 alphaBlendColor = accumColor + (1.0 - accumAlpha) * srcColor;\n float alphaBlendAlpha = accumAlpha + (1.0 - accumAlpha) * srcAlpha;\n\n vec3 addBlendColor = accumColor + srcColor;\n float addBlendAlpha = accumAlpha + srcAlpha;\n\n accumColor = mix(alphaBlendColor, addBlendColor, u_bloom);\n accumAlpha = mix(alphaBlendAlpha, addBlendAlpha, u_bloom);\n }\n\n float overlayAlpha = u_colorBloom.a;\n vec3 overlayColor = u_colorBloom.rgb * overlayAlpha;\n\n vec3 colorWithOverlay = accumColor + accumAlpha * overlayColor;\n accumColor = mix(accumColor, colorWithOverlay, u_bloom);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n color = clamp(color, 0., 1.);\n opacity = clamp(opacity, 0., 1.);\n\n ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GodRaysUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorBloom: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_spotty: number;\n u_midSize: number;\n u_midIntensity: number;\n u_density: number;\n u_intensity: number;\n u_bloom: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GodRaysParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorBloom?: string;\n colors?: string[];\n spotty?: number;\n midSize?: number;\n midIntensity?: number;\n density?: number;\n intensity?: number;\n bloom?: number;\n}\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,WAAW,oBAAoB,iBAAiB,wBAAwB;AAErF,MAAM,cAAc;AAAA,EACzB,eAAe;AACjB;AAwCO,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASpB,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAchD,SAAU;AAAA,EACV,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcnB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiCK,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAyC9C,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/grain-gradient.d.ts b/public/vendor/paper-shaders/shaders/grain-gradient.d.ts
new file mode 100644
index 0000000..73f1b9f
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/grain-gradient.d.ts
@@ -0,0 +1,82 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const grainGradientMeta: {
+ readonly maxColorCount: 7;
+};
+/**
+ * Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms.
+ *
+ * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning (0 to 1)
+ * - u_originY (float): Reference point for positioning (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic
+ * - u_worldHeight (float): Virtual height of the graphic
+ * - u_fit (float): Fit mode (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level (0.01 to 4)
+ * - u_rotation (float): Rotation angle in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset (-1 to 1)
+ * - u_offsetY (float): Vertical offset (-1 to 1)
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 7 gradient colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ * - u_intensity (float): Distortion between color bands (0 to 1)
+ * - u_noise (float): Grainy noise overlay (0 to 1)
+ * - u_shape (float): Shape type (1 = wave, 2 = dots, 3 = truchet, 4 = corners, 5 = ripple, 6 = blob, 7 = sphere)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used for shapes 4-7)
+ * - v_objectBoxSize (vec2): Size of the object bounding box in pixels
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for shapes 1-3)
+ * - v_patternBoxSize (vec2): Size of the pattern bounding box in pixels
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const grainGradientFragmentShader: string;
+export interface GrainGradientUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_softness: number;
+ u_intensity: number;
+ u_noise: number;
+ u_shape: (typeof GrainGradientShapes)[GrainGradientShape];
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ softness?: number;
+ intensity?: number;
+ noise?: number;
+ shape?: GrainGradientShape;
+}
+export declare const GrainGradientShapes: {
+ wave: number;
+ dots: number;
+ truchet: number;
+ corners: number;
+ ripple: number;
+ blob: number;
+ sphere: number;
+};
+export type GrainGradientShape = keyof typeof GrainGradientShapes;
diff --git a/public/vendor/paper-shaders/shaders/grain-gradient.js b/public/vendor/paper-shaders/shaders/grain-gradient.js
new file mode 100644
index 0000000..ed7a3fc
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/grain-gradient.js
@@ -0,0 +1,303 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {
+} from "../shader-sizing.js";
+import {
+ simplexNoise,
+ declarePI,
+ rotation2,
+ textureRandomizerR,
+ proceduralHash11
+} from "../shader-utils.js";
+const grainGradientMeta = {
+ maxColorCount: 7
+};
+const grainGradientFragmentShader = `#version 300 es
+precision lowp float;
+
+uniform mediump float u_time;
+uniform mediump vec2 u_resolution;
+uniform mediump float u_pixelRatio;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${grainGradientMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_softness;
+uniform float u_intensity;
+uniform float u_noise;
+uniform float u_shape;
+
+uniform mediump float u_originX;
+uniform mediump float u_originY;
+uniform mediump float u_worldWidth;
+uniform mediump float u_worldHeight;
+uniform mediump float u_fit;
+
+uniform mediump float u_scale;
+uniform mediump float u_rotation;
+uniform mediump float u_offsetX;
+uniform mediump float u_offsetY;
+
+in vec2 v_objectUV;
+in vec2 v_patternUV;
+in vec2 v_objectBoxSize;
+in vec2 v_patternBoxSize;
+
+out vec4 fragColor;
+
+${declarePI}
+${simplexNoise}
+${rotation2}
+${textureRandomizerR}
+
+float valueNoiseR(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = randomR(i);
+ float b = randomR(i + vec2(1.0, 0.0));
+ float c = randomR(i + vec2(0.0, 1.0));
+ float d = randomR(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+vec4 fbmR(vec2 n0, vec2 n1, vec2 n2, vec2 n3) {
+ float amplitude = 0.2;
+ vec4 total = vec4(0.);
+ for (int i = 0; i < 3; i++) {
+ n0 = rotate(n0, 0.3);
+ n1 = rotate(n1, 0.3);
+ n2 = rotate(n2, 0.3);
+ n3 = rotate(n3, 0.3);
+ total.x += valueNoiseR(n0) * amplitude;
+ total.y += valueNoiseR(n1) * amplitude;
+ total.z += valueNoiseR(n2) * amplitude;
+ total.z += valueNoiseR(n3) * amplitude;
+ n0 *= 1.99;
+ n1 *= 1.99;
+ n2 *= 1.99;
+ n3 *= 1.99;
+ amplitude *= 0.6;
+ }
+ return total;
+}
+
+${proceduralHash11}
+
+vec2 truchet(vec2 uv, float idx){
+ idx = fract(((idx - .5) * 2.));
+ if (idx > 0.75) {
+ uv = vec2(1.0) - uv;
+ } else if (idx > 0.5) {
+ uv = vec2(1.0 - uv.x, uv.y);
+ } else if (idx > 0.25) {
+ uv = 1.0 - vec2(1.0 - uv.x, uv.y);
+ }
+ return uv;
+}
+
+void main() {
+
+ const float firstFrameOffset = 7.;
+ float t = .1 * (u_time + firstFrameOffset);
+
+ vec2 shape_uv = vec2(0.);
+ vec2 grain_uv = vec2(0.);
+
+ float r = u_rotation * PI / 180.;
+ float cr = cos(r);
+ float sr = sin(r);
+ mat2 graphicRotation = mat2(cr, sr, -sr, cr);
+ vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
+
+ if (u_shape > 3.5) {
+ shape_uv = v_objectUV;
+ grain_uv = shape_uv;
+
+ // apply inverse transform to grain_uv so it respects the originXY
+ grain_uv = transpose(graphicRotation) * grain_uv;
+ grain_uv *= u_scale;
+ grain_uv -= graphicOffset;
+ grain_uv *= v_objectBoxSize;
+ grain_uv *= .7;
+ } else {
+ shape_uv = .5 * v_patternUV;
+ grain_uv = 100. * v_patternUV;
+
+ // apply inverse transform to grain_uv so it respects the originXY
+ grain_uv = transpose(graphicRotation) * grain_uv;
+ grain_uv *= u_scale;
+ if (u_fit > 0.) {
+ vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
+ givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
+ float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;
+ vec2 patternBoxGivenSize = vec2(
+ (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
+ (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
+ );
+ patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;
+ float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);
+ grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);
+ }
+ vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;
+ grain_uv -= graphicOffset / patternBoxScale;
+ grain_uv *= 1.6;
+ }
+
+
+ float shape = 0.;
+
+ if (u_shape < 1.5) {
+ // Sine wave
+
+ float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t));
+ shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);
+
+ } else if (u_shape < 2.5) {
+ // Grid (dots)
+
+ float stripeIdx = floor(2. * shape_uv.x / TWO_PI);
+ float rand = hash11(stripeIdx * 100.);
+ rand = sign(rand - .5) * pow(4. * abs(rand), .3);
+ shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);
+ shape = pow(abs(shape), 4.);
+
+ } else if (u_shape < 3.5) {
+ // Truchet pattern
+
+ float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t);
+ shape_uv.x += 10.;
+ shape_uv *= .6;
+
+ vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv)));
+
+ float distance1 = length(tile);
+ float distance2 = length(tile - vec2(1.));
+
+ n2 -= .5;
+ n2 *= .1;
+ shape = smoothstep(.2, .55, distance1 + n2) * (1. - smoothstep(.45, .8, distance1 - n2));
+ shape += smoothstep(.2, .55, distance2 + n2) * (1. - smoothstep(.45, .8, distance2 - n2));
+
+ shape = pow(shape, 1.5);
+
+ } else if (u_shape < 4.5) {
+ // Corners
+
+ shape_uv *= .6;
+ vec2 outer = vec2(.5);
+
+ vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t)));
+ vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv);
+ shape = 1. - bl.x * bl.y * tr.x * tr.y;
+
+ shape_uv = -shape_uv;
+ bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t)));
+ tr = smoothstep(vec2(0.), outer, 1. - shape_uv);
+ shape -= bl.x * bl.y * tr.x * tr.y;
+
+ shape = 1. - smoothstep(0., 1., shape);
+
+ } else if (u_shape < 5.5) {
+ // Ripple
+
+ shape_uv *= 2.;
+ float dist = length(.4 * shape_uv);
+ float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5;
+ shape = waves;
+
+ } else if (u_shape < 6.5) {
+ // Blob
+
+ t *= 2.;
+
+ vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.));
+ vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t));
+ vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t));
+ vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.));
+
+ shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.);
+ shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.);
+ shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.);
+ shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.);
+
+ shape = smoothstep(.0, .9, shape);
+ float edge = smoothstep(.25, .3, shape);
+ shape = mix(.0, shape, edge);
+
+ } else {
+ // Sphere
+
+ shape_uv *= 2.;
+ float d = 1. - pow(length(shape_uv), 2.);
+ vec3 pos = vec3(shape_uv, sqrt(max(d, 0.)));
+ vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));
+ shape = .5 + .5 * dot(lightPos, pos);
+ shape *= step(0., d);
+ }
+
+ float baseNoise = snoise(grain_uv * .5);
+ vec4 fbmVals = fbmR(
+ .002 * grain_uv + 10.,
+ .003 * grain_uv,
+ .001 * grain_uv,
+ rotate(.4 * grain_uv, 2.)
+ );
+ float grainDist = baseNoise * snoise(grain_uv * .2) - fbmVals.x - fbmVals.y;
+ float rawNoise = .75 * baseNoise - fbmVals.w - fbmVals.z;
+ float noise = clamp(rawNoise, 0., 1.);
+
+ shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);
+ shape += u_noise * 10. / u_colorsCount * noise;
+
+ float aa = fwidth(shape);
+
+ shape = clamp(shape - .5 / u_colorsCount, 0., 1.);
+ float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.));
+ float mixer = shape * (u_colorsCount - 1.);
+
+ int cntStop = int(u_colorsCount) - 1;
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+ for (int i = 1; i < ${grainGradientMeta.maxColorCount}; i++) {
+ if (i > cntStop) break;
+
+ float localT = clamp(mixer - float(i - 1), 0., 1.);
+ localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, localT);
+
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, localT);
+ }
+
+ vec3 color = gradient.rgb * totalShape;
+ float opacity = gradient.a * totalShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1.0 - opacity);
+ opacity = opacity + u_colorBack.a * (1.0 - opacity);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const GrainGradientShapes = {
+ wave: 1,
+ dots: 2,
+ truchet: 3,
+ corners: 4,
+ ripple: 5,
+ blob: 6,
+ sphere: 7
+};
+export {
+ GrainGradientShapes,
+ grainGradientFragmentShader,
+ grainGradientMeta
+};
+//# sourceMappingURL=grain-gradient.js.map
diff --git a/public/vendor/paper-shaders/shaders/grain-gradient.js.map b/public/vendor/paper-shaders/shaders/grain-gradient.js.map
new file mode 100644
index 0000000..27240ed
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/grain-gradient.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/grain-gradient.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport {\n simplexNoise,\n declarePI,\n rotation2,\n textureRandomizerR,\n proceduralHash11,\n} from '../shader-utils.js';\n\nexport const grainGradientMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms.\n *\n * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning (0 to 1)\n * - u_originY (float): Reference point for positioning (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic\n * - u_worldHeight (float): Virtual height of the graphic\n * - u_fit (float): Fit mode (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level (0.01 to 4)\n * - u_rotation (float): Rotation angle in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset (-1 to 1)\n * - u_offsetY (float): Vertical offset (-1 to 1)\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 7 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_intensity (float): Distortion between color bands (0 to 1)\n * - u_noise (float): Grainy noise overlay (0 to 1)\n * - u_shape (float): Shape type (1 = wave, 2 = dots, 3 = truchet, 4 = corners, 5 = ripple, 6 = blob, 7 = sphere)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used for shapes 4-7)\n * - v_objectBoxSize (vec2): Size of the object bounding box in pixels\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for shapes 1-3)\n * - v_patternBoxSize (vec2): Size of the pattern bounding box in pixels\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\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\nin vec2 v_objectUV;\nin vec2 v_patternUV;\nin vec2 v_objectBoxSize;\nin vec2 v_patternBoxSize;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n${ rotation2 }\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}\nvec4 fbmR(vec2 n0, vec2 n1, vec2 n2, vec2 n3) {\n float amplitude = 0.2;\n vec4 total = vec4(0.);\n for (int i = 0; i < 3; i++) {\n n0 = rotate(n0, 0.3);\n n1 = rotate(n1, 0.3);\n n2 = rotate(n2, 0.3);\n n3 = rotate(n3, 0.3);\n total.x += valueNoiseR(n0) * amplitude;\n total.y += valueNoiseR(n1) * amplitude;\n total.z += valueNoiseR(n2) * amplitude;\n total.z += valueNoiseR(n3) * amplitude;\n n0 *= 1.99;\n n1 *= 1.99;\n n2 *= 1.99;\n n3 *= 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 const float firstFrameOffset = 7.;\n float t = .1 * (u_time + firstFrameOffset);\n\n vec2 shape_uv = vec2(0.);\n vec2 grain_uv = vec2(0.);\n\n float r = u_rotation * PI / 180.;\n float cr = cos(r);\n float sr = sin(r);\n mat2 graphicRotation = mat2(cr, sr, -sr, cr);\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\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 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 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(abs(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) * (1. - smoothstep(.45, .8, distance1 - n2));\n shape += smoothstep(.2, .55, distance2 + n2) * (1. - smoothstep(.45, .8, 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(max(d, 0.)));\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 baseNoise = snoise(grain_uv * .5);\n vec4 fbmVals = fbmR(\n .002 * grain_uv + 10.,\n .003 * grain_uv,\n .001 * grain_uv,\n rotate(.4 * grain_uv, 2.)\n );\n float grainDist = baseNoise * snoise(grain_uv * .2) - fbmVals.x - fbmVals.y;\n float rawNoise = .75 * baseNoise - fbmVals.w - fbmVals.z;\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 int cntStop = int(u_colorsCount) - 1;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ grainGradientMeta.maxColorCount }; i++) {\n if (i > cntStop) 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"],
+ "mappings": ";;;;;AAEA;AAAA,OAGO;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AACjB;AAmDO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAU1B,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBtD,SAAU;AAAA,EACV,YAAa;AAAA,EACb,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCnB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiLK,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0ClD,MAAM,sBAAsB;AAAA,EACjC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AACV;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts b/public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts
new file mode 100644
index 0000000..c77f09b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/halftone-cmyk.d.ts
@@ -0,0 +1,105 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * CMYK halftone printing effect applied to images with customizable dot patterns
+ * and ink colors for each channel (Cyan, Magenta, Yellow, Black).
+ *
+ * Fragment shader uniforms:
+ * - u_image (sampler2D): Source image texture
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorBack (vec4): Background (paper) color in RGBA
+ * - u_colorC (vec4): Cyan ink color in RGBA
+ * - u_colorM (vec4): Magenta ink color in RGBA
+ * - u_colorY (vec4): Yellow ink color in RGBA
+ * - u_colorK (vec4): Black ink color in RGBA
+ * - u_size (float): Halftone cell size (0 to 1)
+ * - u_minDot (float): Minimum dot thickness (0 to 1)
+ * - u_contrast (float): Image contrast adjustment (0 to 2)
+ * - u_softness (float): Edge softness of dots (0 to 1)
+ * - u_grainSize (float): Size of grain overlay texture (0 to 1)
+ * - u_grainMixer (float): Strength of grain affecting dot size (0 to 1)
+ * - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1)
+ * - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1)
+ * - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1)
+ * - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1)
+ * - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1)
+ * - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1)
+ * - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1)
+ * - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1)
+ * - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1)
+ * - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1)
+ * - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const halftoneCmykFragmentShader: string;
+export interface HalftoneCmykUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string | undefined;
+ u_noiseTexture?: HTMLImageElement;
+ u_colorBack: [number, number, number, number];
+ u_colorC: [number, number, number, number];
+ u_colorM: [number, number, number, number];
+ u_colorY: [number, number, number, number];
+ u_colorK: [number, number, number, number];
+ u_size: number;
+ u_contrast: number;
+ u_softness: number;
+ u_grainSize: number;
+ u_grainMixer: number;
+ u_grainOverlay: number;
+ u_gridNoise: number;
+ u_floodC: number;
+ u_floodM: number;
+ u_floodY: number;
+ u_floodK: number;
+ u_gainC: number;
+ u_gainM: number;
+ u_gainY: number;
+ u_gainK: number;
+ u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType];
+}
+export interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams {
+ image?: HTMLImageElement | string;
+ colorBack?: string;
+ colorC?: string;
+ colorM?: string;
+ colorY?: string;
+ colorK?: string;
+ size?: number;
+ contrast?: number;
+ softness?: number;
+ grainSize?: number;
+ grainMixer?: number;
+ grainOverlay?: number;
+ gridNoise?: number;
+ floodC?: number;
+ floodM?: number;
+ floodY?: number;
+ floodK?: number;
+ gainC?: number;
+ gainM?: number;
+ gainY?: number;
+ gainK?: number;
+ type?: HalftoneCmykType;
+}
+export declare const HalftoneCmykTypes: {
+ readonly dots: 0;
+ readonly ink: 1;
+ readonly sharp: 2;
+};
+export type HalftoneCmykType = keyof typeof HalftoneCmykTypes;
diff --git a/public/vendor/paper-shaders/shaders/halftone-cmyk.js b/public/vendor/paper-shaders/shaders/halftone-cmyk.js
new file mode 100644
index 0000000..e361a7c
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/halftone-cmyk.js
@@ -0,0 +1,292 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI } from "../shader-utils.js";
+const halftoneCmykFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorC;
+uniform vec4 u_colorM;
+uniform vec4 u_colorY;
+uniform vec4 u_colorK;
+uniform float u_size;
+uniform float u_minDot;
+uniform float u_contrast;
+uniform float u_grainSize;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+uniform float u_gridNoise;
+uniform float u_softness;
+uniform float u_floodC;
+uniform float u_floodM;
+uniform float u_floodY;
+uniform float u_floodK;
+uniform float u_gainC;
+uniform float u_gainM;
+uniform float u_gainY;
+uniform float u_gainK;
+uniform float u_type;
+uniform sampler2D u_noiseTexture;
+
+in vec2 v_imageUV;
+out vec4 fragColor;
+
+const float shiftC = -.5;
+const float shiftM = -.25;
+const float shiftY = .2;
+const float shiftK = 0.;
+
+// Precomputed sin/cos for rotation angles (15\xB0, 75\xB0, 0\xB0, 45\xB0)
+const float cosC = 0.9659258; const float sinC = 0.2588190; // 15\xB0
+const float cosM = 0.2588190; const float sinM = 0.9659258; // 75\xB0
+const float cosY = 1.0; const float sinY = 0.0; // 0\xB0
+const float cosK = 0.7071068; const float sinK = 0.7071068; // 45\xB0
+
+${declarePI}
+
+vec2 randomRG(vec2 p) {
+ vec2 uv = floor(p) / 100. + .5;
+ return texture(u_noiseTexture, fract(uv)).rg;
+}
+vec3 hash23(vec2 p) {
+ vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1;
+ p3 += dot(p3, p3.yzx + 19.19);
+ return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x));
+}
+
+float sst(float edge0, float edge1, float x) {
+ return smoothstep(edge0, edge1, x);
+}
+
+vec3 valueNoise3(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ vec3 a = hash23(i);
+ vec3 b = hash23(i + vec2(1.0, 0.0));
+ vec3 c = hash23(i + vec2(0.0, 1.0));
+ vec3 d = hash23(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ vec3 x1 = mix(a, b, u.x);
+ vec3 x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float getUvFrame(vec2 uv, vec2 pad) {
+ float left = smoothstep(-pad.x, 0., uv.x);
+ float right = smoothstep(1. + pad.x, 1., uv.x);
+ float bottom = smoothstep(-pad.y, 0., uv.y);
+ float top = smoothstep(1. + pad.y, 1., uv.y);
+
+ return left * right * bottom * top;
+}
+
+vec4 RGBAtoCMYK(vec4 rgba) {
+ float k = 1. - max(max(rgba.r, rgba.g), rgba.b);
+ float denom = 1. - k;
+ vec3 cmy = vec3(0.);
+ if (denom > 1e-5) {
+ cmy = (1. - rgba.rgb - vec3(k)) / denom;
+ }
+ return vec4(cmy, k) * rgba.a;
+}
+
+vec3 applyContrast(vec3 rgb) {
+ return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
+}
+
+// Single-component CMYK extractors with contrast built-in, alpha-aware
+float getCyan(vec4 rgba) {
+ vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
+ float maxRGB = max(max(c.r, c.g), c.b);
+ return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a;
+}
+float getMagenta(vec4 rgba) {
+ vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
+ float maxRGB = max(max(c.r, c.g), c.b);
+ return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a;
+}
+float getYellow(vec4 rgba) {
+ vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
+ float maxRGB = max(max(c.r, c.g), c.b);
+ return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a;
+}
+float getBlack(vec4 rgba) {
+ vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
+ return (1. - max(max(c.r, c.g), c.b)) * rgba.a;
+}
+
+vec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) {
+ vec2 cellCenter = floor(uv) + .5 + cellOffset;
+ return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise;
+}
+
+vec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) {
+ vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift);
+ return uvGrid * pad + 0.5;
+}
+
+void colorMask(vec2 pos, vec2 cellCenter, float rad, float transparency, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {
+ float dist = length(pos - cellCenter);
+
+ float radius = rad;
+ radius *= (1. + generalComp);
+ radius += (.15 + channelgain * radius);
+ radius = max(0., radius);
+ radius = mix(0., radius, transparency);
+ radius += channelAddon;
+ radius *= (1. - grain);
+
+ float mask = 1. - sst(0., radius, dist);
+ if (isJoined) {
+ // ink or sharp (joined)
+ mask = pow(mask, 1.2);
+ } else {
+ // dots (separate)
+ mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask);
+ }
+
+ mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness);
+ outMask += mask;
+}
+
+vec3 applyInk(vec3 paper, vec3 inkColor, float cov) {
+ vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0));
+ return paper * inkEffect;
+}
+
+void main() {
+ vec2 uv = v_imageUV;
+
+ float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7));
+ float cellSizeY = 1.0 / cellsPerSide;
+ vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);
+ vec2 uvGrid = (uv - .5) / pad;
+ float insideImageBox = getUvFrame(uv, pad);
+
+ float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);
+
+ vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC;
+ vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM;
+ vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY;
+ vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK;
+
+ vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);
+ vec2 grainUV = (v_imageUV - .5) * grainSize + .5;
+ vec3 noiseValues = valueNoise3(grainUV);
+ float grain = sst(.55, 1., noiseValues.r);
+ grain *= u_grainMixer;
+
+ vec4 outMask = vec4(0.);
+ bool isJoined = u_type > 0.5;
+
+ if (u_type < 1.5) {
+ // dots or ink: per-cell color sampling
+ for (int dy = -1; dy <= 1; dy++) {
+ for (int dx = -1; dx <= 1; dx++) {
+ vec2 cellOffset = vec2(float(dx), float(dy));
+
+ vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);
+ vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));
+ colorMask(uvC, cellCenterC, getCyan(texC), insideImageBox * texC.a, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);
+
+ vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);
+ vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));
+ colorMask(uvM, cellCenterM, getMagenta(texM), insideImageBox * texM.a, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);
+
+ vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);
+ vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));
+ colorMask(uvY, cellCenterY, getYellow(texY), insideImageBox * texY.a, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);
+
+ vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);
+ vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));
+ colorMask(uvK, cellCenterK, getBlack(texK), insideImageBox * texK.a, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);
+ }
+ }
+ } else {
+ // sharp: direct px color sampling
+ vec4 tex = texture(u_image, uv);
+ tex.rgb = applyContrast(tex.rgb);
+ insideImageBox *= tex.a;
+ vec4 cmykOriginal = RGBAtoCMYK(tex);
+ for (int dy = -1; dy <= 1; dy++) {
+ for (int dx = -1; dx <= 1; dx++) {
+ vec2 cellOffset = vec2(float(dx), float(dy));
+
+ colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, insideImageBox, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);
+ colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, insideImageBox, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);
+ colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, insideImageBox, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);
+ colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, insideImageBox, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);
+ }
+ }
+ }
+
+ float shape;
+
+ float C = outMask[0];
+ float M = outMask[1];
+ float Y = outMask[2];
+ float K = outMask[3];
+
+ if (isJoined) {
+ // ink or sharp: apply threshold for joined dots
+ float th = .5;
+ float sLeft = th * u_softness;
+ float sRight = (1. - th) * u_softness + .01;
+ C = smoothstep(th - sLeft - fwidth(C), th + sRight, C);
+ M = smoothstep(th - sLeft - fwidth(M), th + sRight, M);
+ Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y);
+ K = smoothstep(th - sLeft - fwidth(K), th + sRight, K);
+ }
+
+ C *= u_colorC.a;
+ M *= u_colorM.a;
+ Y *= u_colorY.a;
+ K *= u_colorK.a;
+
+ vec3 ink = vec3(1.);
+ ink = applyInk(ink, u_colorK.rgb, K);
+ ink = applyInk(ink, u_colorC.rgb, C);
+ ink = applyInk(ink, u_colorM.rgb, M);
+ ink = applyInk(ink, u_colorY.rgb, Y);
+
+ shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);
+
+ vec3 color = u_colorBack.rgb * u_colorBack.a;
+
+ float opacity = u_colorBack.a;
+ color = mix(color, ink, shape);
+ opacity += shape;
+ opacity = clamp(opacity, 0., 1.);
+
+ float grainOverlay = mix(noiseValues.g, noiseValues.b, .5);
+ grainOverlay = pow(grainOverlay, 1.3);
+
+ float grainOverlayV = grainOverlay * 2. - 1.;
+ vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
+ float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
+ grainOverlayStrength = pow(grainOverlayStrength, .8);
+ color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);
+
+ opacity += .5 * grainOverlayStrength;
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const HalftoneCmykTypes = {
+ dots: 0,
+ ink: 1,
+ sharp: 2
+};
+export {
+ HalftoneCmykTypes,
+ halftoneCmykFragmentShader
+};
+//# sourceMappingURL=halftone-cmyk.js.map
diff --git a/public/vendor/paper-shaders/shaders/halftone-cmyk.js.map b/public/vendor/paper-shaders/shaders/halftone-cmyk.js.map
new file mode 100644
index 0000000..3dc3d4e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/halftone-cmyk.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/halftone-cmyk.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI } from '../shader-utils.js';\n\n/**\n * CMYK halftone printing effect applied to images with customizable dot patterns\n * and ink colors for each channel (Cyan, Magenta, Yellow, Black).\n *\n * Fragment shader uniforms:\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background (paper) color in RGBA\n * - u_colorC (vec4): Cyan ink color in RGBA\n * - u_colorM (vec4): Magenta ink color in RGBA\n * - u_colorY (vec4): Yellow ink color in RGBA\n * - u_colorK (vec4): Black ink color in RGBA\n * - u_size (float): Halftone cell size (0 to 1)\n * - u_minDot (float): Minimum dot thickness (0 to 1)\n * - u_contrast (float): Image contrast adjustment (0 to 2)\n * - u_softness (float): Edge softness of dots (0 to 1)\n * - u_grainSize (float): Size of grain overlay texture (0 to 1)\n * - u_grainMixer (float): Strength of grain affecting dot size (0 to 1)\n * - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1)\n * - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1)\n * - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1)\n * - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1)\n * - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1)\n * - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1)\n * - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1)\n * - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1)\n * - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1)\n * - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1)\n * - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const halftoneCmykFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorC;\nuniform vec4 u_colorM;\nuniform vec4 u_colorY;\nuniform vec4 u_colorK;\nuniform float u_size;\nuniform float u_minDot;\nuniform float u_contrast;\nuniform float u_grainSize;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_gridNoise;\nuniform float u_softness;\nuniform float u_floodC;\nuniform float u_floodM;\nuniform float u_floodY;\nuniform float u_floodK;\nuniform float u_gainC;\nuniform float u_gainM;\nuniform float u_gainY;\nuniform float u_gainK;\nuniform float u_type;\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_imageUV;\nout vec4 fragColor;\n\nconst float shiftC = -.5;\nconst float shiftM = -.25;\nconst float shiftY = .2;\nconst float shiftK = 0.;\n\n// Precomputed sin/cos for rotation angles (15\u00B0, 75\u00B0, 0\u00B0, 45\u00B0)\nconst float cosC = 0.9659258; const float sinC = 0.2588190; // 15\u00B0\nconst float cosM = 0.2588190; const float sinM = 0.9659258; // 75\u00B0\nconst float cosY = 1.0; const float sinY = 0.0; // 0\u00B0\nconst float cosK = 0.7071068; const float sinK = 0.7071068; // 45\u00B0\n\n${ declarePI }\n\nvec2 randomRG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).rg;\n}\nvec3 hash23(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1;\n p3 += dot(p3, p3.yzx + 19.19);\n return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x));\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nvec3 valueNoise3(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n vec3 a = hash23(i);\n vec3 b = hash23(i + vec2(1.0, 0.0));\n vec3 c = hash23(i + vec2(0.0, 1.0));\n vec3 d = hash23(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n vec3 x1 = mix(a, b, u.x);\n vec3 x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float left = smoothstep(-pad.x, 0., uv.x);\n float right = smoothstep(1. + pad.x, 1., uv.x);\n float bottom = smoothstep(-pad.y, 0., uv.y);\n float top = smoothstep(1. + pad.y, 1., uv.y);\n\n return left * right * bottom * top;\n}\n\nvec4 RGBAtoCMYK(vec4 rgba) {\n float k = 1. - max(max(rgba.r, rgba.g), rgba.b);\n float denom = 1. - k;\n vec3 cmy = vec3(0.);\n if (denom > 1e-5) {\n cmy = (1. - rgba.rgb - vec3(k)) / denom;\n }\n return vec4(cmy, k) * rgba.a;\n}\n\nvec3 applyContrast(vec3 rgb) {\n return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n}\n\n// Single-component CMYK extractors with contrast built-in, alpha-aware\nfloat getCyan(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a;\n}\nfloat getMagenta(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a;\n}\nfloat getYellow(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a;\n}\nfloat getBlack(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n return (1. - max(max(c.r, c.g), c.b)) * rgba.a;\n}\n\nvec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) {\n vec2 cellCenter = floor(uv) + .5 + cellOffset;\n return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise;\n}\n\nvec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) {\n vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift);\n return uvGrid * pad + 0.5;\n}\n\nvoid colorMask(vec2 pos, vec2 cellCenter, float rad, float transparency, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {\n float dist = length(pos - cellCenter);\n\n float radius = rad;\n radius *= (1. + generalComp);\n radius += (.15 + channelgain * radius);\n radius = max(0., radius);\n radius = mix(0., radius, transparency);\n radius += channelAddon;\n radius *= (1. - grain);\n\n float mask = 1. - sst(0., radius, dist);\n if (isJoined) {\n // ink or sharp (joined)\n mask = pow(mask, 1.2);\n } else {\n // dots (separate)\n mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask);\n }\n\n mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness);\n outMask += mask;\n}\n\nvec3 applyInk(vec3 paper, vec3 inkColor, float cov) {\n vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0));\n return paper * inkEffect;\n}\n\nvoid main() {\n vec2 uv = v_imageUV;\n\n float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7));\n float cellSizeY = 1.0 / cellsPerSide;\n vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);\n vec2 uvGrid = (uv - .5) / pad;\n float insideImageBox = getUvFrame(uv, pad);\n\n float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);\n\n vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC;\n vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM;\n vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY;\n vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK;\n\n vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);\n vec2 grainUV = (v_imageUV - .5) * grainSize + .5;\n vec3 noiseValues = valueNoise3(grainUV);\n float grain = sst(.55, 1., noiseValues.r);\n grain *= u_grainMixer;\n\n vec4 outMask = vec4(0.);\n bool isJoined = u_type > 0.5;\n\n if (u_type < 1.5) {\n // dots or ink: per-cell color sampling\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);\n vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));\n colorMask(uvC, cellCenterC, getCyan(texC), insideImageBox * texC.a, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n\n vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);\n vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));\n colorMask(uvM, cellCenterM, getMagenta(texM), insideImageBox * texM.a, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n\n vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);\n vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));\n colorMask(uvY, cellCenterY, getYellow(texY), insideImageBox * texY.a, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n\n vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);\n vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));\n colorMask(uvK, cellCenterK, getBlack(texK), insideImageBox * texK.a, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n } else {\n // sharp: direct px color sampling\n vec4 tex = texture(u_image, uv);\n tex.rgb = applyContrast(tex.rgb);\n insideImageBox *= tex.a;\n vec4 cmykOriginal = RGBAtoCMYK(tex);\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, insideImageBox, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, insideImageBox, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, insideImageBox, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, insideImageBox, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n }\n\n float shape;\n\n float C = outMask[0];\n float M = outMask[1];\n float Y = outMask[2];\n float K = outMask[3];\n\n if (isJoined) {\n // ink or sharp: apply threshold for joined dots\n float th = .5;\n float sLeft = th * u_softness;\n float sRight = (1. - th) * u_softness + .01;\n C = smoothstep(th - sLeft - fwidth(C), th + sRight, C);\n M = smoothstep(th - sLeft - fwidth(M), th + sRight, M);\n Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y);\n K = smoothstep(th - sLeft - fwidth(K), th + sRight, K);\n }\n\n C *= u_colorC.a;\n M *= u_colorM.a;\n Y *= u_colorY.a;\n K *= u_colorK.a;\n\n vec3 ink = vec3(1.);\n ink = applyInk(ink, u_colorK.rgb, K);\n ink = applyInk(ink, u_colorC.rgb, C);\n ink = applyInk(ink, u_colorM.rgb, M);\n ink = applyInk(ink, u_colorY.rgb, Y);\n\n shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);\n\n vec3 color = u_colorBack.rgb * u_colorBack.a;\n\n float opacity = u_colorBack.a;\n color = mix(color, ink, shape);\n opacity += shape;\n opacity = clamp(opacity, 0., 1.);\n\n float grainOverlay = mix(noiseValues.g, noiseValues.b, .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface HalftoneCmykUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorBack: [number, number, number, number];\n u_colorC: [number, number, number, number];\n u_colorM: [number, number, number, number];\n u_colorY: [number, number, number, number];\n u_colorK: [number, number, number, number];\n u_size: number;\n u_contrast: number;\n u_softness: number;\n u_grainSize: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_gridNoise: number;\n u_floodC: number;\n u_floodM: number;\n u_floodY: number;\n u_floodK: number;\n u_gainC: number;\n u_gainM: number;\n u_gainY: number;\n u_gainK: number;\n u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType];\n}\n\nexport interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorC?: string;\n colorM?: string;\n colorY?: string;\n colorK?: string;\n size?: number;\n contrast?: number;\n softness?: number;\n grainSize?: number;\n grainMixer?: number;\n grainOverlay?: number;\n gridNoise?: number;\n floodC?: number;\n floodM?: number;\n floodY?: number;\n floodK?: number;\n gainC?: number;\n gainM?: number;\n gainY?: number;\n gainK?: number;\n type?: HalftoneCmykType;\n}\n\nexport const HalftoneCmykTypes = {\n dots: 0,\n ink: 1,\n sharp: 2,\n} as const;\n\nexport type HalftoneCmykType = keyof typeof HalftoneCmykTypes;\n\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,iBAAiB;AAmDnB,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4C/C,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2RN,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AACT;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/halftone-dots.d.ts b/public/vendor/paper-shaders/shaders/halftone-dots.d.ts
new file mode 100644
index 0000000..24f6a95
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/halftone-dots.d.ts
@@ -0,0 +1,82 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * A halftone-dot image filter featuring customizable grids, color palettes, and dot styles.
+ *
+ * Fragment shader uniforms:
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_time (float): Animation time
+ * - u_image (sampler2D): Source image texture
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorFront (vec4): Foreground color in RGBA
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_originalColors (bool): Use sampled image's original colors instead of colorFront
+ * - u_type (float): Dot style (0 = classic, 1 = gooey, 2 = holes, 3 = soft)
+ * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast
+ * - u_grid (float): Grid type (0 = square, 1 = hex)
+ * - u_size (float): Grid size relative to the image box (0 to 1)
+ * - u_radius (float): Maximum dot size relative to grid cell (0 to 2)
+ * - u_contrast (float): Contrast applied to the sampled image (0 to 1)
+ * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)
+ * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
+ * - u_grainSize (float): Scale applied to both grain distortion and grain overlay (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const halftoneDotsFragmentShader: string;
+export interface HalftoneDotsUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string | undefined;
+ u_colorFront: [number, number, number, number];
+ u_colorBack: [number, number, number, number];
+ u_size: number;
+ u_grid: (typeof HalftoneDotsGrids)[HalftoneDotsGrid];
+ u_radius: number;
+ u_contrast: number;
+ u_originalColors: boolean;
+ u_inverted: boolean;
+ u_grainMixer: number;
+ u_grainOverlay: number;
+ u_grainSize: number;
+ u_type: (typeof HalftoneDotsTypes)[HalftoneDotsType];
+}
+export interface HalftoneDotsParams extends ShaderSizingParams, ShaderMotionParams {
+ image?: HTMLImageElement | string;
+ colorFront?: string;
+ colorBack?: string;
+ size?: number;
+ grid?: HalftoneDotsGrid;
+ radius?: number;
+ contrast?: number;
+ originalColors?: boolean;
+ inverted?: boolean;
+ grainMixer?: number;
+ grainOverlay?: number;
+ grainSize?: number;
+ type?: HalftoneDotsType;
+}
+export declare const HalftoneDotsTypes: {
+ readonly classic: 0;
+ readonly gooey: 1;
+ readonly holes: 2;
+ readonly soft: 3;
+};
+export type HalftoneDotsType = keyof typeof HalftoneDotsTypes;
+export declare const HalftoneDotsGrids: {
+ readonly square: 0;
+ readonly hex: 1;
+};
+export type HalftoneDotsGrid = keyof typeof HalftoneDotsGrids;
diff --git a/public/vendor/paper-shaders/shaders/halftone-dots.js b/public/vendor/paper-shaders/shaders/halftone-dots.js
new file mode 100644
index 0000000..ffdedcf
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/halftone-dots.js
@@ -0,0 +1,321 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
+const halftoneDotsFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_rotation;
+
+uniform float u_time;
+
+uniform vec4 u_colorFront;
+uniform vec4 u_colorBack;
+uniform float u_radius;
+uniform float u_contrast;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform float u_size;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+uniform float u_grainSize;
+uniform float u_grid;
+uniform bool u_originalColors;
+uniform bool u_inverted;
+uniform float u_type;
+
+in vec2 v_imageUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${proceduralHash21}
+
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = hash21(i);
+ float b = hash21(i + vec2(1.0, 0.0));
+ float c = hash21(i + vec2(0.0, 1.0));
+ float d = hash21(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float lst(float edge0, float edge1, float x) {
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+}
+
+float sst(float edge0, float edge1, float x) {
+ return smoothstep(edge0, edge1, x);
+}
+
+float getCircle(vec2 uv, float r, float baseR) {
+ r = mix(.25 * baseR, 0., r);
+ float d = length(uv - .5);
+ float aa = fwidth(d);
+ return 1. - smoothstep(r - aa, r + aa, d);
+}
+
+float getCell(vec2 uv) {
+ float insideX = step(0.0, uv.x) * (1.0 - step(1.0, uv.x));
+ float insideY = step(0.0, uv.y) * (1.0 - step(1.0, uv.y));
+ return insideX * insideY;
+}
+
+float getCircleWithHole(vec2 uv, float r, float baseR) {
+ float cell = getCell(uv);
+
+ r = mix(.75 * baseR, 0., r);
+ float rMod = mod(r, .5);
+
+ float d = length(uv - .5);
+ float aa = fwidth(d);
+ float circle = 1. - smoothstep(rMod - aa, rMod + aa, d);
+ if (r < .5) {
+ return circle;
+ } else {
+ return cell - circle;
+ }
+}
+
+float getGooeyBall(vec2 uv, float r, float baseR) {
+ float d = length(uv - .5);
+ float sizeRadius = .3;
+ if (u_grid == 1.) {
+ sizeRadius = .42;
+ }
+ sizeRadius = mix(sizeRadius * baseR, 0., r);
+ d = 1. - sst(0., sizeRadius, d);
+
+ d = pow(d, 2. + baseR);
+ return d;
+}
+
+float getSoftBall(vec2 uv, float r, float baseR) {
+ float d = length(uv - .5);
+ float sizeRadius = clamp(baseR, 0., 1.);
+ sizeRadius = mix(.5 * sizeRadius, 0., r);
+ d = 1. - lst(0., sizeRadius, d);
+ float powRadius = 1. - lst(0., 2., baseR);
+ d = pow(d, 4. + 3. * powRadius);
+ return d;
+}
+
+float getUvFrame(vec2 uv, vec2 pad) {
+ float aa = 0.0001;
+
+ float left = smoothstep(-pad.x, -pad.x + aa, uv.x);
+ float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);
+ float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);
+ float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);
+
+ return left * right * bottom * top;
+}
+
+float sigmoid(float x, float k) {
+ return 1.0 / (1.0 + exp(-k * (x - 0.5)));
+}
+
+float getLumAtPx(vec2 uv, float contrast) {
+ vec4 tex = texture(u_image, uv);
+ vec3 color = vec3(
+ sigmoid(tex.r, contrast),
+ sigmoid(tex.g, contrast),
+ sigmoid(tex.b, contrast)
+ );
+ float lum = dot(vec3(0.2126, 0.7152, 0.0722), color);
+ lum = mix(1., lum, tex.a);
+ lum = u_inverted ? (1. - lum) : lum;
+ return lum;
+}
+
+float getLumBall(vec2 p, vec2 pad, vec2 inCellOffset, float contrast, float baseR, float stepSize, out vec4 ballColor) {
+ p += inCellOffset;
+ vec2 uv_i = floor(p);
+ vec2 uv_f = fract(p);
+ vec2 samplingUV = (uv_i + .5 - inCellOffset) * pad + vec2(.5);
+ float outOfFrame = getUvFrame(samplingUV, pad * stepSize);
+
+ float lum = getLumAtPx(samplingUV, contrast);
+ ballColor = texture(u_image, samplingUV);
+ ballColor.rgb *= ballColor.a;
+ ballColor *= outOfFrame;
+
+ float ball = 0.;
+ if (u_type == 0.) {
+ // classic
+ ball = getCircle(uv_f, lum, baseR);
+ } else if (u_type == 1.) {
+ // gooey
+ ball = getGooeyBall(uv_f, lum, baseR);
+ } else if (u_type == 2.) {
+ // holes
+ ball = getCircleWithHole(uv_f, lum, baseR);
+ } else if (u_type == 3.) {
+ // soft
+ ball = getSoftBall(uv_f, lum, baseR);
+ }
+
+ return ball * outOfFrame;
+}
+
+
+void main() {
+
+ float stepMultiplier = 1.;
+ if (u_type == 0.) {
+ // classic
+ stepMultiplier = 2.;
+ } else if (u_type == 1. || u_type == 3.) {
+ // gooey & soft
+ stepMultiplier = 6.;
+ }
+
+ float cellsPerSide = mix(300., 7., pow(u_size, .7));
+ cellsPerSide /= stepMultiplier;
+ float cellSizeY = 1. / cellsPerSide;
+ vec2 pad = cellSizeY * vec2(1. / u_imageAspectRatio, 1.);
+ if (u_type == 1. && u_grid == 1.) {
+ // gooey diagonal grid works differently
+ pad *= .7;
+ }
+
+ vec2 uv = v_imageUV;
+ uv -= vec2(.5);
+ uv /= pad;
+
+ float contrast = mix(0., 15., pow(u_contrast, 1.5));
+ float baseRadius = u_radius;
+ if (u_originalColors == true) {
+ contrast = mix(.1, 4., pow(u_contrast, 2.));
+ baseRadius = 2. * pow(.5 * u_radius, .3);
+ }
+
+ float totalShape = 0.;
+ vec3 totalColor = vec3(0.);
+ float totalOpacity = 0.;
+
+ vec4 ballColor;
+ float shape;
+ float stepSize = 1. / stepMultiplier;
+ for (float x = -0.5; x < 0.5; x += stepSize) {
+ for (float y = -0.5; y < 0.5; y += stepSize) {
+ vec2 offset = vec2(x, y);
+
+ if (u_grid == 1.) {
+ float rowIndex = floor((y + .5) / stepSize);
+ float colIndex = floor((x + .5) / stepSize);
+ if (stepSize == 1.) {
+ rowIndex = floor(uv.y + y + 1.);
+ if (u_type == 1.) {
+ colIndex = floor(uv.x + x + 1.);
+ }
+ }
+ if (u_type == 1.) {
+ if (mod(rowIndex + colIndex, 2.) == 1.) {
+ continue;
+ }
+ } else {
+ if (mod(rowIndex, 2.) == 1.) {
+ offset.x += .5 * stepSize;
+ }
+ }
+ }
+
+ shape = getLumBall(uv, pad, offset, contrast, baseRadius, stepSize, ballColor);
+ totalColor += ballColor.rgb * shape;
+ totalShape += shape;
+ totalOpacity += shape;
+ }
+ }
+
+ const float eps = 1e-4;
+
+ totalColor /= max(totalShape, eps);
+ totalOpacity /= max(totalShape, eps);
+
+ float finalShape = 0.;
+ if (u_type == 0.) {
+ finalShape = min(1., totalShape);
+ } else if (u_type == 1.) {
+ float aa = fwidth(totalShape);
+ float th = .5;
+ finalShape = smoothstep(th - aa, th + aa, totalShape);
+ } else if (u_type == 2.) {
+ finalShape = min(1., totalShape);
+ } else if (u_type == 3.) {
+ finalShape = totalShape;
+ }
+
+ vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);
+ vec2 grainUV = v_imageUV - .5;
+ grainUV *= grainSize;
+ grainUV += .5;
+ float grain = valueNoise(grainUV);
+ grain = smoothstep(.55, .7 + .2 * u_grainMixer, grain);
+ grain *= u_grainMixer;
+ finalShape = mix(finalShape, 0., grain);
+
+ vec3 color = vec3(0.);
+ float opacity = 0.;
+
+ if (u_originalColors == true) {
+ color = totalColor * finalShape;
+ opacity = totalOpacity * finalShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1. - opacity);
+ opacity = opacity + u_colorBack.a * (1. - opacity);
+ } else {
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+
+ color = fgColor * finalShape;
+ opacity = fgOpacity * finalShape;
+ color += bgColor * (1. - opacity);
+ opacity += bgOpacity * (1. - opacity);
+ }
+
+ float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));
+ grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
+ grainOverlay = pow(grainOverlay, 1.3);
+
+ float grainOverlayV = grainOverlay * 2. - 1.;
+ vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
+ float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
+ grainOverlayStrength = pow(grainOverlayStrength, .8);
+ color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);
+
+ opacity += .5 * grainOverlayStrength;
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const HalftoneDotsTypes = {
+ classic: 0,
+ gooey: 1,
+ holes: 2,
+ soft: 3
+};
+const HalftoneDotsGrids = {
+ square: 0,
+ hex: 1
+};
+export {
+ HalftoneDotsGrids,
+ HalftoneDotsTypes,
+ halftoneDotsFragmentShader
+};
+//# sourceMappingURL=halftone-dots.js.map
diff --git a/public/vendor/paper-shaders/shaders/halftone-dots.js.map b/public/vendor/paper-shaders/shaders/halftone-dots.js.map
new file mode 100644
index 0000000..1d1a973
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/halftone-dots.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/halftone-dots.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * A halftone-dot image filter featuring customizable grids, color palettes, and dot styles.\n *\n * Fragment shader uniforms:\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_time (float): Animation time\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_originalColors (bool): Use sampled image's original colors instead of colorFront\n * - u_type (float): Dot style (0 = classic, 1 = gooey, 2 = holes, 3 = soft)\n * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast\n * - u_grid (float): Grid type (0 = square, 1 = hex)\n * - u_size (float): Grid size relative to the image box (0 to 1)\n * - u_radius (float): Maximum dot size relative to grid cell (0 to 2)\n * - u_contrast (float): Contrast applied to the sampled image (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n * - u_grainSize (float): Scale applied to both grain distortion and grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const halftoneDotsFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_rotation;\n\nuniform float u_time;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform float u_radius;\nuniform float u_contrast;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_size;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_grainSize;\nuniform float u_grid;\nuniform bool u_originalColors;\nuniform bool u_inverted;\nuniform float u_type;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(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 lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nfloat getCircle(vec2 uv, float r, float baseR) {\n r = mix(.25 * baseR, 0., r);\n float d = length(uv - .5);\n float aa = fwidth(d);\n return 1. - smoothstep(r - aa, r + aa, d);\n}\n\nfloat getCell(vec2 uv) {\n float insideX = step(0.0, uv.x) * (1.0 - step(1.0, uv.x));\n float insideY = step(0.0, uv.y) * (1.0 - step(1.0, uv.y));\n return insideX * insideY;\n}\n\nfloat getCircleWithHole(vec2 uv, float r, float baseR) {\n float cell = getCell(uv);\n\n r = mix(.75 * baseR, 0., r);\n float rMod = mod(r, .5);\n\n float d = length(uv - .5);\n float aa = fwidth(d);\n float circle = 1. - smoothstep(rMod - aa, rMod + aa, d);\n if (r < .5) {\n return circle;\n } else {\n return cell - circle;\n }\n}\n\nfloat getGooeyBall(vec2 uv, float r, float baseR) {\n float d = length(uv - .5);\n float sizeRadius = .3;\n if (u_grid == 1.) {\n sizeRadius = .42;\n }\n sizeRadius = mix(sizeRadius * baseR, 0., r);\n d = 1. - sst(0., sizeRadius, d);\n\n d = pow(d, 2. + baseR);\n return d;\n}\n\nfloat getSoftBall(vec2 uv, float r, float baseR) {\n float d = length(uv - .5);\n float sizeRadius = clamp(baseR, 0., 1.);\n sizeRadius = mix(.5 * sizeRadius, 0., r);\n d = 1. - lst(0., sizeRadius, d);\n float powRadius = 1. - lst(0., 2., baseR);\n d = pow(d, 4. + 3. * powRadius);\n return d;\n}\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float aa = 0.0001;\n\n float left = smoothstep(-pad.x, -pad.x + aa, uv.x);\n float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);\n float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);\n float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);\n\n return left * right * bottom * top;\n}\n\nfloat sigmoid(float x, float k) {\n return 1.0 / (1.0 + exp(-k * (x - 0.5)));\n}\n\nfloat getLumAtPx(vec2 uv, float contrast) {\n vec4 tex = texture(u_image, uv);\n vec3 color = vec3(\n sigmoid(tex.r, contrast),\n sigmoid(tex.g, contrast),\n sigmoid(tex.b, contrast)\n );\n float lum = dot(vec3(0.2126, 0.7152, 0.0722), color);\n lum = mix(1., lum, tex.a);\n lum = u_inverted ? (1. - lum) : lum;\n return lum;\n}\n\nfloat getLumBall(vec2 p, vec2 pad, vec2 inCellOffset, float contrast, float baseR, float stepSize, out vec4 ballColor) {\n p += inCellOffset;\n vec2 uv_i = floor(p);\n vec2 uv_f = fract(p);\n vec2 samplingUV = (uv_i + .5 - inCellOffset) * pad + vec2(.5);\n float outOfFrame = getUvFrame(samplingUV, pad * stepSize);\n\n float lum = getLumAtPx(samplingUV, contrast);\n ballColor = texture(u_image, samplingUV);\n ballColor.rgb *= ballColor.a;\n ballColor *= outOfFrame;\n\n float ball = 0.;\n if (u_type == 0.) {\n // classic\n ball = getCircle(uv_f, lum, baseR);\n } else if (u_type == 1.) {\n // gooey\n ball = getGooeyBall(uv_f, lum, baseR);\n } else if (u_type == 2.) {\n // holes\n ball = getCircleWithHole(uv_f, lum, baseR);\n } else if (u_type == 3.) {\n // soft\n ball = getSoftBall(uv_f, lum, baseR);\n }\n\n return ball * outOfFrame;\n}\n\n\nvoid main() {\n\n float stepMultiplier = 1.;\n if (u_type == 0.) {\n // classic\n stepMultiplier = 2.;\n } else if (u_type == 1. || u_type == 3.) {\n // gooey & soft\n stepMultiplier = 6.;\n }\n\n float cellsPerSide = mix(300., 7., pow(u_size, .7));\n cellsPerSide /= stepMultiplier;\n float cellSizeY = 1. / cellsPerSide;\n vec2 pad = cellSizeY * vec2(1. / u_imageAspectRatio, 1.);\n if (u_type == 1. && u_grid == 1.) {\n // gooey diagonal grid works differently\n pad *= .7;\n }\n\n vec2 uv = v_imageUV;\n uv -= vec2(.5);\n uv /= pad;\n\n float contrast = mix(0., 15., pow(u_contrast, 1.5));\n float baseRadius = u_radius;\n if (u_originalColors == true) {\n contrast = mix(.1, 4., pow(u_contrast, 2.));\n baseRadius = 2. * pow(.5 * u_radius, .3);\n }\n\n float totalShape = 0.;\n vec3 totalColor = vec3(0.);\n float totalOpacity = 0.;\n\n vec4 ballColor;\n float shape;\n float stepSize = 1. / stepMultiplier;\n for (float x = -0.5; x < 0.5; x += stepSize) {\n for (float y = -0.5; y < 0.5; y += stepSize) {\n vec2 offset = vec2(x, y);\n\n if (u_grid == 1.) {\n float rowIndex = floor((y + .5) / stepSize);\n float colIndex = floor((x + .5) / stepSize);\n if (stepSize == 1.) {\n rowIndex = floor(uv.y + y + 1.);\n if (u_type == 1.) {\n colIndex = floor(uv.x + x + 1.);\n }\n }\n if (u_type == 1.) {\n if (mod(rowIndex + colIndex, 2.) == 1.) {\n continue;\n }\n } else {\n if (mod(rowIndex, 2.) == 1.) {\n offset.x += .5 * stepSize;\n }\n }\n }\n\n shape = getLumBall(uv, pad, offset, contrast, baseRadius, stepSize, ballColor);\n totalColor += ballColor.rgb * shape;\n totalShape += shape;\n totalOpacity += shape;\n }\n }\n\n const float eps = 1e-4;\n\n totalColor /= max(totalShape, eps);\n totalOpacity /= max(totalShape, eps);\n\n float finalShape = 0.;\n if (u_type == 0.) {\n finalShape = min(1., totalShape);\n } else if (u_type == 1.) {\n float aa = fwidth(totalShape);\n float th = .5;\n finalShape = smoothstep(th - aa, th + aa, totalShape);\n } else if (u_type == 2.) {\n finalShape = min(1., totalShape);\n } else if (u_type == 3.) {\n finalShape = totalShape;\n }\n\n vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);\n vec2 grainUV = v_imageUV - .5;\n grainUV *= grainSize;\n grainUV += .5;\n float grain = valueNoise(grainUV);\n grain = smoothstep(.55, .7 + .2 * u_grainMixer, grain);\n grain *= u_grainMixer;\n finalShape = mix(finalShape, 0., grain);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n\n if (u_originalColors == true) {\n color = totalColor * finalShape;\n opacity = totalOpacity * finalShape;\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 } else {\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 color = fgColor * finalShape;\n opacity = fgOpacity * finalShape;\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n }\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface HalftoneDotsUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_size: number;\n u_grid: (typeof HalftoneDotsGrids)[HalftoneDotsGrid];\n u_radius: number;\n u_contrast: number;\n u_originalColors: boolean;\n u_inverted: boolean;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_grainSize: number;\n u_type: (typeof HalftoneDotsTypes)[HalftoneDotsType];\n}\n\nexport interface HalftoneDotsParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n size?: number;\n grid?: HalftoneDotsGrid;\n radius?: number;\n contrast?: number;\n originalColors?: boolean;\n inverted?: boolean;\n grainMixer?: number;\n grainOverlay?: number;\n grainSize?: number;\n type?: HalftoneDotsType;\n}\n\nexport const HalftoneDotsTypes = {\n classic: 0,\n gooey: 1,\n holes: 2,\n soft: 3,\n} as const;\n\nexport type HalftoneDotsType = keyof typeof HalftoneDotsTypes;\n\nexport const HalftoneDotsGrids = {\n square: 0,\n hex: 1,\n} as const;\n\nexport type HalftoneDotsGrid = keyof typeof HalftoneDotsGrids;\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,wBAAwB;AAyChD,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;AAAA,EA4B/C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6Sb,MAAM,oBAAoB;AAAA,EAC/B,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AACR;AAIO,MAAM,oBAAoB;AAAA,EAC/B,QAAQ;AAAA,EACR,KAAK;AACP;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/heatmap.d.ts b/public/vendor/paper-shaders/shaders/heatmap.d.ts
new file mode 100644
index 0000000..0e8b624
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/heatmap.d.ts
@@ -0,0 +1,67 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const heatmapMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * A glowing gradient of colors flowing through an input shape.
+ * The effect creates a smoothly animated wave of intensity across the image.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_image (sampler2D): Pre-processed source image texture (R = contour, G = outer blur, B = inner blur)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 10 heatmap colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_contour (float): Heat intensity near the edges of the input shape (0 to 1)
+ * - u_angle (float): Direction of the heatwaves in degrees (0 to 360)
+ * - u_noise (float): Grain applied across the entire graphic (0 to 1)
+ * - u_innerGlow (float): Size of the heated area inside the input shape (0 to 1)
+ * - u_outerGlow (float): Size of the heated area outside the input shape (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const heatmapFragmentShader: string;
+export declare function toProcessedHeatmap(file: File | string): Promise<{
+ blob: Blob;
+}>;
+export interface HeatmapUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string;
+ u_contour: number;
+ u_angle: number;
+ u_noise: number;
+ u_innerGlow: number;
+ u_outerGlow: number;
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+}
+export interface HeatmapParams extends ShaderSizingParams, ShaderMotionParams {
+ image: HTMLImageElement | string;
+ contour?: number;
+ angle?: number;
+ noise?: number;
+ innerGlow?: number;
+ outerGlow?: number;
+ colorBack?: string;
+ colors?: string[];
+}
diff --git a/public/vendor/paper-shaders/shaders/heatmap.js b/public/vendor/paper-shaders/shaders/heatmap.js
new file mode 100644
index 0000000..2e2441b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/heatmap.js
@@ -0,0 +1,385 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+const heatmapMeta = {
+ maxColorCount: 10
+};
+const heatmapFragmentShader = `#version 300 es
+precision highp float;
+
+in mediump vec2 v_imageUV;
+in mediump vec2 v_objectUV;
+out vec4 fragColor;
+
+uniform sampler2D u_image;
+uniform float u_time;
+uniform mediump float u_imageAspectRatio;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${heatmapMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_angle;
+uniform float u_noise;
+uniform float u_innerGlow;
+uniform float u_outerGlow;
+uniform float u_contour;
+
+#define TWO_PI 6.28318530718
+#define PI 3.14159265358979323846
+
+float getImgFrame(vec2 uv, float th) {
+ float frame = 1.;
+ frame *= smoothstep(0., th, uv.y);
+ frame *= 1. - smoothstep(1. - th, 1., uv.y);
+ frame *= smoothstep(0., th, uv.x);
+ frame *= 1. - smoothstep(1. - th, 1., uv.x);
+ return frame;
+}
+
+float circle(vec2 uv, vec2 c, vec2 r) {
+ return 1. - smoothstep(r[0], r[1], length(uv - c));
+}
+
+float lst(float edge0, float edge1, float x) {
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+}
+
+float sst(float edge0, float edge1, float x) {
+ return smoothstep(edge0, edge1, x);
+}
+
+float shadowShape(vec2 uv, float t, float contour) {
+ vec2 scaledUV = uv;
+
+ // base shape tranjectory
+ float posY = mix(-1., 2., t);
+
+ // scaleX when it's moving down
+ scaledUV.y -= .5;
+ float mainCircleScale = sst(0., .8, posY) * lst(1.4, .9, posY);
+ scaledUV *= vec2(1., 1. + 1.5 * mainCircleScale);
+ scaledUV.y += .5;
+
+ // base shape
+ float innerR = .4;
+ float outerR = 1. - .3 * (sst(.1, .2, t) * (1. - sst(.2, .5, t)));
+ float s = circle(scaledUV, vec2(.5, posY - .2), vec2(innerR, outerR));
+ float shapeSizing = sst(.2, .3, t) * sst(.6, .3, t);
+ s = pow(s, 1.4);
+ s *= 1.2;
+
+ // flat gradient to take over the shadow shape
+ float topFlattener = 0.;
+ {
+ float pos = posY - uv.y;
+ float edge = 1.2;
+ topFlattener = lst(-.4, 0., pos) * (1. - sst(.0, edge, pos));
+ topFlattener = pow(topFlattener, 3.);
+ float topFlattenerMixer = (1. - sst(.0, .3, pos));
+ s = mix(topFlattener, s, topFlattenerMixer);
+ }
+
+ // apple right circle
+ {
+ float visibility = sst(.6, .7, t) * (1. - sst(.8, .9, t));
+ float angle = -2. -t * TWO_PI;
+ float rightCircle = circle(uv, vec2(.95 - .2 * cos(angle), .4 - .1 * sin(angle)), vec2(.15, .3));
+ rightCircle *= visibility;
+ s = mix(s, 0., rightCircle);
+ }
+
+ // apple top circle
+ {
+ float topCircle = circle(uv, vec2(.5, .19), vec2(.05, .25));
+ topCircle += 2. * contour * circle(uv, vec2(.5, .19), vec2(.2, .5));
+ float visibility = .55 * sst(.2, .3, t) * (1. - sst(.3, .45, t));
+ topCircle *= visibility;
+ s = mix(s, 0., topCircle);
+ }
+
+ float leafMask = circle(uv, vec2(.53, .13), vec2(.08, .19));
+ leafMask = mix(leafMask, 0., 1. - sst(.4, .54, uv.x));
+ leafMask = mix(0., leafMask, sst(.0, .2, uv.y));
+ leafMask *= (sst(.5, 1.1, posY) * sst(1.5, 1.3, posY));
+ s += leafMask;
+
+ // apple bottom circle
+ {
+ float visibility = sst(.0, .4, t) * (1. - sst(.6, .8, t));
+ s = mix(s, 0., visibility * circle(uv, vec2(.52, .92), vec2(.09, .25)));
+ }
+
+ // random balls that are invisible if apple logo is selected
+ {
+ float pos = sst(.0, .6, t) * (1. - sst(.6, 1., t));
+ s = mix(s, .5, circle(uv, vec2(.0, 1.2 - .5 * pos), vec2(.1, .3)));
+ s = mix(s, .0, circle(uv, vec2(1., .5 + .5 * pos), vec2(.1, .3)));
+
+ s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * sst(.7, .5, t)), vec2(.07, .22)));
+ s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * (1. - sst(.5, .7, t))), vec2(.07, .22)));
+ s /= max(1e-4, sst(1., .85, uv.y));
+ }
+
+ s = clamp(0., 1., s);
+ return s;
+}
+
+float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {
+ vec2 texel = 1.0 / vec2(textureSize(tex, 0));
+ vec2 r = radius * texel;
+
+ float w1 = 1.0, w2 = 2.0, w4 = 4.0;
+ float norm = 16.0;
+ float sum = w4 * centerSample;
+
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).g;
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).g;
+ sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).g;
+ sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).g;
+
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).g;
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).g;
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).g;
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).g;
+
+ return sum / norm;
+}
+
+void main() {
+ vec2 uv = v_objectUV + .5;
+ uv.y = 1. - uv.y;
+
+ vec2 imgUV = v_imageUV;
+ imgUV -= .5;
+ imgUV *= 0.5714285714285714;
+ imgUV += .5;
+ float imgSoftFrame = getImgFrame(imgUV, .03);
+
+ vec4 img = texture(u_image, imgUV);
+ vec2 dudx = dFdx(imgUV);
+ vec2 dudy = dFdy(imgUV);
+
+ if (img.a == 0.) {
+ fragColor = u_colorBack;
+ return;
+ }
+
+ float t = .1 * u_time;
+ t -= .3;
+
+ float tCopy = t + 1. / 3.;
+ float tCopy2 = t + 2. / 3.;
+
+ t = mod(t, 1.);
+ tCopy = mod(tCopy, 1.);
+ tCopy2 = mod(tCopy2, 1.);
+
+ vec2 animationUV = imgUV - vec2(.5);
+ float angle = -u_angle * PI / 180.;
+ float cosA = cos(angle);
+ float sinA = sin(angle);
+ animationUV = vec2(
+ animationUV.x * cosA - animationUV.y * sinA,
+ animationUV.x * sinA + animationUV.y * cosA
+ ) + vec2(.5);
+
+ float shape = img[0];
+
+ img[1] = blurEdge3x3(u_image, imgUV, dudx, dudy, 8., img[1]);
+
+ float outerBlur = 1. - mix(1., img[1], shape);
+ float innerBlur = mix(img[1], 0., shape);
+ float contour = mix(img[2], 0., shape);
+
+ outerBlur *= imgSoftFrame;
+
+ float shadow = shadowShape(animationUV, t, innerBlur);
+ float shadowCopy = shadowShape(animationUV, tCopy, innerBlur);
+ float shadowCopy2 = shadowShape(animationUV, tCopy2, innerBlur);
+
+ float inner = .8 + .8 * innerBlur;
+ inner = mix(inner, 0., shadow);
+ inner = mix(inner, 0., shadowCopy);
+ inner = mix(inner, 0., shadowCopy2);
+
+ inner *= mix(0., 2., u_innerGlow);
+
+ inner += (u_contour * 2.) * contour;
+ inner = min(1., inner);
+ inner *= (1. - shape);
+
+ float outer = 0.;
+ {
+ t *= 3.;
+ t = mod(t - .1, 1.);
+
+ outer = .9 * pow(outerBlur, .8);
+ float y = mod(animationUV.y - t, 1.);
+ float animatedMask = sst(.3, .65, y) * (1. - sst(.65, 1., y));
+ animatedMask = .5 + animatedMask;
+ outer *= animatedMask;
+ outer *= mix(0., 5., pow(u_outerGlow, 2.));
+ outer *= imgSoftFrame;
+ }
+
+ inner = pow(inner, 1.2);
+ float heat = clamp(inner + outer, 0., 1.);
+
+ heat += (.005 + .35 * u_noise) * (fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123) - .5);
+
+ float mixer = heat * u_colorsCount;
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+ float outerShape = 0.;
+ for (int i = 1; i < ${heatmapMeta.maxColorCount + 1}; i++) {
+ if (i > int(u_colorsCount)) break;
+ float m = clamp(mixer - float(i - 1), 0., 1.);
+ if (i == 1) {
+ outerShape = m;
+ }
+ vec4 c = u_colors[i - 1];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, m);
+ }
+
+ vec3 color = gradient.rgb * outerShape;
+ float opacity = gradient.a * outerShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1.0 - opacity);
+ opacity = opacity + u_colorBack.a * (1.0 - opacity);
+
+ color += .02 * (fract(sin(dot(uv + 1., vec2(12.9898, 78.233))) * 43758.5453123) - .5);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+function toProcessedHeatmap(file) {
+ const canvas = document.createElement("canvas");
+ const canvasSize = 1e3;
+ return new Promise((resolve, reject) => {
+ const image = new Image();
+ image.crossOrigin = "anonymous";
+ image.addEventListener("load", () => {
+ if (typeof file === "string" ? file.endsWith(".svg") : file.type === "image/svg+xml") {
+ image.width = canvasSize;
+ image.height = canvasSize;
+ }
+ const ratio = image.naturalWidth / image.naturalHeight;
+ const maxBlur = Math.floor(canvasSize * 0.15);
+ const padding = Math.ceil(maxBlur * 2.5);
+ let imgWidth = canvasSize;
+ let imgHeight = canvasSize;
+ if (ratio > 1) {
+ imgHeight = Math.floor(canvasSize / ratio);
+ } else {
+ imgWidth = Math.floor(canvasSize * ratio);
+ }
+ canvas.width = imgWidth + 2 * padding;
+ canvas.height = imgHeight + 2 * padding;
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
+ if (!ctx) {
+ throw new Error("Failed to get canvas 2d context");
+ }
+ ctx.fillStyle = "white";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.drawImage(image, padding, padding, imgWidth, imgHeight);
+ const { width, height } = canvas;
+ const srcImageData = ctx.getImageData(0, 0, width, height);
+ const src = srcImageData.data;
+ const totalPixels = width * height;
+ const gray = new Uint8ClampedArray(totalPixels);
+ for (let i = 0; i < totalPixels; i++) {
+ const px = i * 4;
+ const r = src[px] ?? 0;
+ const g = src[px + 1] ?? 0;
+ const b = src[px + 2] ?? 0;
+ gray[i] = 0.299 * r + 0.587 * g + 0.114 * b | 0;
+ }
+ const bigBlurRadius = maxBlur;
+ const innerBlurRadius = Math.max(1, Math.round(0.12 * maxBlur));
+ const contourRadius = 5;
+ const bigBlurGray = multiPassBlurGray(gray, width, height, bigBlurRadius, 3);
+ const innerBlurGray = multiPassBlurGray(gray, width, height, innerBlurRadius, 3);
+ const contourGray = multiPassBlurGray(gray, width, height, contourRadius, 1);
+ const processedImageData = ctx.createImageData(width, height);
+ const dst = processedImageData.data;
+ for (let i = 0; i < totalPixels; i++) {
+ const px = i * 4;
+ dst[px] = contourGray[i] ?? 0;
+ dst[px + 1] = bigBlurGray[i] ?? 0;
+ dst[px + 2] = innerBlurGray[i] ?? 0;
+ dst[px + 3] = 255;
+ }
+ ctx.putImageData(processedImageData, 0, 0);
+ canvas.toBlob((blob) => {
+ if (!blob) {
+ reject(new Error("Failed to create PNG blob"));
+ return;
+ }
+ resolve({ blob });
+ }, "image/png");
+ });
+ image.addEventListener("error", () => {
+ reject(new Error("Failed to load image"));
+ });
+ image.src = typeof file === "string" ? file : URL.createObjectURL(file);
+ });
+}
+function blurGray(gray, width, height, radius) {
+ if (radius <= 0) {
+ return gray.slice();
+ }
+ const out = new Uint8ClampedArray(width * height);
+ const integral = new Uint32Array(width * height);
+ for (let y = 0; y < height; y++) {
+ let rowSum = 0;
+ for (let x = 0; x < width; x++) {
+ const idx = y * width + x;
+ const v = gray[idx] ?? 0;
+ rowSum += v;
+ integral[idx] = rowSum + (y > 0 ? integral[idx - width] ?? 0 : 0);
+ }
+ }
+ for (let y = 0; y < height; y++) {
+ const y1 = Math.max(0, y - radius);
+ const y2 = Math.min(height - 1, y + radius);
+ for (let x = 0; x < width; x++) {
+ const x1 = Math.max(0, x - radius);
+ const x2 = Math.min(width - 1, x + radius);
+ const idxA = y2 * width + x2;
+ const idxB = y2 * width + (x1 - 1);
+ const idxC = (y1 - 1) * width + x2;
+ const idxD = (y1 - 1) * width + (x1 - 1);
+ const A = integral[idxA] ?? 0;
+ const B = x1 > 0 ? integral[idxB] ?? 0 : 0;
+ const C = y1 > 0 ? integral[idxC] ?? 0 : 0;
+ const D = x1 > 0 && y1 > 0 ? integral[idxD] ?? 0 : 0;
+ const sum = A - B - C + D;
+ const area = (x2 - x1 + 1) * (y2 - y1 + 1);
+ out[y * width + x] = Math.round(sum / area);
+ }
+ }
+ return out;
+}
+function multiPassBlurGray(gray, width, height, radius, passes) {
+ if (radius <= 0 || passes <= 1) {
+ return blurGray(gray, width, height, radius);
+ }
+ let input = gray;
+ let tmp = gray;
+ for (let p = 0; p < passes; p++) {
+ tmp = blurGray(input, width, height, radius);
+ input = tmp;
+ }
+ return tmp;
+}
+export {
+ heatmapFragmentShader,
+ heatmapMeta,
+ toProcessedHeatmap
+};
+//# sourceMappingURL=heatmap.js.map
diff --git a/public/vendor/paper-shaders/shaders/heatmap.js.map b/public/vendor/paper-shaders/shaders/heatmap.js.map
new file mode 100644
index 0000000..36f6d7a
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/heatmap.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/heatmap.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';\n\nexport const heatmapMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A glowing gradient of colors flowing through an input shape.\n * The effect creates a smoothly animated wave of intensity across the image.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_image (sampler2D): Pre-processed source image texture (R = contour, G = outer blur, B = inner blur)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 heatmap colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_contour (float): Heat intensity near the edges of the input shape (0 to 1)\n * - u_angle (float): Direction of the heatwaves in degrees (0 to 360)\n * - u_noise (float): Grain applied across the entire graphic (0 to 1)\n * - u_innerGlow (float): Size of the heated area inside the input shape (0 to 1)\n * - u_outerGlow (float): Size of the heated area outside the input shape (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const heatmapFragmentShader: string = `#version 300 es\nprecision highp float;\n\nin mediump vec2 v_imageUV;\nin mediump vec2 v_objectUV;\nout vec4 fragColor;\n\nuniform sampler2D u_image;\nuniform float u_time;\nuniform mediump float u_imageAspectRatio;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ heatmapMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_angle;\nuniform float u_noise;\nuniform float u_innerGlow;\nuniform float u_outerGlow;\nuniform float u_contour;\n\n#define TWO_PI 6.28318530718\n#define PI 3.14159265358979323846\n\nfloat getImgFrame(vec2 uv, float th) {\n float frame = 1.;\n frame *= smoothstep(0., th, uv.y);\n frame *= 1. - smoothstep(1. - th, 1., uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= 1. - smoothstep(1. - th, 1., uv.x);\n return frame;\n}\n\nfloat circle(vec2 uv, vec2 c, vec2 r) {\n return 1. - smoothstep(r[0], r[1], length(uv - c));\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nfloat shadowShape(vec2 uv, float t, float contour) {\n vec2 scaledUV = uv;\n\n // base shape tranjectory\n float posY = mix(-1., 2., t);\n\n // scaleX when it's moving down\n scaledUV.y -= .5;\n float mainCircleScale = sst(0., .8, posY) * lst(1.4, .9, posY);\n scaledUV *= vec2(1., 1. + 1.5 * mainCircleScale);\n scaledUV.y += .5;\n\n // base shape\n float innerR = .4;\n float outerR = 1. - .3 * (sst(.1, .2, t) * (1. - sst(.2, .5, t)));\n float s = circle(scaledUV, vec2(.5, posY - .2), vec2(innerR, outerR));\n float shapeSizing = sst(.2, .3, t) * sst(.6, .3, t);\n s = pow(s, 1.4);\n s *= 1.2;\n\n // flat gradient to take over the shadow shape\n float topFlattener = 0.;\n {\n float pos = posY - uv.y;\n float edge = 1.2;\n topFlattener = lst(-.4, 0., pos) * (1. - sst(.0, edge, pos));\n topFlattener = pow(topFlattener, 3.);\n float topFlattenerMixer = (1. - sst(.0, .3, pos));\n s = mix(topFlattener, s, topFlattenerMixer);\n }\n\n // apple right circle\n {\n float visibility = sst(.6, .7, t) * (1. - sst(.8, .9, t));\n float angle = -2. -t * TWO_PI;\n float rightCircle = circle(uv, vec2(.95 - .2 * cos(angle), .4 - .1 * sin(angle)), vec2(.15, .3));\n rightCircle *= visibility;\n s = mix(s, 0., rightCircle);\n }\n\n // apple top circle\n {\n float topCircle = circle(uv, vec2(.5, .19), vec2(.05, .25));\n topCircle += 2. * contour * circle(uv, vec2(.5, .19), vec2(.2, .5));\n float visibility = .55 * sst(.2, .3, t) * (1. - sst(.3, .45, t));\n topCircle *= visibility;\n s = mix(s, 0., topCircle);\n }\n\n float leafMask = circle(uv, vec2(.53, .13), vec2(.08, .19));\n leafMask = mix(leafMask, 0., 1. - sst(.4, .54, uv.x));\n leafMask = mix(0., leafMask, sst(.0, .2, uv.y));\n leafMask *= (sst(.5, 1.1, posY) * sst(1.5, 1.3, posY));\n s += leafMask;\n\n // apple bottom circle\n {\n float visibility = sst(.0, .4, t) * (1. - sst(.6, .8, t));\n s = mix(s, 0., visibility * circle(uv, vec2(.52, .92), vec2(.09, .25)));\n }\n\n // random balls that are invisible if apple logo is selected\n {\n float pos = sst(.0, .6, t) * (1. - sst(.6, 1., t));\n s = mix(s, .5, circle(uv, vec2(.0, 1.2 - .5 * pos), vec2(.1, .3)));\n s = mix(s, .0, circle(uv, vec2(1., .5 + .5 * pos), vec2(.1, .3)));\n\n s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * sst(.7, .5, t)), vec2(.07, .22)));\n s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * (1. - sst(.5, .7, t))), vec2(.07, .22)));\n s /= max(1e-4, sst(1., .85, uv.y));\n }\n\n s = clamp(0., 1., s);\n return s;\n}\n\nfloat blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = radius * texel;\n\n float w1 = 1.0, w2 = 2.0, w4 = 4.0;\n float norm = 16.0;\n float sum = w4 * centerSample;\n\n sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).g;\n sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).g;\n sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).g;\n sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).g;\n\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).g;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).g;\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).g;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).g;\n\n return sum / norm;\n}\n\nvoid main() {\n vec2 uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n\n vec2 imgUV = v_imageUV;\n imgUV -= .5;\n imgUV *= 0.5714285714285714;\n imgUV += .5;\n float imgSoftFrame = getImgFrame(imgUV, .03);\n\n vec4 img = texture(u_image, imgUV);\n vec2 dudx = dFdx(imgUV);\n vec2 dudy = dFdy(imgUV);\n\n if (img.a == 0.) {\n fragColor = u_colorBack;\n return;\n }\n\n float t = .1 * u_time;\n t -= .3;\n\n float tCopy = t + 1. / 3.;\n float tCopy2 = t + 2. / 3.;\n\n t = mod(t, 1.);\n tCopy = mod(tCopy, 1.);\n tCopy2 = mod(tCopy2, 1.);\n\n vec2 animationUV = imgUV - vec2(.5);\n float angle = -u_angle * PI / 180.;\n float cosA = cos(angle);\n float sinA = sin(angle);\n animationUV = vec2(\n animationUV.x * cosA - animationUV.y * sinA,\n animationUV.x * sinA + animationUV.y * cosA\n ) + vec2(.5);\n\n float shape = img[0];\n\n img[1] = blurEdge3x3(u_image, imgUV, dudx, dudy, 8., img[1]);\n\n float outerBlur = 1. - mix(1., img[1], shape);\n float innerBlur = mix(img[1], 0., shape);\n float contour = mix(img[2], 0., shape);\n\n outerBlur *= imgSoftFrame;\n\n float shadow = shadowShape(animationUV, t, innerBlur);\n float shadowCopy = shadowShape(animationUV, tCopy, innerBlur);\n float shadowCopy2 = shadowShape(animationUV, tCopy2, innerBlur);\n\n float inner = .8 + .8 * innerBlur;\n inner = mix(inner, 0., shadow);\n inner = mix(inner, 0., shadowCopy);\n inner = mix(inner, 0., shadowCopy2);\n\n inner *= mix(0., 2., u_innerGlow);\n\n inner += (u_contour * 2.) * contour;\n inner = min(1., inner);\n inner *= (1. - shape);\n\n float outer = 0.;\n {\n t *= 3.;\n t = mod(t - .1, 1.);\n\n outer = .9 * pow(outerBlur, .8);\n float y = mod(animationUV.y - t, 1.);\n float animatedMask = sst(.3, .65, y) * (1. - sst(.65, 1., y));\n animatedMask = .5 + animatedMask;\n outer *= animatedMask;\n outer *= mix(0., 5., pow(u_outerGlow, 2.));\n outer *= imgSoftFrame;\n }\n\n inner = pow(inner, 1.2);\n float heat = clamp(inner + outer, 0., 1.);\n\n heat += (.005 + .35 * u_noise) * (fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n\n float mixer = heat * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n float outerShape = 0.;\n for (int i = 1; i < ${ heatmapMeta.maxColorCount + 1 }; i++) {\n if (i > int(u_colorsCount)) break;\n float m = clamp(mixer - float(i - 1), 0., 1.);\n if (i == 1) {\n outerShape = m;\n }\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 color += .02 * (fract(sin(dot(uv + 1., vec2(12.9898, 78.233))) * 43758.5453123) - .5);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport function toProcessedHeatmap(file: File | string): Promise<{ blob: Blob }> {\n const canvas = document.createElement('canvas');\n const canvasSize = 1000;\n\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.crossOrigin = 'anonymous';\n\n image.addEventListener('load', () => {\n if (typeof file === 'string' ? file.endsWith('.svg') : file.type === 'image/svg+xml') {\n // Force SVG to load at a high fidelity size if it's an SVG\n image.width = canvasSize;\n image.height = canvasSize;\n }\n\n const ratio = image.naturalWidth / image.naturalHeight;\n\n const maxBlur = Math.floor(canvasSize * 0.15);\n const padding = Math.ceil(maxBlur * 2.5);\n let imgWidth = canvasSize;\n let imgHeight = canvasSize;\n if (ratio > 1) {\n imgHeight = Math.floor(canvasSize / ratio);\n } else {\n imgWidth = Math.floor(canvasSize * ratio);\n }\n\n canvas.width = imgWidth + 2 * padding;\n canvas.height = imgHeight + 2 * padding;\n\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\n if (!ctx) {\n throw new Error('Failed to get canvas 2d context');\n }\n\n // 1) Draw original image once, no filters\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n\n const { width, height } = canvas;\n const srcImageData = ctx.getImageData(0, 0, width, height);\n const src = srcImageData.data; // RGBA\n\n // 2) Build grayscale array (luma)\n const totalPixels = width * height;\n const gray = new Uint8ClampedArray(totalPixels);\n for (let i = 0; i < totalPixels; i++) {\n const px = i * 4;\n const r = src[px] ?? 0;\n const g = src[px + 1] ?? 0;\n const b = src[px + 2] ?? 0;\n // Standard luma conversion\n gray[i] = (0.299 * r + 0.587 * g + 0.114 * b) | 0;\n }\n\n // 3) Blur grayscale for each \"filter\" you previously used\n const bigBlurRadius = maxBlur;\n const innerBlurRadius = Math.max(1, Math.round(0.12 * maxBlur));\n const contourRadius = 5;\n\n const bigBlurGray = multiPassBlurGray(gray, width, height, bigBlurRadius, 3);\n const innerBlurGray = multiPassBlurGray(gray, width, height, innerBlurRadius, 3);\n const contourGray = multiPassBlurGray(gray, width, height, contourRadius, 1);\n\n // 4) Combine into final ImageData\n const processedImageData = ctx.createImageData(width, height);\n const dst = processedImageData.data;\n\n for (let i = 0; i < totalPixels; i++) {\n const px = i * 4;\n dst[px] = contourGray[i] ?? 0;\n dst[px + 1] = bigBlurGray[i] ?? 0;\n dst[px + 2] = innerBlurGray[i] ?? 0;\n dst[px + 3] = 255;\n }\n\n ctx.putImageData(processedImageData, 0, 0);\n\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n resolve({ blob });\n }, 'image/png');\n });\n\n image.addEventListener('error', () => {\n reject(new Error('Failed to load image'));\n });\n\n image.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\n/**\n * Fast box blur for grayscale images using an integral image.\n * gray: Uint8ClampedArray of length width * height\n * radius: blur radius in pixels\n */\nfunction blurGray(gray: Uint8ClampedArray, width: number, height: number, radius: number): Uint8ClampedArray {\n if (radius <= 0) {\n return gray.slice();\n }\n\n const out = new Uint8ClampedArray(width * height);\n const integral = new Uint32Array(width * height);\n\n // Build integral image\n for (let y = 0; y < height; y++) {\n let rowSum = 0;\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const v = gray[idx] ?? 0;\n rowSum += v;\n integral[idx] = rowSum + (y > 0 ? (integral[idx - width] ?? 0) : 0);\n }\n }\n\n // Blur using integral image\n for (let y = 0; y < height; y++) {\n const y1 = Math.max(0, y - radius);\n const y2 = Math.min(height - 1, y + radius);\n for (let x = 0; x < width; x++) {\n const x1 = Math.max(0, x - radius);\n const x2 = Math.min(width - 1, x + radius);\n\n const idxA = y2 * width + x2;\n const idxB = y2 * width + (x1 - 1);\n const idxC = (y1 - 1) * width + x2;\n const idxD = (y1 - 1) * width + (x1 - 1);\n\n const A = integral[idxA] ?? 0;\n const B = x1 > 0 ? (integral[idxB] ?? 0) : 0;\n const C = y1 > 0 ? (integral[idxC] ?? 0) : 0;\n const D = x1 > 0 && y1 > 0 ? (integral[idxD] ?? 0) : 0;\n\n const sum = A - B - C + D;\n const area = (x2 - x1 + 1) * (y2 - y1 + 1);\n out[y * width + x] = Math.round(sum / area);\n }\n }\n\n return out;\n}\n\nfunction multiPassBlurGray(\n gray: Uint8ClampedArray,\n width: number,\n height: number,\n radius: number,\n passes: number\n): Uint8ClampedArray {\n if (radius <= 0 || passes <= 1) {\n return blurGray(gray, width, height, radius);\n }\n\n let input = gray;\n let tmp: Uint8ClampedArray = gray;\n\n for (let p = 0; p < passes; p++) {\n tmp = blurGray(input, width, height, radius);\n input = tmp;\n }\n\n return tmp;\n}\n\nexport interface HeatmapUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string;\n u_contour: number;\n u_angle: number;\n u_noise: number;\n u_innerGlow: number;\n u_outerGlow: number;\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n}\n\nexport interface HeatmapParams extends ShaderSizingParams, ShaderMotionParams {\n image: HTMLImageElement | string;\n contour?: number;\n angle?: number;\n noise?: number;\n innerGlow?: number;\n outerGlow?: number;\n colorBack?: string;\n colors?: string[];\n}\n"],
+ "mappings": "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",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/image-dithering.d.ts b/public/vendor/paper-shaders/shaders/image-dithering.d.ts
new file mode 100644
index 0000000..3392dfa
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/image-dithering.d.ts
@@ -0,0 +1,66 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * A dithering image filter with support for 4 dithering modes and multiple color palettes
+ * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled
+ * from the original image).
+ *
+ * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep
+ * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any
+ * transforms, so scaling/rotating only affects the underlying image.
+ * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used.
+ *
+ * Fragment shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_image (sampler2D): Source image texture
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorFront (vec4): Foreground color in RGBA
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering)
+ * - u_originalColors (bool): Use the original colors of the image instead of the color palette
+ * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast
+ * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)
+ * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)
+ * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)
+ *
+ */
+export declare const imageDitheringFragmentShader: string;
+export interface ImageDitheringUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string;
+ u_colorFront: [number, number, number, number];
+ u_colorBack: [number, number, number, number];
+ u_colorHighlight: [number, number, number, number];
+ u_type: (typeof DitheringTypes)[DitheringType];
+ u_pxSize: number;
+ u_colorSteps: number;
+ u_originalColors: boolean;
+ u_inverted: boolean;
+}
+export interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {
+ image: HTMLImageElement | string;
+ colorFront?: string;
+ colorBack?: string;
+ colorHighlight?: string;
+ type?: DitheringType;
+ size?: number;
+ colorSteps?: number;
+ originalColors?: boolean;
+ inverted?: boolean;
+}
+export declare const DitheringTypes: {
+ readonly random: 1;
+ readonly '2x2': 2;
+ readonly '4x4': 3;
+ readonly '8x8': 4;
+};
+export type DitheringType = keyof typeof DitheringTypes;
diff --git a/public/vendor/paper-shaders/shaders/image-dithering.js b/public/vendor/paper-shaders/shaders/image-dithering.js
new file mode 100644
index 0000000..82f3fcf
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/image-dithering.js
@@ -0,0 +1,201 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { proceduralHash21, declarePI } from "../shader-utils.js";
+const imageDitheringFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec2 u_resolution;
+uniform float u_pixelRatio;
+uniform float u_originX;
+uniform float u_originY;
+uniform float u_worldWidth;
+uniform float u_worldHeight;
+uniform float u_fit;
+
+uniform float u_scale;
+uniform float u_rotation;
+uniform float u_offsetX;
+uniform float u_offsetY;
+
+uniform vec4 u_colorFront;
+uniform vec4 u_colorBack;
+uniform vec4 u_colorHighlight;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform float u_type;
+uniform float u_pxSize;
+uniform bool u_originalColors;
+uniform bool u_inverted;
+uniform float u_colorSteps;
+
+out vec4 fragColor;
+
+
+${proceduralHash21}
+${declarePI}
+
+float getUvFrame(vec2 uv, vec2 pad) {
+ float aa = 0.0001;
+
+ float left = smoothstep(-pad.x, -pad.x + aa, uv.x);
+ float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);
+ float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);
+ float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);
+
+ return left * right * bottom * top;
+}
+
+vec2 getImageUV(vec2 uv) {
+ vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
+ float r = u_rotation * PI / 180.;
+ mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
+ vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
+
+ vec2 imageBoxSize;
+ if (u_fit == 1.) { // contain
+ imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
+ } else if (u_fit == 2.) { // cover
+ imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
+ } else {
+ imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);
+ }
+ imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;
+ vec2 imageBoxScale = u_resolution.xy / imageBoxSize;
+
+ vec2 imageUV = uv;
+ imageUV *= imageBoxScale;
+ imageUV += boxOrigin * (imageBoxScale - 1.);
+ imageUV += graphicOffset;
+ imageUV /= u_scale;
+ imageUV.x *= u_imageAspectRatio;
+ imageUV = graphicRotation * imageUV;
+ imageUV.x /= u_imageAspectRatio;
+
+ imageUV += .5;
+ imageUV.y = 1. - imageUV.y;
+
+ return imageUV;
+}
+
+const int bayer2x2[4] = int[4](0, 2, 3, 1);
+const int bayer4x4[16] = int[16](
+0, 8, 2, 10,
+12, 4, 14, 6,
+3, 11, 1, 9,
+15, 7, 13, 5
+);
+
+const int bayer8x8[64] = int[64](
+0, 32, 8, 40, 2, 34, 10, 42,
+48, 16, 56, 24, 50, 18, 58, 26,
+12, 44, 4, 36, 14, 46, 6, 38,
+60, 28, 52, 20, 62, 30, 54, 22,
+3, 35, 11, 43, 1, 33, 9, 41,
+51, 19, 59, 27, 49, 17, 57, 25,
+15, 47, 7, 39, 13, 45, 5, 37,
+63, 31, 55, 23, 61, 29, 53, 21
+);
+
+float getBayerValue(vec2 uv, int size) {
+ ivec2 pos = ivec2(fract(uv / float(size)) * float(size));
+ int index = pos.y * size + pos.x;
+
+ if (size == 2) {
+ return float(bayer2x2[index]) / 4.0;
+ } else if (size == 4) {
+ return float(bayer4x4[index]) / 16.0;
+ } else if (size == 8) {
+ return float(bayer8x8[index]) / 64.0;
+ }
+ return 0.0;
+}
+
+
+void main() {
+
+ float pxSize = u_pxSize * u_pixelRatio;
+ vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;
+ pxSizeUV /= pxSize;
+ vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;
+ vec2 normalizedUV = canvasPixelizedUV / u_resolution;
+
+ vec2 imageUV = getImageUV(normalizedUV);
+ vec2 ditheringNoiseUV = canvasPixelizedUV;
+ vec4 image = texture(u_image, imageUV);
+ float frame = getUvFrame(imageUV, pxSize / u_resolution);
+
+ int type = int(floor(u_type));
+ float dithering = 0.0;
+
+ float lum = dot(vec3(.2126, .7152, .0722), image.rgb);
+ lum = u_inverted ? (1. - lum) : lum;
+
+ switch (type) {
+ case 1: {
+ dithering = step(hash21(ditheringNoiseUV), lum);
+ } break;
+ case 2:
+ dithering = getBayerValue(pxSizeUV, 2);
+ break;
+ case 3:
+ dithering = getBayerValue(pxSizeUV, 4);
+ break;
+ default :
+ dithering = getBayerValue(pxSizeUV, 8);
+ break;
+ }
+
+ float colorSteps = max(floor(u_colorSteps), 1.);
+ vec3 color = vec3(0.0);
+ float opacity = 1.;
+
+ dithering -= .5;
+ float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0);
+ brightness = mix(0.0, brightness, frame);
+ brightness = mix(0.0, brightness, image.a);
+ float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps;
+ quantLum = mix(0.0, quantLum, frame);
+
+ if (u_originalColors == true) {
+ vec3 normColor = image.rgb / max(lum, 0.001);
+ color = normColor * quantLum;
+
+ float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps;
+ opacity = mix(quantLum, 1., quantAlpha);
+ } else {
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+ vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a;
+ float hlOpacity = u_colorHighlight.a;
+
+ fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness));
+ fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness));
+
+ color = fgColor * quantLum;
+ opacity = fgOpacity * quantLum;
+ color += bgColor * (1.0 - opacity);
+ opacity += bgOpacity * (1.0 - opacity);
+ }
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const DitheringTypes = {
+ "random": 1,
+ "2x2": 2,
+ "4x4": 3,
+ "8x8": 4
+};
+export {
+ DitheringTypes,
+ imageDitheringFragmentShader
+};
+//# sourceMappingURL=image-dithering.js.map
diff --git a/public/vendor/paper-shaders/shaders/image-dithering.js.map b/public/vendor/paper-shaders/shaders/image-dithering.js.map
new file mode 100644
index 0000000..eb53c89
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/image-dithering.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/image-dithering.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { proceduralHash21, declarePI } from '../shader-utils.js';\n\n/**\n * A dithering image filter with support for 4 dithering modes and multiple color palettes\n * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled\n * from the original image).\n *\n * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep\n * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any\n * transforms, so scaling/rotating only affects the underlying image.\n * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering)\n * - u_originalColors (bool): Use the original colors of the image instead of the color palette\n * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast\n * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)\n * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)\n * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)\n *\n */\n\n// language=GLSL\nexport const imageDitheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\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 vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_type;\nuniform float u_pxSize;\nuniform bool u_originalColors;\nuniform bool u_inverted;\nuniform float u_colorSteps;\n\nout vec4 fragColor;\n\n\n${ proceduralHash21 }\n${ declarePI }\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float aa = 0.0001;\n\n float left = smoothstep(-pad.x, -pad.x + aa, uv.x);\n float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);\n float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);\n float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);\n\n return left * right * bottom * top;\n}\n\nvec2 getImageUV(vec2 uv) {\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n float r = u_rotation * PI / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\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 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\n return imageUV;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n0, 8, 2, 10,\n12, 4, 14, 6,\n3, 11, 1, 9,\n15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n0, 32, 8, 40, 2, 34, 10, 42,\n48, 16, 56, 24, 50, 18, 58, 26,\n12, 44, 4, 36, 14, 46, 6, 38,\n60, 28, 52, 20, 62, 30, 54, 22,\n3, 35, 11, 43, 1, 33, 9, 41,\n51, 19, 59, 27, 49, 17, 57, 25,\n15, 47, 7, 39, 13, 45, 5, 37,\n63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(fract(uv / float(size)) * 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\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;\n pxSizeUV /= pxSize;\n vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;\n vec2 normalizedUV = canvasPixelizedUV / u_resolution;\n\n vec2 imageUV = getImageUV(normalizedUV);\n vec2 ditheringNoiseUV = canvasPixelizedUV;\n vec4 image = texture(u_image, imageUV);\n float frame = getUvFrame(imageUV, pxSize / u_resolution);\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n float lum = dot(vec3(.2126, .7152, .0722), image.rgb);\n lum = u_inverted ? (1. - lum) : lum;\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoiseUV), lum);\n } break;\n case 2:\n dithering = getBayerValue(pxSizeUV, 2);\n break;\n case 3:\n dithering = getBayerValue(pxSizeUV, 4);\n break;\n default :\n dithering = getBayerValue(pxSizeUV, 8);\n break;\n }\n\n float colorSteps = max(floor(u_colorSteps), 1.);\n vec3 color = vec3(0.0);\n float opacity = 1.;\n\n dithering -= .5;\n float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0);\n brightness = mix(0.0, brightness, frame);\n brightness = mix(0.0, brightness, image.a);\n float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps;\n quantLum = mix(0.0, quantLum, frame);\n\n if (u_originalColors == true) {\n vec3 normColor = image.rgb / max(lum, 0.001);\n color = normColor * quantLum;\n\n float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps;\n opacity = mix(quantLum, 1., quantAlpha);\n } else {\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 vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a;\n float hlOpacity = u_colorHighlight.a;\n\n fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness));\n fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness));\n\n color = fgColor * quantLum;\n opacity = fgOpacity * quantLum;\n color += bgColor * (1.0 - opacity);\n opacity += bgOpacity * (1.0 - opacity);\n }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ImageDitheringUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n u_colorSteps: number;\n u_originalColors: boolean;\n u_inverted: boolean;\n}\n\nexport interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {\n image: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n colorHighlight?: string;\n type?: DitheringType;\n size?: number;\n colorSteps?: number;\n originalColors?: boolean;\n inverted?: boolean;\n}\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"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,kBAAkB,iBAAiB;AAsCrC,MAAM,+BAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgCjD,gBAAiB;AAAA,EACjB,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+KN,MAAM,iBAAiB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/lens-distortion.d.ts b/public/vendor/paper-shaders/shaders/lens-distortion.d.ts
new file mode 100644
index 0000000..8a1970c
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/lens-distortion.d.ts
@@ -0,0 +1,97 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const lensDistortionMeta: {
+ readonly maxSamples: 50;
+};
+/**
+ *
+ * Lens Distortion image filter separates an image into shifting color layers
+ * (recreating the chromatic aberration of a lens) and warps the image geometry,
+ * curving it outward or inward like barrel and pincushion distortion.
+ *
+ * Fragment shader uniforms:
+ * - u_image (sampler2D): Source image texture
+ * - u_spread (float): Strength of the color split; how far the color layers are pushed apart; 0 is off (0 to 1)
+ * - u_bias (float): Shifts the colors toward one end of the spread; 0 spaces them evenly (-1 to 1)
+ * - u_angle (float): Direction of the spread in degrees (0 to 360)
+ * - u_perspective (float): Shapes the spread direction from a straight line (0) to a radial burst out from the centre (1) (0 to 1)
+ * - u_count (float): Number of sampled color layers along the spread; higher is smoother and costlier (2 to 50)
+ * - u_dispersion (float): Overall amount of color dispersion; 1 gives each layer its own color from the spectrum, 0 keeps the original image color (0 to 1)
+ * - u_dispersionShift (float): Balance of the dispersion between a soft circular zone at the centre and the rest of the image; 0 applies it evenly, -1 keeps it in the centre only, 1 keeps it at the edges only (-1 to 1)
+ * - u_dispersionColor (float): Rotates the colors around the hue wheel, 0 to 1 for a full turn
+ * - u_focusCenter (float): Reduces the spread in a circular zone at the centre; 0 keeps it full to the centre (0 to 1)
+ * - u_focusEdges (float): Reduces the spread toward the edges; 0 keeps it full to the edges, 1 restores the original image there (0 to 1)
+ * - u_swirl (float): Rotates the color layers around the centre by an angle growing along the spread; 0 is off (-1 to 1)
+ * - u_noise (float): Scatters the spread direction with noise; 0 is off (0 to 1)
+ * - u_noiseFrequency (float): Frequency of the noise, 0 to 1 mapped internally to 0 to 18; higher is finer (no effect with noise = 0)
+ * - u_noiseOffset (float): Offsets the noise pattern for a different seed, 0 to 1 mapped internally to 0 to 30 (no effect with noise = 0)
+ * - u_lensBulge (float): Radial lens warp of the image geometry; positive bulges out like a fisheye/barrel, negative pinches in like a pincushion; strong positive values fade out the corners (-1 to 1)
+ * - u_lensCircle (float): Squeezes pixels outside the inscribed circle inward so the outline becomes a circle; also turns the spread radial and damps it near the rim; 0 is off, 1 is full (0 to 1)
+ * - u_grainMixer (float): Scatters the spread with grain noise, breaking up the edges of the color layers (0 to 1)
+ * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
+ * - u_imageX (float): Pans the image horizontally behind the effect; 0 is centred (-1 to 1)
+ * - u_imageY (float): Pans the image vertically behind the effect; 0 is centred (-1 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const lensDistortionFragmentShader: string;
+export interface LensDistortionUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string | undefined;
+ u_spread: number;
+ u_bias: number;
+ u_angle: number;
+ u_perspective: number;
+ u_count: number;
+ u_dispersion: number;
+ u_dispersionShift: number;
+ u_dispersionColor: number;
+ u_focusCenter: number;
+ u_focusEdges: number;
+ u_swirl: number;
+ u_noise: number;
+ u_noiseFrequency: number;
+ u_noiseOffset: number;
+ u_lensBulge: number;
+ u_lensCircle: number;
+ u_grainMixer: number;
+ u_grainOverlay: number;
+ u_imageX: number;
+ u_imageY: number;
+}
+export interface LensDistortionParams extends ShaderSizingParams, ShaderMotionParams {
+ image?: HTMLImageElement | string;
+ spread?: number;
+ bias?: number;
+ angle?: number;
+ perspective?: number;
+ count?: number;
+ dispersion?: number;
+ dispersionShift?: number;
+ dispersionColor?: number;
+ focusCenter?: number;
+ focusEdges?: number;
+ swirl?: number;
+ noise?: number;
+ noiseFrequency?: number;
+ noiseOffset?: number;
+ lensBulge?: number;
+ lensCircle?: number;
+ grainMixer?: number;
+ grainOverlay?: number;
+ imageX?: number;
+ imageY?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/lens-distortion.js b/public/vendor/paper-shaders/shaders/lens-distortion.js
new file mode 100644
index 0000000..98a6cc4
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/lens-distortion.js
@@ -0,0 +1,276 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, proceduralHash21, rotation2 } from "../shader-utils.js";
+const lensDistortionMeta = {
+ maxSamples: 50
+};
+const lensDistortionFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+uniform float u_spread;
+uniform float u_bias;
+uniform float u_angle;
+uniform float u_perspective;
+uniform float u_count;
+uniform float u_dispersion;
+uniform float u_dispersionShift;
+uniform float u_dispersionColor;
+uniform float u_focusCenter;
+uniform float u_focusEdges;
+uniform float u_swirl;
+uniform float u_noise;
+uniform float u_noiseFrequency;
+uniform float u_noiseOffset;
+uniform float u_lensBulge;
+uniform float u_lensCircle;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+uniform float u_imageX;
+uniform float u_imageY;
+
+in vec2 v_imageUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${proceduralHash21}
+${rotation2}
+
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = hash21(i);
+ float b = hash21(i + vec2(1., 0.));
+ float c = hash21(i + vec2(0., 1.));
+ float d = hash21(i + vec2(1., 1.));
+ vec2 u = f * f * (3. - 2. * f);
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
+}
+
+float getUvFrame(vec2 uv) {
+ vec2 invAA = 1. / clamp(fwidth(uv), 1e-5, .02);
+ vec2 lo = clamp(uv * invAA + .5, 0., 1.);
+ vec2 hi = clamp((1. - uv) * invAA + .5, 0., 1.);
+ return lo.x * hi.x * lo.y * hi.y;
+}
+
+vec4 sampleOverWhite(vec2 uv) {
+ vec4 img = texture(u_image, uv);
+ float cover = img.a * getUvFrame(uv);
+ vec3 colorOverWhite = mix(vec3(1.), img.rgb, cover);
+ return vec4(colorOverWhite, cover);
+}
+
+vec3 hueColor(float hue) {
+ vec3 rgb = clamp(abs(mod(hue * 6. + vec3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.);
+ rgb = rgb * rgb * (3. - 2. * rgb);
+ return rgb;
+}
+
+float boxInradius() {
+ return .5 * min(u_imageAspectRatio, 1.);
+}
+
+float boxOutradius() {
+ return .5 * length(vec2(u_imageAspectRatio, 1.));
+}
+
+float spreadReach() {
+ return .7 * pow(u_spread, 1.3 + 2.7 * u_spread);
+}
+
+float innerCircleMask(float radius, float inradius) {
+ return 1. - smoothstep(.5 * inradius, 1.1 * inradius, radius);
+}
+
+float dispersionCurve(float t, float biasPow) {
+ float mirroredT = u_bias < 0. ? 1. - t : t;
+ float curved = pow(mirroredT, biasPow);
+ return u_bias < 0. ? 1. - curved : curved;
+}
+
+vec2 getSpread(vec2 fromCenter, float radius, vec2 warpedUV, float edgeAA, float inradius, float outradius, float reach, out float outStrength) {
+ float angleRad = radians(u_angle);
+ vec2 uniformDir = vec2(cos(angleRad), sin(angleRad));
+
+ float invInradius = 1. / inradius;
+ vec2 radialDir = fromCenter * invInradius;
+ float maxLen = (outradius + reach) * invInradius;
+ float radialLen = radius * invInradius;
+ if (radialLen > maxLen) radialDir *= maxLen / radialLen;
+ vec2 spreadDir = mix(uniformDir, radialDir, u_perspective);
+
+ float bandProximity = smoothstep(inradius * .8, inradius, radius);
+ float lensCircleMaxing = bandProximity * u_lensCircle * u_lensCircle * u_lensCircle;
+ spreadDir = mix(spreadDir, radialDir, lensCircleMaxing);
+
+ vec2 warpedAbs = abs(warpedUV - .5);
+ float inner = mix(1., smoothstep(0., mix(inradius, outradius, u_focusCenter), radius), u_focusCenter);
+ float boxDist = max(warpedAbs.x, warpedAbs.y) * 2.;
+ float outer = mix(1., 1. - min(boxDist, 1.), u_focusEdges);
+ float strength = inner * outer;
+
+ strength *= mix(1., mix(.15, .03, max(-u_lensBulge, 0.)), lensCircleMaxing);
+
+ vec2 outside = max(warpedAbs - .5, 0.);
+ float margin = max(reach * length(spreadDir) * (1. - u_lensCircle), edgeAA);
+ strength *= 1. - smoothstep(0., margin, length(outside));
+
+ outStrength = strength;
+ vec2 axis = spreadDir * (reach * strength);
+
+ if (u_noise > 0.) {
+ float turn = (valueNoise(fromCenter * u_noiseFrequency * 18. + u_noiseOffset * 30.) - .5) * 2. * u_noise;
+ float cs = cos(turn), sn = sin(turn);
+ axis = mat2(cs, -sn, sn, cs) * axis;
+ }
+
+ axis.x /= u_imageAspectRatio;
+ return axis;
+}
+
+vec2 lensWarp(vec2 fromCenter, float radius, float inradius, out float bulgeFade) {
+ bulgeFade = 1.;
+ if (u_lensBulge == 0. && u_lensCircle <= 0.) return fromCenter;
+ if (radius < 1e-5) return fromCenter;
+
+ float r = radius;
+
+ if (u_lensBulge != 0.) {
+ float rn = radius / inradius;
+ float bulge = abs(u_lensBulge) * (u_lensBulge > 0. ? 1.4 : 1.2);
+ if (u_lensBulge > 0.) bulgeFade = 1. - smoothstep(1.45, 1.53, rn * bulge);
+ float map = u_lensBulge > 0.
+ ? tan(min(rn * bulge, 1.53)) / tan(bulge)
+ : atan(rn * tan(bulge)) / bulge;
+ float bulgeScale = map / rn;
+ fromCenter *= bulgeScale;
+ r *= bulgeScale;
+ }
+
+ if (u_lensCircle > 0.) {
+ vec2 dir = fromCenter / max(r, 1e-5);
+ vec2 halfBox = vec2(u_imageAspectRatio, 1.) * .5;
+ float rBox = min(halfBox.x / max(abs(dir.x), 1e-4), halfBox.y / max(abs(dir.y), 1e-4));
+ float band = inradius * mix(.03, .2, .5 * (u_lensBulge + 1.));
+ float innerEdge = inradius - band;
+ float over = smoothstep(0., 1., (r - innerEdge) / band);
+ float g = r + (rBox - inradius) * pow(over, 14.);
+ fromCenter = dir * mix(r, g, u_lensCircle);
+ }
+
+ return fromCenter;
+}
+
+void main() {
+ vec2 uv = v_imageUV;
+
+ float invAspect = 1. / u_imageAspectRatio;
+ float inradius = boxInradius();
+ float outradius = boxOutradius();
+ float reach = spreadReach();
+
+ vec2 fromCenter = uv - .5;
+ fromCenter.x *= u_imageAspectRatio;
+ float radius = length(fromCenter);
+
+ float bulgeFade;
+ vec2 warpedFromCenter = lensWarp(fromCenter, radius, inradius, bulgeFade);
+ vec2 baseUV = vec2(warpedFromCenter.x * invAspect, warpedFromCenter.y) + .5;
+
+ vec2 baseDerivative = fwidth(baseUV);
+ float edgeAA = clamp(2. * max(baseDerivative.x, baseDerivative.y), .001, .02);
+
+ float spreadStrength;
+ vec2 spreadAxis = getSpread(fromCenter, radius, baseUV, edgeAA, inradius, outradius, reach, spreadStrength);
+
+ vec2 grainUV = vec2(0.);
+ if (u_grainMixer > 0. || u_grainOverlay > 0.) {
+ vec2 dudx = dFdx(v_imageUV);
+ vec2 dudy = dFdy(v_imageUV);
+ grainUV = (v_imageUV - .5) * (.8 / vec2(length(dudx), length(dudy))) + .5;
+ }
+
+ if (u_grainMixer > 0.) {
+ float grainSeed = valueNoise(grainUV);
+ vec2 jit = fract(grainSeed * vec2(157.31, 113.57)) * 2. - 1.;
+ spreadAxis += jit * .3 * u_grainMixer * length(spreadAxis);
+ }
+
+ float count = floor(u_count);
+ int countInteger = int(count);
+
+ float invCount = 1. / count;
+ float invSpan = 1. / max(count - 1., 1.);
+ float hueBase = u_dispersionColor + .5;
+ float biasPower = 1. + 2. * abs(u_bias);
+ vec2 tapBias = .5 - vec2(u_imageX, u_imageY);
+
+ float centerAmount = clamp(1. - u_dispersionShift, 0., 1.);
+ float edgesAmount = clamp(1. + u_dispersionShift, 0., 1.);
+ float dispersion = u_dispersion * mix(edgesAmount, centerAmount, innerCircleMask(radius, inradius));
+ float dispersionPower = pow(dispersion, .8);
+
+ float warpedRadius = length(warpedFromCenter);
+ float swirlAngle = u_swirl * .4 * PI * spreadStrength * u_spread * min(1., inradius / max(warpedRadius, 1e-4));
+
+ vec3 colorSum = vec3(0.);
+ vec3 weightSum = vec3(0.);
+ float coverSum = 0.;
+
+ for (int i = 0; i < ${lensDistortionMeta.maxSamples}; i++) {
+ if (i >= countInteger) break;
+
+ float layer = float(i);
+ float hue = hueBase + layer * invCount;
+
+ float spread = layer * invSpan;
+ if (u_bias != 0.) spread = dispersionCurve(spread, biasPower);
+
+ // mix(axis, -axis, spread) is axis scaled by the signed position along the fan
+ float fanPos = 1. - 2. * spread;
+ vec2 tapUV = baseUV + spreadAxis * fanPos - .5;
+
+ if (u_swirl != 0.) {
+ tapUV.x *= u_imageAspectRatio;
+ tapUV = rotate(tapUV, swirlAngle * fanPos);
+ tapUV.x *= invAspect;
+ }
+
+ vec4 tap = sampleOverWhite(tapUV + tapBias);
+ vec3 weight = 1. - dispersionPower * hueColor(hue);
+
+ colorSum += tap.rgb * weight;
+ weightSum += weight;
+ coverSum += tap.a;
+ }
+
+ vec3 color = colorSum / max(weightSum, 1e-4);
+ float coverAvg = coverSum * invCount;
+
+ float ground = min(color.r, min(color.g, color.b));
+ float alpha = max(coverAvg, 1. - ground);
+ vec3 premult = max(color - (1. - alpha), 0.);
+ fragColor = vec4(premult, alpha) * bulgeFade;
+
+ if (u_grainOverlay > 0.) {
+ float grain = valueNoise(rotate(grainUV, 1.) + vec2(3.));
+ grain = mix(grain, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
+ grain = pow(grain, 1.3);
+ float grainV = grain * 2. - 1.;
+ float grainStrength = pow(u_grainOverlay * abs(grainV), .8) * fragColor.a;
+ fragColor.rgb = mix(fragColor.rgb, vec3(step(0., grainV)) * fragColor.a, .35 * grainStrength);
+ }
+}
+`;
+export {
+ lensDistortionFragmentShader,
+ lensDistortionMeta
+};
+//# sourceMappingURL=lens-distortion.js.map
diff --git a/public/vendor/paper-shaders/shaders/lens-distortion.js.map b/public/vendor/paper-shaders/shaders/lens-distortion.js.map
new file mode 100644
index 0000000..e5e6c2c
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/lens-distortion.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/lens-distortion.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, proceduralHash21, rotation2 } from '../shader-utils.js';\n\nexport const lensDistortionMeta = {\n maxSamples: 50,\n} as const;\n\n/**\n *\n * Lens Distortion image filter separates an image into shifting color layers\n * (recreating the chromatic aberration of a lens) and warps the image geometry,\n * curving it outward or inward like barrel and pincushion distortion.\n *\n * Fragment shader uniforms:\n * - u_image (sampler2D): Source image texture\n * - u_spread (float): Strength of the color split; how far the color layers are pushed apart; 0 is off (0 to 1)\n * - u_bias (float): Shifts the colors toward one end of the spread; 0 spaces them evenly (-1 to 1)\n * - u_angle (float): Direction of the spread in degrees (0 to 360)\n * - u_perspective (float): Shapes the spread direction from a straight line (0) to a radial burst out from the centre (1) (0 to 1)\n * - u_count (float): Number of sampled color layers along the spread; higher is smoother and costlier (2 to 50)\n * - u_dispersion (float): Overall amount of color dispersion; 1 gives each layer its own color from the spectrum, 0 keeps the original image color (0 to 1)\n * - u_dispersionShift (float): Balance of the dispersion between a soft circular zone at the centre and the rest of the image; 0 applies it evenly, -1 keeps it in the centre only, 1 keeps it at the edges only (-1 to 1)\n * - u_dispersionColor (float): Rotates the colors around the hue wheel, 0 to 1 for a full turn\n * - u_focusCenter (float): Reduces the spread in a circular zone at the centre; 0 keeps it full to the centre (0 to 1)\n * - u_focusEdges (float): Reduces the spread toward the edges; 0 keeps it full to the edges, 1 restores the original image there (0 to 1)\n * - u_swirl (float): Rotates the color layers around the centre by an angle growing along the spread; 0 is off (-1 to 1)\n * - u_noise (float): Scatters the spread direction with noise; 0 is off (0 to 1)\n * - u_noiseFrequency (float): Frequency of the noise, 0 to 1 mapped internally to 0 to 18; higher is finer (no effect with noise = 0)\n * - u_noiseOffset (float): Offsets the noise pattern for a different seed, 0 to 1 mapped internally to 0 to 30 (no effect with noise = 0)\n * - u_lensBulge (float): Radial lens warp of the image geometry; positive bulges out like a fisheye/barrel, negative pinches in like a pincushion; strong positive values fade out the corners (-1 to 1)\n * - u_lensCircle (float): Squeezes pixels outside the inscribed circle inward so the outline becomes a circle; also turns the spread radial and damps it near the rim; 0 is off, 1 is full (0 to 1)\n * - u_grainMixer (float): Scatters the spread with grain noise, breaking up the edges of the color layers (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n * - u_imageX (float): Pans the image horizontally behind the effect; 0 is centred (-1 to 1)\n * - u_imageY (float): Pans the image vertically behind the effect; 0 is centred (-1 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const lensDistortionFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\nuniform float u_spread;\nuniform float u_bias;\nuniform float u_angle;\nuniform float u_perspective;\nuniform float u_count;\nuniform float u_dispersion;\nuniform float u_dispersionShift;\nuniform float u_dispersionColor;\nuniform float u_focusCenter;\nuniform float u_focusEdges;\nuniform float u_swirl;\nuniform float u_noise;\nuniform float u_noiseFrequency;\nuniform float u_noiseOffset;\nuniform float u_lensBulge;\nuniform float u_lensCircle;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_imageX;\nuniform float u_imageY;\n\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${declarePI}\n${proceduralHash21}\n${rotation2}\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1., 0.));\n float c = hash21(i + vec2(0., 1.));\n float d = hash21(i + vec2(1., 1.));\n vec2 u = f * f * (3. - 2. * f);\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat getUvFrame(vec2 uv) {\n vec2 invAA = 1. / clamp(fwidth(uv), 1e-5, .02);\n vec2 lo = clamp(uv * invAA + .5, 0., 1.);\n vec2 hi = clamp((1. - uv) * invAA + .5, 0., 1.);\n return lo.x * hi.x * lo.y * hi.y;\n}\n\nvec4 sampleOverWhite(vec2 uv) {\n vec4 img = texture(u_image, uv);\n float cover = img.a * getUvFrame(uv);\n vec3 colorOverWhite = mix(vec3(1.), img.rgb, cover);\n return vec4(colorOverWhite, cover);\n}\n\nvec3 hueColor(float hue) {\n vec3 rgb = clamp(abs(mod(hue * 6. + vec3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.);\n rgb = rgb * rgb * (3. - 2. * rgb);\n return rgb;\n}\n \nfloat boxInradius() {\n return .5 * min(u_imageAspectRatio, 1.);\n}\n\nfloat boxOutradius() {\n return .5 * length(vec2(u_imageAspectRatio, 1.));\n}\n\nfloat spreadReach() {\n return .7 * pow(u_spread, 1.3 + 2.7 * u_spread);\n}\n\nfloat innerCircleMask(float radius, float inradius) {\n return 1. - smoothstep(.5 * inradius, 1.1 * inradius, radius);\n}\n\nfloat dispersionCurve(float t, float biasPow) {\n float mirroredT = u_bias < 0. ? 1. - t : t;\n float curved = pow(mirroredT, biasPow);\n return u_bias < 0. ? 1. - curved : curved;\n}\n\nvec2 getSpread(vec2 fromCenter, float radius, vec2 warpedUV, float edgeAA, float inradius, float outradius, float reach, out float outStrength) {\n float angleRad = radians(u_angle);\n vec2 uniformDir = vec2(cos(angleRad), sin(angleRad));\n\n float invInradius = 1. / inradius;\n vec2 radialDir = fromCenter * invInradius;\n float maxLen = (outradius + reach) * invInradius;\n float radialLen = radius * invInradius;\n if (radialLen > maxLen) radialDir *= maxLen / radialLen;\n vec2 spreadDir = mix(uniformDir, radialDir, u_perspective);\n\n float bandProximity = smoothstep(inradius * .8, inradius, radius);\n float lensCircleMaxing = bandProximity * u_lensCircle * u_lensCircle * u_lensCircle;\n spreadDir = mix(spreadDir, radialDir, lensCircleMaxing);\n\n vec2 warpedAbs = abs(warpedUV - .5);\n float inner = mix(1., smoothstep(0., mix(inradius, outradius, u_focusCenter), radius), u_focusCenter);\n float boxDist = max(warpedAbs.x, warpedAbs.y) * 2.;\n float outer = mix(1., 1. - min(boxDist, 1.), u_focusEdges);\n float strength = inner * outer;\n\n strength *= mix(1., mix(.15, .03, max(-u_lensBulge, 0.)), lensCircleMaxing);\n\n vec2 outside = max(warpedAbs - .5, 0.);\n float margin = max(reach * length(spreadDir) * (1. - u_lensCircle), edgeAA);\n strength *= 1. - smoothstep(0., margin, length(outside));\n\n outStrength = strength;\n vec2 axis = spreadDir * (reach * strength);\n\n if (u_noise > 0.) {\n float turn = (valueNoise(fromCenter * u_noiseFrequency * 18. + u_noiseOffset * 30.) - .5) * 2. * u_noise;\n float cs = cos(turn), sn = sin(turn);\n axis = mat2(cs, -sn, sn, cs) * axis;\n }\n\n axis.x /= u_imageAspectRatio;\n return axis;\n}\n\nvec2 lensWarp(vec2 fromCenter, float radius, float inradius, out float bulgeFade) {\n bulgeFade = 1.;\n if (u_lensBulge == 0. && u_lensCircle <= 0.) return fromCenter;\n if (radius < 1e-5) return fromCenter;\n \n float r = radius;\n\n if (u_lensBulge != 0.) {\n float rn = radius / inradius;\n float bulge = abs(u_lensBulge) * (u_lensBulge > 0. ? 1.4 : 1.2);\n if (u_lensBulge > 0.) bulgeFade = 1. - smoothstep(1.45, 1.53, rn * bulge);\n float map = u_lensBulge > 0.\n ? tan(min(rn * bulge, 1.53)) / tan(bulge)\n : atan(rn * tan(bulge)) / bulge;\n float bulgeScale = map / rn;\n fromCenter *= bulgeScale;\n r *= bulgeScale;\n }\n\n if (u_lensCircle > 0.) {\n vec2 dir = fromCenter / max(r, 1e-5);\n vec2 halfBox = vec2(u_imageAspectRatio, 1.) * .5;\n float rBox = min(halfBox.x / max(abs(dir.x), 1e-4), halfBox.y / max(abs(dir.y), 1e-4));\n float band = inradius * mix(.03, .2, .5 * (u_lensBulge + 1.));\n float innerEdge = inradius - band;\n float over = smoothstep(0., 1., (r - innerEdge) / band);\n float g = r + (rBox - inradius) * pow(over, 14.);\n fromCenter = dir * mix(r, g, u_lensCircle);\n }\n\n return fromCenter;\n}\n\nvoid main() {\n vec2 uv = v_imageUV;\n\n float invAspect = 1. / u_imageAspectRatio;\n float inradius = boxInradius();\n float outradius = boxOutradius();\n float reach = spreadReach();\n\n vec2 fromCenter = uv - .5;\n fromCenter.x *= u_imageAspectRatio;\n float radius = length(fromCenter);\n\n float bulgeFade;\n vec2 warpedFromCenter = lensWarp(fromCenter, radius, inradius, bulgeFade);\n vec2 baseUV = vec2(warpedFromCenter.x * invAspect, warpedFromCenter.y) + .5;\n\n vec2 baseDerivative = fwidth(baseUV);\n float edgeAA = clamp(2. * max(baseDerivative.x, baseDerivative.y), .001, .02);\n\n float spreadStrength;\n vec2 spreadAxis = getSpread(fromCenter, radius, baseUV, edgeAA, inradius, outradius, reach, spreadStrength);\n\n vec2 grainUV = vec2(0.);\n if (u_grainMixer > 0. || u_grainOverlay > 0.) {\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n grainUV = (v_imageUV - .5) * (.8 / vec2(length(dudx), length(dudy))) + .5;\n }\n\n if (u_grainMixer > 0.) {\n float grainSeed = valueNoise(grainUV);\n vec2 jit = fract(grainSeed * vec2(157.31, 113.57)) * 2. - 1.;\n spreadAxis += jit * .3 * u_grainMixer * length(spreadAxis);\n }\n\n float count = floor(u_count);\n int countInteger = int(count);\n\n float invCount = 1. / count;\n float invSpan = 1. / max(count - 1., 1.);\n float hueBase = u_dispersionColor + .5;\n float biasPower = 1. + 2. * abs(u_bias);\n vec2 tapBias = .5 - vec2(u_imageX, u_imageY);\n\n float centerAmount = clamp(1. - u_dispersionShift, 0., 1.);\n float edgesAmount = clamp(1. + u_dispersionShift, 0., 1.);\n float dispersion = u_dispersion * mix(edgesAmount, centerAmount, innerCircleMask(radius, inradius));\n float dispersionPower = pow(dispersion, .8);\n\n float warpedRadius = length(warpedFromCenter);\n float swirlAngle = u_swirl * .4 * PI * spreadStrength * u_spread * min(1., inradius / max(warpedRadius, 1e-4));\n\n vec3 colorSum = vec3(0.);\n vec3 weightSum = vec3(0.);\n float coverSum = 0.;\n\n for (int i = 0; i < ${lensDistortionMeta.maxSamples}; i++) {\n if (i >= countInteger) break;\n\n float layer = float(i);\n float hue = hueBase + layer * invCount;\n\n float spread = layer * invSpan;\n if (u_bias != 0.) spread = dispersionCurve(spread, biasPower);\n\n // mix(axis, -axis, spread) is axis scaled by the signed position along the fan\n float fanPos = 1. - 2. * spread;\n vec2 tapUV = baseUV + spreadAxis * fanPos - .5;\n\n if (u_swirl != 0.) {\n tapUV.x *= u_imageAspectRatio;\n tapUV = rotate(tapUV, swirlAngle * fanPos);\n tapUV.x *= invAspect;\n }\n\n vec4 tap = sampleOverWhite(tapUV + tapBias);\n vec3 weight = 1. - dispersionPower * hueColor(hue);\n\n colorSum += tap.rgb * weight;\n weightSum += weight;\n coverSum += tap.a;\n }\n\n vec3 color = colorSum / max(weightSum, 1e-4);\n float coverAvg = coverSum * invCount;\n\n float ground = min(color.r, min(color.g, color.b));\n float alpha = max(coverAvg, 1. - ground);\n vec3 premult = max(color - (1. - alpha), 0.);\n fragColor = vec4(premult, alpha) * bulgeFade;\n\n if (u_grainOverlay > 0.) {\n float grain = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grain = mix(grain, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grain = pow(grain, 1.3);\n float grainV = grain * 2. - 1.;\n float grainStrength = pow(u_grainOverlay * abs(grainV), .8) * fragColor.a;\n fragColor.rgb = mix(fragColor.rgb, vec3(step(0., grainV)) * fragColor.a, .35 * grainStrength);\n }\n}\n`;\n\nexport interface LensDistortionUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_spread: number;\n u_bias: number;\n u_angle: number;\n u_perspective: number;\n u_count: number;\n u_dispersion: number;\n u_dispersionShift: number;\n u_dispersionColor: number;\n u_focusCenter: number;\n u_focusEdges: number;\n u_swirl: number;\n u_noise: number;\n u_noiseFrequency: number;\n u_noiseOffset: number;\n u_lensBulge: number;\n u_lensCircle: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_imageX: number;\n u_imageY: number;\n}\n\nexport interface LensDistortionParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n spread?: number;\n bias?: number;\n angle?: number;\n perspective?: number;\n count?: number;\n dispersion?: number;\n dispersionShift?: number;\n dispersionColor?: number;\n focusCenter?: number;\n focusEdges?: number;\n swirl?: number;\n noise?: number;\n noiseFrequency?: number;\n noiseOffset?: number;\n lensBulge?: number;\n lensCircle?: number;\n grainMixer?: number;\n grainOverlay?: number;\n imageX?: number;\n imageY?: number;\n}\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,kBAAkB,iBAAiB;AAEhD,MAAM,qBAAqB;AAAA,EAChC,YAAY;AACd;AAiDO,MAAM,+BAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BlD,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAwLa,mBAAmB,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;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/liquid-metal.d.ts b/public/vendor/paper-shaders/shaders/liquid-metal.d.ts
new file mode 100644
index 0000000..fd09ed5
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/liquid-metal.d.ts
@@ -0,0 +1,90 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Futuristic liquid metal material applied to uploaded logo or abstract shape.
+ * Fluid motion imitation applied over user image with animated stripe pattern
+ * getting distorted along shape edges.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = opacity)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorTint (vec4): Overlay color in RGBA (color burn blending used)
+ * - u_repetition (float): Density of pattern stripes (1 to 10)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ * - u_shiftRed (float): R-channel dispersion (-1 to 1)
+ * - u_shiftBlue (float): B-channel dispersion (-1 to 1)
+ * - u_distortion (float): Noise distortion over the stripes pattern (0 to 1)
+ * - u_contour (float): Strength of the distortion on the shape edges (0 to 1)
+ * - u_angle (float): Direction of pattern animation in degrees (0 to 360)
+ * - u_shape (float): Predefined shape when no image provided (0 = none, 1 = circle, 2 = daisy, 3 = diamond, 4 = metaballs)
+ * - u_isImage (bool): Whether an image is being used as the effect mask
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used when no image)
+ * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio (used for canvas-fill mode)
+ * - v_responsiveBoxGivenSize (vec2): TBD
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const liquidMetalFragmentShader: string;
+export declare const POISSON_CONFIG_OPTIMIZED: {
+ measurePerformance: boolean;
+ workingSize: number;
+ iterations: number;
+};
+export declare function toProcessedLiquidMetal(file: File | string): Promise<{
+ imageData: ImageData;
+ pngBlob: Blob;
+}>;
+export interface LiquidMetalUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colorTint: [number, number, number, number];
+ u_image: HTMLImageElement | string | undefined;
+ u_repetition: number;
+ u_shiftRed: number;
+ u_shiftBlue: number;
+ u_contour: number;
+ u_softness: number;
+ u_distortion: number;
+ u_angle: number;
+ u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape];
+ u_isImage: boolean;
+}
+export interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colorTint?: string;
+ image?: HTMLImageElement | string | undefined;
+ repetition?: number;
+ shiftRed?: number;
+ shiftBlue?: number;
+ contour?: number;
+ softness?: number;
+ distortion?: number;
+ angle?: number;
+ shape?: LiquidMetalShape;
+}
+export declare const LiquidMetalShapes: {
+ readonly none: 0;
+ readonly circle: 1;
+ readonly daisy: 2;
+ readonly diamond: 3;
+ readonly metaballs: 4;
+};
+export type LiquidMetalShape = keyof typeof LiquidMetalShapes;
diff --git a/public/vendor/paper-shaders/shaders/liquid-metal.js b/public/vendor/paper-shaders/shaders/liquid-metal.js
new file mode 100644
index 0000000..31fb3ea
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/liquid-metal.js
@@ -0,0 +1,630 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, simplexNoise, colorBandingFix } from "../shader-utils.js";
+const liquidMetalFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform vec2 u_resolution;
+uniform float u_time;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorTint;
+
+uniform float u_softness;
+uniform float u_repetition;
+uniform float u_shiftRed;
+uniform float u_shiftBlue;
+uniform float u_distortion;
+uniform float u_contour;
+uniform float u_angle;
+
+uniform float u_shape;
+uniform bool u_isImage;
+
+in vec2 v_objectUV;
+in vec2 v_responsiveUV;
+in vec2 v_responsiveBoxGivenSize;
+in vec2 v_imageUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${simplexNoise}
+
+float getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {
+
+ float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));
+
+ float border = w[0];
+ ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));
+
+ if (u_isImage == true) {
+ bump = smoothstep(.2, .8, bump);
+ }
+ border = w[0] + .4 * (1. - bump) * w[1];
+ ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));
+
+ border = w[0] + .5 * (1. - bump) * w[1];
+ ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));
+
+ border = w[0] + w[1];
+ ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));
+
+ float gradient_t = (stripe_p - w[0] - w[1]) / w[2];
+ float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));
+ ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));
+
+ // Tint color is applied with color burn blending
+ ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);
+ return ch;
+}
+
+float getImgFrame(vec2 uv, float th) {
+ float frame = 1.;
+ frame *= smoothstep(0., th, uv.y);
+ frame *= 1.0 - smoothstep(1. - th, 1., uv.y);
+ frame *= smoothstep(0., th, uv.x);
+ frame *= 1.0 - smoothstep(1. - th, 1., uv.x);
+ return frame;
+}
+
+float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {
+ vec2 texel = 1.0 / vec2(textureSize(tex, 0));
+ vec2 r = radius * texel;
+
+ float w1 = 1.0, w2 = 2.0, w4 = 4.0;
+ float norm = 16.0;
+ float sum = w4 * centerSample;
+
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r;
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r;
+ sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r;
+ sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r;
+
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r;
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r;
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r;
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r;
+
+ return sum / norm;
+}
+
+float lst(float edge0, float edge1, float x) {
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+}
+
+void main() {
+
+ const float firstFrameOffset = 2.8;
+ float t = .3 * (u_time + firstFrameOffset);
+
+ vec2 uv = v_imageUV;
+ vec2 dudx = dFdx(v_imageUV);
+ vec2 dudy = dFdy(v_imageUV);
+ vec4 img = textureGrad(u_image, uv, dudx, dudy);
+
+ if (u_isImage == false) {
+ uv = v_objectUV + .5;
+ uv.y = 1. - uv.y;
+ }
+
+ float cycleWidth = u_repetition;
+ float edge = 0.;
+ float contOffset = 1.;
+
+ vec2 rotatedUV = uv - vec2(.5);
+ float angle = (-u_angle + 70.) * PI / 180.;
+ float cosA = cos(angle);
+ float sinA = sin(angle);
+ rotatedUV = vec2(
+ rotatedUV.x * cosA - rotatedUV.y * sinA,
+ rotatedUV.x * sinA + rotatedUV.y * cosA
+ ) + vec2(.5);
+
+ if (u_isImage == true) {
+ float edgeRaw = img.r;
+ edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw);
+ edge = pow(edge, 1.6);
+ edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour));
+ } else {
+ if (u_shape < 1.) {
+ // full-fill on canvas
+ vec2 borderUV = v_responsiveUV + .5;
+ float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
+ vec2 mask = min(borderUV, 1. - borderUV);
+ vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));
+ float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
+ float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
+ maskX = pow(maskX, .25);
+ maskY = pow(maskY, .25);
+ edge = clamp(1. - maskX * maskY, 0., 1.);
+
+ uv = v_responsiveUV;
+ if (ratio > 1.) {
+ uv.y /= ratio;
+ } else {
+ uv.x *= ratio;
+ }
+ uv += .5;
+ uv.y = 1. - uv.y;
+
+ cycleWidth *= 2.;
+ contOffset = 1.5;
+
+ } else if (u_shape < 2.) {
+ // circle
+ vec2 shapeUV = uv - .5;
+ shapeUV *= .67;
+ edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);
+ } else if (u_shape < 3.) {
+ // daisy
+ vec2 shapeUV = uv - .5;
+ shapeUV *= 1.68;
+
+ float r = length(shapeUV) * 2.;
+ float a = atan(shapeUV.y, shapeUV.x) + .2;
+ r *= (1. + .05 * sin(3. * a + 2. * t));
+ float f = abs(cos(a * 3.));
+ edge = smoothstep(f, f + .7, r);
+ edge *= edge;
+
+ uv *= .8;
+ cycleWidth *= 1.6;
+
+ } else if (u_shape < 4.) {
+ // diamond
+ vec2 shapeUV = uv - .5;
+ shapeUV = rotate(shapeUV, .25 * PI);
+ shapeUV *= 1.42;
+ shapeUV += .5;
+ vec2 mask = min(shapeUV, 1. - shapeUV);
+ vec2 pixel_thickness = vec2(.15);
+ float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
+ float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
+ maskX = pow(maskX, .25);
+ maskY = pow(maskY, .25);
+ edge = clamp(1. - maskX * maskY, 0., 1.);
+ } else if (u_shape < 5.) {
+ // metaballs
+ vec2 shapeUV = uv - .5;
+ shapeUV *= 1.3;
+ edge = 0.;
+ for (int i = 0; i < 5; i++) {
+ float fi = float(i);
+ float speed = 1.5 + 2./3. * sin(fi * 12.345);
+ float angle = -fi * 1.5;
+ vec2 dir1 = vec2(cos(angle), sin(angle));
+ vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));
+ vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));
+ float d = length(shapeUV + traj);
+ edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);
+ }
+ edge = 1. - smoothstep(.65, .9, edge);
+ edge = pow(edge, 4.);
+ }
+
+ edge = mix(smoothstep(.9 - 2. * fwidth(edge), .9, edge), edge, smoothstep(0.0, 0.4, u_contour));
+
+ }
+
+ float opacity = 0.;
+ if (u_isImage == true) {
+ opacity = img.g;
+ float frame = getImgFrame(v_imageUV, 0.);
+ opacity *= frame;
+ } else {
+ opacity = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);
+ if (u_shape < 2.) {
+ edge = 1.2 * edge;
+ } else if (u_shape < 5.) {
+ edge = 1.8 * pow(edge, 1.5);
+ }
+ }
+
+ float diagBLtoTR = rotatedUV.x - rotatedUV.y;
+ float diagTLtoBR = rotatedUV.x + rotatedUV.y;
+
+ vec3 color = vec3(0.);
+ vec3 color1 = vec3(.98, 0.98, 1.);
+ vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR));
+
+ vec2 grad_uv = uv - .5;
+
+ float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR));
+ grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI);
+ float direction = grad_uv.x;
+
+ float bump = pow(1.8 * dist, 1.2);
+ bump = 1. - bump;
+ bump *= pow(uv.y, .3);
+
+
+ float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump);
+ float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump);
+ float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio);
+
+ float thin_strip_1_width = cycleWidth * thin_strip_1_ratio;
+ float thin_strip_2_width = cycleWidth * thin_strip_2_ratio;
+
+ float noise = snoise(uv - t);
+
+ edge += (1. - edge) * u_distortion * noise;
+
+ direction += diagBLtoTR;
+ float contour = 0.;
+ direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * (1.0 - smoothstep(0., 1., edge)));
+ direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour));
+ direction -= 1.7 * edge * smoothstep(.5, 1., u_contour);
+ direction += .2 * pow(u_contour, 4.) * (1.0 - smoothstep(0., 1., edge));
+
+ bump *= clamp(pow(uv.y, .1), .3, 1.);
+ direction *= (.1 + (1.1 - edge) * bump);
+
+ direction *= (.4 + .6 * (1.0 - smoothstep(.5, 1., edge)));
+ direction += .18 * (smoothstep(.1, .2, uv.y) * (1.0 - smoothstep(.2, .4, uv.y)));
+ direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * (1.0 - smoothstep(.2, .4, 1. - uv.y)));
+
+ direction *= (.5 + .5 * pow(uv.y, 2.));
+ direction *= cycleWidth;
+ direction -= t;
+
+
+ float colorDispersion = (1. - bump);
+ colorDispersion = clamp(colorDispersion, 0., 1.);
+ float dispersionRed = colorDispersion;
+ dispersionRed += .03 * bump * noise;
+ dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * (1.0 - smoothstep(.1, .5, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, 1., bump)));
+ dispersionRed -= diagBLtoTR;
+
+ float dispersionBlue = colorDispersion;
+ dispersionBlue *= 1.3;
+ dispersionBlue += (smoothstep(0., .4, uv.y) * (1.0 - smoothstep(.1, .8, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, .8, bump)));
+ dispersionBlue -= .2 * edge;
+
+ dispersionRed *= (u_shiftRed / 20.);
+ dispersionBlue *= (u_shiftBlue / 20.);
+
+ float blur = 0.;
+ float rExtraBlur = 0.;
+ float gExtraBlur = 0.;
+ if (u_isImage == true) {
+ float softness = 0.05 * u_softness;
+ blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge);
+ float smallCanvasT = 1.0 - smoothstep(100., 500., min(u_resolution.x, u_resolution.y));
+ blur += smallCanvasT * smoothstep(.0, 1., edge);
+ rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump);
+ gExtraBlur = softness * 0.05 / max(0.001, abs(1. - diagBLtoTR));
+ } else {
+ blur = u_softness / 15. + .3 * contour;
+ }
+
+ vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);
+ w[1] -= .02 * smoothstep(.0, 1., edge + bump);
+ float stripe_r = fract(direction + dispersionRed);
+ float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r);
+ float stripe_g = fract(direction);
+ float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g);
+ float stripe_b = fract(direction - dispersionBlue);
+ float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);
+
+ color = vec3(r, g, b);
+ color *= opacity;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1. - opacity);
+ opacity = opacity + u_colorBack.a * (1. - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const POISSON_CONFIG_OPTIMIZED = {
+ measurePerformance: false,
+ // Set to true to see performance metrics
+ workingSize: 512,
+ // Size to solve Poisson at (will upscale to original size)
+ iterations: 40
+ // SOR converges ~2-20x faster than standard Gauss-Seidel
+};
+function toProcessedLiquidMetal(file) {
+ const canvas = document.createElement("canvas");
+ const ctx = canvas.getContext("2d");
+ const isBlob = typeof file === "string" && file.startsWith("blob:");
+ return new Promise((resolve, reject) => {
+ if (!file || !ctx) {
+ reject(new Error("Invalid file or canvas context"));
+ return;
+ }
+ const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get("Content-Type"));
+ const img = new Image();
+ img.crossOrigin = "anonymous";
+ const totalStartTime = performance.now();
+ img.onload = async () => {
+ let isSVG;
+ const blobContentType = await blobContentTypePromise;
+ if (blobContentType) {
+ isSVG = blobContentType === "image/svg+xml";
+ } else if (typeof file === "string") {
+ isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml");
+ } else {
+ isSVG = file.type === "image/svg+xml";
+ }
+ let originalWidth = img.width || img.naturalWidth;
+ let originalHeight = img.height || img.naturalHeight;
+ if (isSVG) {
+ const svgMaxSize = 4096;
+ const aspectRatio = originalWidth / originalHeight;
+ if (originalWidth > originalHeight) {
+ originalWidth = svgMaxSize;
+ originalHeight = svgMaxSize / aspectRatio;
+ } else {
+ originalHeight = svgMaxSize;
+ originalWidth = svgMaxSize * aspectRatio;
+ }
+ img.width = originalWidth;
+ img.height = originalHeight;
+ }
+ const minDimension = Math.min(originalWidth, originalHeight);
+ const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;
+ const scaleFactor = targetSize / minDimension;
+ const width = Math.round(originalWidth * scaleFactor);
+ const height = Math.round(originalHeight * scaleFactor);
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ console.log(`[Processing Mode]`);
+ console.log(` Original: ${originalWidth}\xD7${originalHeight}`);
+ console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);
+ if (scaleFactor < 1) {
+ console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`);
+ }
+ }
+ canvas.width = originalWidth;
+ canvas.height = originalHeight;
+ const shapeCanvas = document.createElement("canvas");
+ shapeCanvas.width = width;
+ shapeCanvas.height = height;
+ const shapeCtx = shapeCanvas.getContext("2d");
+ shapeCtx.drawImage(img, 0, 0, width, height);
+ const startMask = performance.now();
+ const shapeImageData = shapeCtx.getImageData(0, 0, width, height);
+ const data = shapeImageData.data;
+ const shapeMask = new Uint8Array(width * height);
+ const boundaryMask = new Uint8Array(width * height);
+ let shapePixelCount = 0;
+ for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {
+ const a = data[i + 3];
+ const isShape = a === 0 ? 0 : 1;
+ shapeMask[idx] = isShape;
+ shapePixelCount += isShape;
+ }
+ const boundaryIndices = [];
+ const interiorIndices = [];
+ for (let y = 0; y < height; y++) {
+ for (let x = 0; x < width; x++) {
+ const idx = y * width + x;
+ if (!shapeMask[idx]) continue;
+ let isBoundary = false;
+ if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
+ isBoundary = true;
+ } else {
+ isBoundary = !shapeMask[idx - 1] || // left
+ !shapeMask[idx + 1] || // right
+ !shapeMask[idx - width] || // top
+ !shapeMask[idx + width] || // bottom
+ !shapeMask[idx - width - 1] || // top-left
+ !shapeMask[idx - width + 1] || // top-right
+ !shapeMask[idx + width - 1] || // bottom-left
+ !shapeMask[idx + width + 1];
+ }
+ if (isBoundary) {
+ boundaryMask[idx] = 1;
+ boundaryIndices.push(idx);
+ } else {
+ interiorIndices.push(idx);
+ }
+ }
+ }
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);
+ console.log(
+ ` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)`
+ );
+ console.log(` Interior pixels: ${interiorIndices.length}`);
+ console.log(` Boundary pixels: ${boundaryIndices.length}`);
+ }
+ const sparseData = buildSparseData(
+ shapeMask,
+ boundaryMask,
+ new Uint32Array(interiorIndices),
+ new Uint32Array(boundaryIndices),
+ width,
+ height
+ );
+ const startSolve = performance.now();
+ const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);
+ }
+ let maxVal = 0;
+ let finalImageData;
+ for (let i = 0; i < interiorIndices.length; i++) {
+ const idx = interiorIndices[i];
+ if (u[idx] > maxVal) maxVal = u[idx];
+ }
+ const tempCanvas = document.createElement("canvas");
+ tempCanvas.width = width;
+ tempCanvas.height = height;
+ const tempCtx = tempCanvas.getContext("2d");
+ const tempImg = tempCtx.createImageData(width, height);
+ for (let y = 0; y < height; y++) {
+ for (let x = 0; x < width; x++) {
+ const idx = y * width + x;
+ const px = idx * 4;
+ if (!shapeMask[idx]) {
+ tempImg.data[px] = 255;
+ tempImg.data[px + 1] = 255;
+ tempImg.data[px + 2] = 255;
+ tempImg.data[px + 3] = 0;
+ } else {
+ const poissonRatio = u[idx] / maxVal;
+ const gray = 255 * (1 - poissonRatio);
+ tempImg.data[px] = gray;
+ tempImg.data[px + 1] = gray;
+ tempImg.data[px + 2] = gray;
+ tempImg.data[px + 3] = 255;
+ }
+ }
+ }
+ tempCtx.putImageData(tempImg, 0, 0);
+ ctx.imageSmoothingEnabled = true;
+ ctx.imageSmoothingQuality = "high";
+ ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);
+ const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);
+ const originalCanvas = document.createElement("canvas");
+ originalCanvas.width = originalWidth;
+ originalCanvas.height = originalHeight;
+ const originalCtx = originalCanvas.getContext("2d");
+ originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);
+ const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
+ for (let i = 0; i < outImg.data.length; i += 4) {
+ const a = originalData.data[i + 3];
+ const upscaledAlpha = outImg.data[i + 3];
+ if (a === 0) {
+ outImg.data[i] = 255;
+ outImg.data[i + 1] = 0;
+ } else {
+ outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i];
+ outImg.data[i + 1] = a;
+ }
+ outImg.data[i + 2] = 255;
+ outImg.data[i + 3] = 255;
+ }
+ ctx.putImageData(outImg, 0, 0);
+ finalImageData = outImg;
+ canvas.toBlob((blob) => {
+ if (!blob) {
+ reject(new Error("Failed to create PNG blob"));
+ return;
+ }
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ const totalTime = performance.now() - totalStartTime;
+ console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);
+ if (scaleFactor < 1) {
+ const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5);
+ console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);
+ console.log(
+ `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)`
+ );
+ }
+ }
+ resolve({
+ imageData: finalImageData,
+ pngBlob: blob
+ });
+ }, "image/png");
+ };
+ img.onerror = () => reject(new Error("Failed to load image"));
+ img.src = typeof file === "string" ? file : URL.createObjectURL(file);
+ });
+}
+function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) {
+ const pixelCount = interiorPixels.length;
+ const neighborIndices = new Int32Array(pixelCount * 4);
+ for (let i = 0; i < pixelCount; i++) {
+ const idx = interiorPixels[i];
+ const x = idx % width;
+ const y = Math.floor(idx / width);
+ neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;
+ neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;
+ neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;
+ neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;
+ }
+ return {
+ interiorPixels,
+ boundaryPixels,
+ pixelCount,
+ neighborIndices
+ };
+}
+function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) {
+ const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;
+ const C = 0.01;
+ const u = new Float32Array(width * height);
+ const { interiorPixels, neighborIndices, pixelCount } = sparseData;
+ const startTime = performance.now();
+ const omega = 1.9;
+ const redPixels = [];
+ const blackPixels = [];
+ for (let i = 0; i < pixelCount; i++) {
+ const idx = interiorPixels[i];
+ const x = idx % width;
+ const y = Math.floor(idx / width);
+ if ((x + y) % 2 === 0) {
+ redPixels.push(i);
+ } else {
+ blackPixels.push(i);
+ }
+ }
+ for (let iter = 0; iter < ITERATIONS; iter++) {
+ for (const i of redPixels) {
+ const idx = interiorPixels[i];
+ const eastIdx = neighborIndices[i * 4 + 0];
+ const westIdx = neighborIndices[i * 4 + 1];
+ const northIdx = neighborIndices[i * 4 + 2];
+ const southIdx = neighborIndices[i * 4 + 3];
+ let sumN = 0;
+ if (eastIdx >= 0) sumN += u[eastIdx];
+ if (westIdx >= 0) sumN += u[westIdx];
+ if (northIdx >= 0) sumN += u[northIdx];
+ if (southIdx >= 0) sumN += u[southIdx];
+ const newValue = (C + sumN) / 4;
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
+ }
+ for (const i of blackPixels) {
+ const idx = interiorPixels[i];
+ const eastIdx = neighborIndices[i * 4 + 0];
+ const westIdx = neighborIndices[i * 4 + 1];
+ const northIdx = neighborIndices[i * 4 + 2];
+ const southIdx = neighborIndices[i * 4 + 3];
+ let sumN = 0;
+ if (eastIdx >= 0) sumN += u[eastIdx];
+ if (westIdx >= 0) sumN += u[westIdx];
+ if (northIdx >= 0) sumN += u[northIdx];
+ if (southIdx >= 0) sumN += u[southIdx];
+ const newValue = (C + sumN) / 4;
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
+ }
+ }
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
+ const elapsed = performance.now() - startTime;
+ console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);
+ console.log(` Working size: ${width}\xD7${height}`);
+ console.log(` Iterations: ${ITERATIONS}`);
+ console.log(` Time: ${elapsed.toFixed(2)}ms`);
+ console.log(` Interior pixels processed: ${pixelCount}`);
+ console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`);
+ }
+ return u;
+}
+const LiquidMetalShapes = {
+ none: 0,
+ circle: 1,
+ daisy: 2,
+ diamond: 3,
+ metaballs: 4
+};
+export {
+ LiquidMetalShapes,
+ POISSON_CONFIG_OPTIMIZED,
+ liquidMetalFragmentShader,
+ toProcessedLiquidMetal
+};
+//# sourceMappingURL=liquid-metal.js.map
diff --git a/public/vendor/paper-shaders/shaders/liquid-metal.js.map b/public/vendor/paper-shaders/shaders/liquid-metal.js.map
new file mode 100644
index 0000000..1cdd58b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/liquid-metal.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/liquid-metal.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise, colorBandingFix } from '../shader-utils.js';\n\n/**\n * Futuristic liquid metal material applied to uploaded logo or abstract shape.\n * Fluid motion imitation applied over user image with animated stripe pattern\n * getting distorted along shape edges.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = opacity)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorTint (vec4): Overlay color in RGBA (color burn blending used)\n * - u_repetition (float): Density of pattern stripes (1 to 10)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_shiftRed (float): R-channel dispersion (-1 to 1)\n * - u_shiftBlue (float): B-channel dispersion (-1 to 1)\n * - u_distortion (float): Noise distortion over the stripes pattern (0 to 1)\n * - u_contour (float): Strength of the distortion on the shape edges (0 to 1)\n * - u_angle (float): Direction of pattern animation in degrees (0 to 360)\n * - u_shape (float): Predefined shape when no image provided (0 = none, 1 = circle, 2 = daisy, 3 = diamond, 4 = metaballs)\n * - u_isImage (bool): Whether an image is being used as the effect mask\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used when no image)\n * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio (used for canvas-fill mode)\n * - v_responsiveBoxGivenSize (vec2): TBD\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const liquidMetalFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform vec2 u_resolution;\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorTint;\n\nuniform float u_softness;\nuniform float u_repetition;\nuniform float u_shiftRed;\nuniform float u_shiftBlue;\nuniform float u_distortion;\nuniform float u_contour;\nuniform float u_angle;\n\nuniform float u_shape;\nuniform bool u_isImage;\n\nin vec2 v_objectUV;\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_imageUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ simplexNoise }\n\nfloat getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {\n\n float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));\n\n float border = w[0];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n if (u_isImage == true) {\n bump = smoothstep(.2, .8, bump);\n }\n border = w[0] + .4 * (1. - bump) * w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + .5 * (1. - bump) * w[1];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n float gradient_t = (stripe_p - w[0] - w[1]) / w[2];\n float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));\n ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));\n\n // Tint color is applied with color burn blending\n ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);\n return ch;\n}\n\nfloat getImgFrame(vec2 uv, float th) {\n float frame = 1.;\n frame *= smoothstep(0., th, uv.y);\n frame *= 1.0 - smoothstep(1. - th, 1., uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= 1.0 - smoothstep(1. - th, 1., uv.x);\n return frame;\n}\n\nfloat blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = radius * texel;\n\n float w1 = 1.0, w2 = 2.0, w4 = 4.0;\n float norm = 16.0;\n float sum = w4 * centerSample;\n\n sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r;\n\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r;\n\n return sum / norm;\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n const float firstFrameOffset = 2.8;\n float t = .3 * (u_time + firstFrameOffset);\n\n vec2 uv = v_imageUV;\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n vec4 img = textureGrad(u_image, uv, dudx, dudy);\n\n if (u_isImage == false) {\n uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n }\n\n float cycleWidth = u_repetition;\n float edge = 0.;\n float contOffset = 1.;\n\n vec2 rotatedUV = uv - vec2(.5);\n float angle = (-u_angle + 70.) * PI / 180.;\n float cosA = cos(angle);\n float sinA = sin(angle);\n rotatedUV = vec2(\n rotatedUV.x * cosA - rotatedUV.y * sinA,\n rotatedUV.x * sinA + rotatedUV.y * cosA\n ) + vec2(.5);\n\n if (u_isImage == true) {\n float edgeRaw = img.r;\n edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw);\n edge = pow(edge, 1.6);\n edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour));\n } else {\n if (u_shape < 1.) {\n // full-fill on canvas\n vec2 borderUV = v_responsiveUV + .5;\n float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 mask = min(borderUV, 1. - borderUV);\n vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n\n uv = v_responsiveUV;\n if (ratio > 1.) {\n uv.y /= ratio;\n } else {\n uv.x *= ratio;\n }\n uv += .5;\n uv.y = 1. - uv.y;\n\n cycleWidth *= 2.;\n contOffset = 1.5;\n\n } else if (u_shape < 2.) {\n // circle\n vec2 shapeUV = uv - .5;\n shapeUV *= .67;\n edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);\n } else if (u_shape < 3.) {\n // daisy\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.68;\n\n float r = length(shapeUV) * 2.;\n float a = atan(shapeUV.y, shapeUV.x) + .2;\n r *= (1. + .05 * sin(3. * a + 2. * t));\n float f = abs(cos(a * 3.));\n edge = smoothstep(f, f + .7, r);\n edge *= edge;\n\n uv *= .8;\n cycleWidth *= 1.6;\n\n } else if (u_shape < 4.) {\n // diamond\n vec2 shapeUV = uv - .5;\n shapeUV = rotate(shapeUV, .25 * PI);\n shapeUV *= 1.42;\n shapeUV += .5;\n vec2 mask = min(shapeUV, 1. - shapeUV);\n vec2 pixel_thickness = vec2(.15);\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n } else if (u_shape < 5.) {\n // metaballs\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.3;\n edge = 0.;\n for (int i = 0; i < 5; i++) {\n float fi = float(i);\n float speed = 1.5 + 2./3. * sin(fi * 12.345);\n float angle = -fi * 1.5;\n vec2 dir1 = vec2(cos(angle), sin(angle));\n vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));\n vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));\n float d = length(shapeUV + traj);\n edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);\n }\n edge = 1. - smoothstep(.65, .9, edge);\n edge = pow(edge, 4.);\n }\n\n edge = mix(smoothstep(.9 - 2. * fwidth(edge), .9, edge), edge, smoothstep(0.0, 0.4, u_contour));\n\n }\n\n float opacity = 0.;\n if (u_isImage == true) {\n opacity = img.g;\n float frame = getImgFrame(v_imageUV, 0.);\n opacity *= frame;\n } else {\n opacity = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);\n if (u_shape < 2.) {\n edge = 1.2 * edge;\n } else if (u_shape < 5.) {\n edge = 1.8 * pow(edge, 1.5);\n }\n }\n\n float diagBLtoTR = rotatedUV.x - rotatedUV.y;\n float diagTLtoBR = rotatedUV.x + rotatedUV.y;\n\n vec3 color = vec3(0.);\n vec3 color1 = vec3(.98, 0.98, 1.);\n vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR));\n\n vec2 grad_uv = uv - .5;\n\n float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR));\n grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI);\n float direction = grad_uv.x;\n\n float bump = pow(1.8 * dist, 1.2);\n bump = 1. - bump;\n bump *= pow(uv.y, .3);\n\n\n float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump);\n float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump);\n float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio);\n\n float thin_strip_1_width = cycleWidth * thin_strip_1_ratio;\n float thin_strip_2_width = cycleWidth * thin_strip_2_ratio;\n\n float noise = snoise(uv - t);\n\n edge += (1. - edge) * u_distortion * noise;\n\n direction += diagBLtoTR;\n float contour = 0.;\n direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * (1.0 - smoothstep(0., 1., edge)));\n direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour));\n direction -= 1.7 * edge * smoothstep(.5, 1., u_contour);\n direction += .2 * pow(u_contour, 4.) * (1.0 - smoothstep(0., 1., edge));\n\n bump *= clamp(pow(uv.y, .1), .3, 1.);\n direction *= (.1 + (1.1 - edge) * bump);\n\n direction *= (.4 + .6 * (1.0 - smoothstep(.5, 1., edge)));\n direction += .18 * (smoothstep(.1, .2, uv.y) * (1.0 - smoothstep(.2, .4, uv.y)));\n direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * (1.0 - smoothstep(.2, .4, 1. - uv.y)));\n\n direction *= (.5 + .5 * pow(uv.y, 2.));\n direction *= cycleWidth;\n direction -= t;\n\n\n float colorDispersion = (1. - bump);\n colorDispersion = clamp(colorDispersion, 0., 1.);\n float dispersionRed = colorDispersion;\n dispersionRed += .03 * bump * noise;\n dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * (1.0 - smoothstep(.1, .5, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, 1., bump)));\n dispersionRed -= diagBLtoTR;\n\n float dispersionBlue = colorDispersion;\n dispersionBlue *= 1.3;\n dispersionBlue += (smoothstep(0., .4, uv.y) * (1.0 - smoothstep(.1, .8, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, .8, bump)));\n dispersionBlue -= .2 * edge;\n\n dispersionRed *= (u_shiftRed / 20.);\n dispersionBlue *= (u_shiftBlue / 20.);\n\n float blur = 0.;\n float rExtraBlur = 0.;\n float gExtraBlur = 0.;\n if (u_isImage == true) {\n float softness = 0.05 * u_softness;\n blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge);\n float smallCanvasT = 1.0 - smoothstep(100., 500., min(u_resolution.x, u_resolution.y));\n blur += smallCanvasT * smoothstep(.0, 1., edge);\n rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump);\n gExtraBlur = softness * 0.05 / max(0.001, abs(1. - diagBLtoTR));\n } else {\n blur = u_softness / 15. + .3 * contour;\n }\n\n vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);\n w[1] -= .02 * smoothstep(.0, 1., edge + bump);\n float stripe_r = fract(direction + dispersionRed);\n float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r);\n float stripe_g = fract(direction);\n float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g);\n float stripe_b = fract(direction - dispersionBlue);\n float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);\n\n color = vec3(r, g, b);\n color *= opacity;\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\n// Configuration for Poisson solver\nexport const POISSON_CONFIG_OPTIMIZED = {\n measurePerformance: false, // Set to true to see performance metrics\n workingSize: 512, // Size to solve Poisson at (will upscale to original size)\n iterations: 40, // SOR converges ~2-20x faster than standard Gauss-Seidel\n};\n\n// Precomputed pixel data for sparse processing\ninterface SparsePixelData {\n interiorPixels: Uint32Array; // Indices of interior pixels\n boundaryPixels: Uint32Array; // Indices of boundary pixels\n pixelCount: number;\n // Neighbor indices for each interior pixel (4 neighbors per pixel)\n // Layout: [east, west, north, south] for each pixel\n neighborIndices: Int32Array;\n}\n\nexport function toProcessedLiquidMetal(file: File | string): Promise<{ imageData: ImageData; pngBlob: Blob }> {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const isBlob = typeof file === 'string' && file.startsWith('blob:');\n\n return new Promise((resolve, reject) => {\n if (!file || !ctx) {\n reject(new Error('Invalid file or canvas context'));\n return;\n }\n\n const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get('Content-Type'));\n const img = new Image();\n img.crossOrigin = 'anonymous';\n const totalStartTime = performance.now();\n\n img.onload = async () => {\n // Force SVG to load at a high fidelity size if it's an SVG\n let isSVG;\n\n const blobContentType = await blobContentTypePromise;\n\n if (blobContentType) {\n isSVG = blobContentType === 'image/svg+xml';\n } else if (typeof file === 'string') {\n isSVG = file.endsWith('.svg') || file.startsWith('data:image/svg+xml');\n } else {\n isSVG = file.type === 'image/svg+xml';\n }\n\n let originalWidth = img.width || img.naturalWidth;\n let originalHeight = img.height || img.naturalHeight;\n\n if (isSVG) {\n // Scale SVG to max dimension while preserving aspect ratio\n const svgMaxSize = 4096;\n const aspectRatio = originalWidth / originalHeight;\n\n if (originalWidth > originalHeight) {\n originalWidth = svgMaxSize;\n originalHeight = svgMaxSize / aspectRatio;\n } else {\n originalHeight = svgMaxSize;\n originalWidth = svgMaxSize * aspectRatio;\n }\n\n img.width = originalWidth;\n img.height = originalHeight;\n }\n\n // Always scale to working resolution for consistency\n const minDimension = Math.min(originalWidth, originalHeight);\n const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;\n\n // Calculate scale to fit within workingSize\n const scaleFactor = targetSize / minDimension;\n const width = Math.round(originalWidth * scaleFactor);\n const height = Math.round(originalHeight * scaleFactor);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Processing Mode]`);\n console.log(` Original: ${originalWidth}\u00D7${originalHeight}`);\n console.log(` Working: ${width}\u00D7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);\n if (scaleFactor < 1) {\n console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\u00D7`);\n }\n }\n\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n\n // Use a smaller canvas for shape detection and Poisson solving\n const shapeCanvas = document.createElement('canvas');\n shapeCanvas.width = width;\n shapeCanvas.height = height;\n\n const shapeCtx = shapeCanvas.getContext('2d')!;\n shapeCtx.drawImage(img, 0, 0, width, height);\n\n // 1) Build optimized masks using TypedArrays\n const startMask = performance.now();\n\n const shapeImageData = shapeCtx.getImageData(0, 0, width, height);\n const data = shapeImageData.data;\n\n // Use Uint8Array for masks (1 byte per pixel vs 8+ bytes for boolean array)\n const shapeMask = new Uint8Array(width * height);\n const boundaryMask = new Uint8Array(width * height);\n\n // First pass: identify shape pixels\n let shapePixelCount = 0;\n for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {\n const a = data[i + 3];\n const isShape = a === 0 ? 0 : 1;\n shapeMask[idx] = isShape;\n shapePixelCount += isShape;\n }\n\n // 2) Optimized boundary detection using sparse approach\n // Only check shape pixels, not all pixels\n const boundaryIndices: number[] = [];\n const interiorIndices: number[] = [];\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n if (!shapeMask[idx]) continue;\n\n // Check if pixel is on boundary (optimized: early exit)\n let isBoundary = false;\n\n // Check 4-connected neighbors first (most common case)\n if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {\n isBoundary = true;\n } else {\n // Check all 8 neighbors (including diagonals) for comprehensive boundary detection\n isBoundary =\n !shapeMask[idx - 1] || // left\n !shapeMask[idx + 1] || // right\n !shapeMask[idx - width] || // top\n !shapeMask[idx + width] || // bottom\n !shapeMask[idx - width - 1] || // top-left\n !shapeMask[idx - width + 1] || // top-right\n !shapeMask[idx + width - 1] || // bottom-left\n !shapeMask[idx + width + 1]; // bottom-right\n }\n\n if (isBoundary) {\n boundaryMask[idx] = 1;\n boundaryIndices.push(idx);\n } else {\n interiorIndices.push(idx);\n }\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);\n console.log(\n ` Shape pixels: ${shapePixelCount} / ${width * height} (${((shapePixelCount / (width * height)) * 100).toFixed(1)}%)`\n );\n console.log(` Interior pixels: ${interiorIndices.length}`);\n console.log(` Boundary pixels: ${boundaryIndices.length}`);\n }\n\n // 3) Precompute sparse data structure for solver\n const sparseData = buildSparseData(\n shapeMask,\n boundaryMask,\n new Uint32Array(interiorIndices),\n new Uint32Array(boundaryIndices),\n width,\n height\n );\n\n // 4) Solve Poisson equation with optimized sparse solver\n const startSolve = performance.now();\n const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);\n }\n\n // 5) Generate output image\n let maxVal = 0;\n let finalImageData: ImageData;\n\n // Only check shape pixels for max value\n for (let i = 0; i < interiorIndices.length; i++) {\n const idx = interiorIndices[i]!;\n if (u[idx]! > maxVal) maxVal = u[idx]!;\n }\n\n // Create gradient image at working resolution\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = width;\n tempCanvas.height = height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n const tempImg = tempCtx.createImageData(width, height);\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const px = idx * 4;\n\n if (!shapeMask[idx]) {\n tempImg.data[px] = 255;\n tempImg.data[px + 1] = 255;\n tempImg.data[px + 2] = 255;\n tempImg.data[px + 3] = 0; // Alpha = 0 for background\n } else {\n const poissonRatio = u[idx]! / maxVal;\n const gray = 255 * (1 - poissonRatio);\n tempImg.data[px] = gray;\n tempImg.data[px + 1] = gray;\n tempImg.data[px + 2] = gray;\n tempImg.data[px + 3] = 255; // Alpha = 255 for shape\n }\n }\n }\n tempCtx.putImageData(tempImg, 0, 0);\n\n // Upscale to original resolution with smooth interpolation\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);\n\n // Now get the upscaled image data for final output\n const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Re-apply edges from original resolution with anti-aliasing\n // This ensures edges are pixel-perfect while gradient is smooth\n const originalCanvas = document.createElement('canvas');\n originalCanvas.width = originalWidth;\n originalCanvas.height = originalHeight;\n const originalCtx = originalCanvas.getContext('2d')!;\n // originalCtx.fillStyle = \"white\";\n // originalCtx.fillRect(0, 0, originalWidth, originalHeight);\n originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);\n const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Process each pixel: Red channel = gradient, Alpha channel = original alpha\n for (let i = 0; i < outImg.data.length; i += 4) {\n const a = originalData.data[i + 3]!;\n // Use only alpha to determine background vs shape\n const upscaledAlpha = outImg.data[i + 3]!;\n if (a === 0) {\n // Background pixel\n outImg.data[i] = 255;\n outImg.data[i + 1] = 0;\n } else {\n // Red channel carries the gradient\n // Check if upscale missed this pixel by looking at alpha channel\n // If upscaled alpha is 0, the low-res version thought this was background\n outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]!; // gradient or 0\n outImg.data[i + 1] = a; // original alpha\n }\n\n // Unused channels fixed\n outImg.data[i + 2] = 255;\n outImg.data[i + 3] = 255;\n }\n\n ctx.putImageData(outImg, 0, 0);\n finalImageData = outImg;\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const totalTime = performance.now() - totalStartTime;\n console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);\n if (scaleFactor < 1) {\n const estimatedFullResTime = totalTime * Math.pow((originalWidth * originalHeight) / (width * height), 1.5);\n console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);\n console.log(\n `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\u00D7 faster)`\n );\n }\n }\n\n resolve({\n imageData: finalImageData,\n pngBlob: blob,\n });\n }, 'image/png');\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\nfunction buildSparseData(\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n interiorPixels: Uint32Array,\n boundaryPixels: Uint32Array,\n width: number,\n height: number\n): SparsePixelData {\n const pixelCount = interiorPixels.length;\n\n // Build neighbor indices for sparse processing\n // For each interior pixel, store indices of its 4 neighbors\n // Use -1 for out-of-bounds or non-shape neighbors\n const neighborIndices = new Int32Array(pixelCount * 4);\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n // East neighbor\n neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;\n // West neighbor\n neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;\n // North neighbor\n neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;\n // South neighbor\n neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;\n }\n\n return {\n interiorPixels,\n boundaryPixels,\n pixelCount,\n neighborIndices,\n };\n}\n\nfunction solvePoissonSparse(\n sparseData: SparsePixelData,\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n width: number,\n height: number\n): Float32Array {\n // This controls how smooth the falloff gradient will be and extend into the shape\n const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;\n\n // Keep C constant - only iterations control gradient spread\n const C = 0.01;\n\n const u = new Float32Array(width * height);\n const { interiorPixels, neighborIndices, pixelCount } = sparseData;\n\n // Performance tracking\n const startTime = performance.now();\n\n // Red-Black SOR for better symmetry with fewer iterations\n // omega between 1.8-1.95 typically gives best convergence for Poisson\n const omega = 1.9;\n\n // Pre-classify pixels as red or black for efficient processing\n const redPixels: number[] = [];\n const blackPixels: number[] = [];\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n if ((x + y) % 2 === 0) {\n redPixels.push(i);\n } else {\n blackPixels.push(i);\n }\n }\n\n for (let iter = 0; iter < ITERATIONS; iter++) {\n // Red pass: update red pixels\n for (const i of redPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n\n // Black pass: update black pixels\n for (const i of blackPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const elapsed = performance.now() - startTime;\n\n console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);\n console.log(` Working size: ${width}\u00D7${height}`);\n console.log(` Iterations: ${ITERATIONS}`);\n console.log(` Time: ${elapsed.toFixed(2)}ms`);\n console.log(` Interior pixels processed: ${pixelCount}`);\n console.log(` Speed: ${((ITERATIONS * pixelCount) / (elapsed * 1000)).toFixed(2)} Mpixels/sec`);\n }\n\n return u;\n}\n\nexport interface LiquidMetalUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorTint: [number, number, number, number];\n u_image: HTMLImageElement | string | undefined;\n u_repetition: number;\n u_shiftRed: number;\n u_shiftBlue: number;\n u_contour: number;\n u_softness: number;\n u_distortion: number;\n u_angle: number;\n u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape];\n u_isImage: boolean;\n}\n\nexport interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorTint?: string;\n image?: HTMLImageElement | string | undefined;\n repetition?: number;\n shiftRed?: number;\n shiftBlue?: number;\n contour?: number;\n softness?: number;\n distortion?: number;\n angle?: number;\n shape?: LiquidMetalShape;\n}\n\nexport const LiquidMetalShapes = {\n none: 0,\n circle: 1,\n daisy: 2,\n diamond: 3,\n metaballs: 4,\n} as const;\n\nexport type LiquidMetalShape = keyof typeof LiquidMetalShapes;\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,cAAc,uBAAuB;AA+C7D,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8B9C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6RX,eAAgB;AAAA;AAAA;AAAA;AAAA;AAOd,MAAM,2BAA2B;AAAA,EACtC,oBAAoB;AAAA;AAAA,EACpB,aAAa;AAAA;AAAA,EACb,YAAY;AAAA;AACd;AAYO,SAAS,uBAAuB,MAAuE;AAC5G,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAM,SAAS,OAAO,SAAS,YAAY,KAAK,WAAW,OAAO;AAElE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,CAAC,QAAQ,CAAC,KAAK;AACjB,aAAO,IAAI,MAAM,gCAAgC,CAAC;AAClD;AAAA,IACF;AAEA,UAAM,yBAAyB,UAAU,MAAM,IAAI,EAAE,KAAK,CAAC,QAAQ,IAAI,QAAQ,IAAI,cAAc,CAAC;AAClG,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,cAAc;AAClB,UAAM,iBAAiB,YAAY,IAAI;AAEvC,QAAI,SAAS,YAAY;AAEvB,UAAI;AAEJ,YAAM,kBAAkB,MAAM;AAE9B,UAAI,iBAAiB;AACnB,gBAAQ,oBAAoB;AAAA,MAC9B,WAAW,OAAO,SAAS,UAAU;AACnC,gBAAQ,KAAK,SAAS,MAAM,KAAK,KAAK,WAAW,oBAAoB;AAAA,MACvE,OAAO;AACL,gBAAQ,KAAK,SAAS;AAAA,MACxB;AAEA,UAAI,gBAAgB,IAAI,SAAS,IAAI;AACrC,UAAI,iBAAiB,IAAI,UAAU,IAAI;AAEvC,UAAI,OAAO;AAET,cAAM,aAAa;AACnB,cAAM,cAAc,gBAAgB;AAEpC,YAAI,gBAAgB,gBAAgB;AAClC,0BAAgB;AAChB,2BAAiB,aAAa;AAAA,QAChC,OAAO;AACL,2BAAiB;AACjB,0BAAgB,aAAa;AAAA,QAC/B;AAEA,YAAI,QAAQ;AACZ,YAAI,SAAS;AAAA,MACf;AAGA,YAAM,eAAe,KAAK,IAAI,eAAe,cAAc;AAC3D,YAAM,aAAa,yBAAyB;AAG5C,YAAM,cAAc,aAAa;AACjC,YAAM,QAAQ,KAAK,MAAM,gBAAgB,WAAW;AACpD,YAAM,SAAS,KAAK,MAAM,iBAAiB,WAAW;AAEtD,UAAI,yBAAyB,oBAAoB;AAC/C,gBAAQ,IAAI,mBAAmB;AAC/B,gBAAQ,IAAI,eAAe,aAAa,OAAI,cAAc,EAAE;AAC5D,gBAAQ,IAAI,cAAc,KAAK,OAAI,MAAM,MAAM,cAAc,KAAK,QAAQ,CAAC,CAAC,UAAU;AACtF,YAAI,cAAc,GAAG;AACnB,kBAAQ,IAAI,eAAe,KAAK,MAAM,KAAK,cAAc,YAAY,CAAC,MAAG;AAAA,QAC3E;AAAA,MACF;AAEA,aAAO,QAAQ;AACf,aAAO,SAAS;AAGhB,YAAM,cAAc,SAAS,cAAc,QAAQ;AACnD,kBAAY,QAAQ;AACpB,kBAAY,SAAS;AAErB,YAAM,WAAW,YAAY,WAAW,IAAI;AAC5C,eAAS,UAAU,KAAK,GAAG,GAAG,OAAO,MAAM;AAG3C,YAAM,YAAY,YAAY,IAAI;AAElC,YAAM,iBAAiB,SAAS,aAAa,GAAG,GAAG,OAAO,MAAM;AAChE,YAAM,OAAO,eAAe;AAG5B,YAAM,YAAY,IAAI,WAAW,QAAQ,MAAM;AAC/C,YAAM,eAAe,IAAI,WAAW,QAAQ,MAAM;AAGlD,UAAI,kBAAkB;AACtB,eAAS,IAAI,GAAG,MAAM,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG,OAAO;AACvD,cAAM,IAAI,KAAK,IAAI,CAAC;AACpB,cAAM,UAAU,MAAM,IAAI,IAAI;AAC9B,kBAAU,GAAG,IAAI;AACjB,2BAAmB;AAAA,MACrB;AAIA,YAAM,kBAA4B,CAAC;AACnC,YAAM,kBAA4B,CAAC;AAEnC,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,iBAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,gBAAM,MAAM,IAAI,QAAQ;AACxB,cAAI,CAAC,UAAU,GAAG,EAAG;AAGrB,cAAI,aAAa;AAGjB,cAAI,MAAM,KAAK,MAAM,QAAQ,KAAK,MAAM,KAAK,MAAM,SAAS,GAAG;AAC7D,yBAAa;AAAA,UACf,OAAO;AAEL,yBACE,CAAC,UAAU,MAAM,CAAC;AAAA,YAClB,CAAC,UAAU,MAAM,CAAC;AAAA,YAClB,CAAC,UAAU,MAAM,KAAK;AAAA,YACtB,CAAC,UAAU,MAAM,KAAK;AAAA,YACtB,CAAC,UAAU,MAAM,QAAQ,CAAC;AAAA,YAC1B,CAAC,UAAU,MAAM,QAAQ,CAAC;AAAA,YAC1B,CAAC,UAAU,MAAM,QAAQ,CAAC;AAAA,YAC1B,CAAC,UAAU,MAAM,QAAQ,CAAC;AAAA,UAC9B;AAEA,cAAI,YAAY;AACd,yBAAa,GAAG,IAAI;AACpB,4BAAgB,KAAK,GAAG;AAAA,UAC1B,OAAO;AACL,4BAAgB,KAAK,GAAG;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAEA,UAAI,yBAAyB,oBAAoB;AAC/C,gBAAQ,IAAI,0BAA0B,YAAY,IAAI,IAAI,WAAW,QAAQ,CAAC,CAAC,IAAI;AACnF,gBAAQ;AAAA,UACN,mBAAmB,eAAe,MAAM,QAAQ,MAAM,MAAO,mBAAmB,QAAQ,UAAW,KAAK,QAAQ,CAAC,CAAC;AAAA,QACpH;AACA,gBAAQ,IAAI,sBAAsB,gBAAgB,MAAM,EAAE;AAC1D,gBAAQ,IAAI,sBAAsB,gBAAgB,MAAM,EAAE;AAAA,MAC5D;AAGA,YAAM,aAAa;AAAA,QACjB;AAAA,QACA;AAAA,QACA,IAAI,YAAY,eAAe;AAAA,QAC/B,IAAI,YAAY,eAAe;AAAA,QAC/B;AAAA,QACA;AAAA,MACF;AAGA,YAAM,aAAa,YAAY,IAAI;AACnC,YAAM,IAAI,mBAAmB,YAAY,WAAW,cAAc,OAAO,MAAM;AAE/E,UAAI,yBAAyB,oBAAoB;AAC/C,gBAAQ,IAAI,0BAA0B,YAAY,IAAI,IAAI,YAAY,QAAQ,CAAC,CAAC,IAAI;AAAA,MACtF;AAGA,UAAI,SAAS;AACb,UAAI;AAGJ,eAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;AAC/C,cAAM,MAAM,gBAAgB,CAAC;AAC7B,YAAI,EAAE,GAAG,IAAK,OAAQ,UAAS,EAAE,GAAG;AAAA,MACtC;AAGA,YAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,iBAAW,QAAQ;AACnB,iBAAW,SAAS;AACpB,YAAM,UAAU,WAAW,WAAW,IAAI;AAE1C,YAAM,UAAU,QAAQ,gBAAgB,OAAO,MAAM;AACrD,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,iBAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,gBAAM,MAAM,IAAI,QAAQ;AACxB,gBAAM,KAAK,MAAM;AAEjB,cAAI,CAAC,UAAU,GAAG,GAAG;AACnB,oBAAQ,KAAK,EAAE,IAAI;AACnB,oBAAQ,KAAK,KAAK,CAAC,IAAI;AACvB,oBAAQ,KAAK,KAAK,CAAC,IAAI;AACvB,oBAAQ,KAAK,KAAK,CAAC,IAAI;AAAA,UACzB,OAAO;AACL,kBAAM,eAAe,EAAE,GAAG,IAAK;AAC/B,kBAAM,OAAO,OAAO,IAAI;AACxB,oBAAQ,KAAK,EAAE,IAAI;AACnB,oBAAQ,KAAK,KAAK,CAAC,IAAI;AACvB,oBAAQ,KAAK,KAAK,CAAC,IAAI;AACvB,oBAAQ,KAAK,KAAK,CAAC,IAAI;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AACA,cAAQ,aAAa,SAAS,GAAG,CAAC;AAGlC,UAAI,wBAAwB;AAC5B,UAAI,wBAAwB;AAC5B,UAAI,UAAU,YAAY,GAAG,GAAG,OAAO,QAAQ,GAAG,GAAG,eAAe,cAAc;AAGlF,YAAM,SAAS,IAAI,aAAa,GAAG,GAAG,eAAe,cAAc;AAInE,YAAM,iBAAiB,SAAS,cAAc,QAAQ;AACtD,qBAAe,QAAQ;AACvB,qBAAe,SAAS;AACxB,YAAM,cAAc,eAAe,WAAW,IAAI;AAGlD,kBAAY,UAAU,KAAK,GAAG,GAAG,eAAe,cAAc;AAC9D,YAAM,eAAe,YAAY,aAAa,GAAG,GAAG,eAAe,cAAc;AAGjF,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK,QAAQ,KAAK,GAAG;AAC9C,cAAM,IAAI,aAAa,KAAK,IAAI,CAAC;AAEjC,cAAM,gBAAgB,OAAO,KAAK,IAAI,CAAC;AACvC,YAAI,MAAM,GAAG;AAEX,iBAAO,KAAK,CAAC,IAAI;AACjB,iBAAO,KAAK,IAAI,CAAC,IAAI;AAAA,QACvB,OAAO;AAIL,iBAAO,KAAK,CAAC,IAAI,kBAAkB,IAAI,IAAI,OAAO,KAAK,CAAC;AACxD,iBAAO,KAAK,IAAI,CAAC,IAAI;AAAA,QACvB;AAGA,eAAO,KAAK,IAAI,CAAC,IAAI;AACrB,eAAO,KAAK,IAAI,CAAC,IAAI;AAAA,MACvB;AAEA,UAAI,aAAa,QAAQ,GAAG,CAAC;AAC7B,uBAAiB;AACjB,aAAO,OAAO,CAAC,SAAS;AACtB,YAAI,CAAC,MAAM;AACT,iBAAO,IAAI,MAAM,2BAA2B,CAAC;AAC7C;AAAA,QACF;AAEA,YAAI,yBAAyB,oBAAoB;AAC/C,gBAAM,YAAY,YAAY,IAAI,IAAI;AACtC,kBAAQ,IAAI,2BAA2B,UAAU,QAAQ,CAAC,CAAC,IAAI;AAC/D,cAAI,cAAc,GAAG;AACnB,kBAAM,uBAAuB,YAAY,KAAK,IAAK,gBAAgB,kBAAmB,QAAQ,SAAS,GAAG;AAC1G,oBAAQ,IAAI,wCAAwC,qBAAqB,QAAQ,CAAC,CAAC,IAAI;AACvF,oBAAQ;AAAA,cACN,kBAAkB,uBAAuB,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,MAAM,uBAAuB,SAAS,CAAC;AAAA,YACnH;AAAA,UACF;AAAA,QACF;AAEA,gBAAQ;AAAA,UACN,WAAW;AAAA,UACX,SAAS;AAAA,QACX,CAAC;AAAA,MACH,GAAG,WAAW;AAAA,IAChB;AAEA,QAAI,UAAU,MAAM,OAAO,IAAI,MAAM,sBAAsB,CAAC;AAC5D,QAAI,MAAM,OAAO,SAAS,WAAW,OAAO,IAAI,gBAAgB,IAAI;AAAA,EACtE,CAAC;AACH;AAEA,SAAS,gBACP,WACA,cACA,gBACA,gBACA,OACA,QACiB;AACjB,QAAM,aAAa,eAAe;AAKlC,QAAM,kBAAkB,IAAI,WAAW,aAAa,CAAC;AAErD,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,UAAM,MAAM,eAAe,CAAC;AAC5B,UAAM,IAAI,MAAM;AAChB,UAAM,IAAI,KAAK,MAAM,MAAM,KAAK;AAGhC,oBAAgB,IAAI,IAAI,CAAC,IAAI,IAAI,QAAQ,KAAK,UAAU,MAAM,CAAC,IAAI,MAAM,IAAI;AAE7E,oBAAgB,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,UAAU,MAAM,CAAC,IAAI,MAAM,IAAI;AAErE,oBAAgB,IAAI,IAAI,CAAC,IAAI,IAAI,KAAK,UAAU,MAAM,KAAK,IAAI,MAAM,QAAQ;AAE7E,oBAAgB,IAAI,IAAI,CAAC,IAAI,IAAI,SAAS,KAAK,UAAU,MAAM,KAAK,IAAI,MAAM,QAAQ;AAAA,EACxF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,mBACP,YACA,WACA,cACA,OACA,QACc;AAEd,QAAM,aAAa,yBAAyB;AAG5C,QAAM,IAAI;AAEV,QAAM,IAAI,IAAI,aAAa,QAAQ,MAAM;AACzC,QAAM,EAAE,gBAAgB,iBAAiB,WAAW,IAAI;AAGxD,QAAM,YAAY,YAAY,IAAI;AAIlC,QAAM,QAAQ;AAGd,QAAM,YAAsB,CAAC;AAC7B,QAAM,cAAwB,CAAC;AAE/B,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,UAAM,MAAM,eAAe,CAAC;AAC5B,UAAM,IAAI,MAAM;AAChB,UAAM,IAAI,KAAK,MAAM,MAAM,KAAK;AAEhC,SAAK,IAAI,KAAK,MAAM,GAAG;AACrB,gBAAU,KAAK,CAAC;AAAA,IAClB,OAAO;AACL,kBAAY,KAAK,CAAC;AAAA,IACpB;AAAA,EACF;AAEA,WAAS,OAAO,GAAG,OAAO,YAAY,QAAQ;AAE5C,eAAW,KAAK,WAAW;AACzB,YAAM,MAAM,eAAe,CAAC;AAG5B,YAAM,UAAU,gBAAgB,IAAI,IAAI,CAAC;AACzC,YAAM,UAAU,gBAAgB,IAAI,IAAI,CAAC;AACzC,YAAM,WAAW,gBAAgB,IAAI,IAAI,CAAC;AAC1C,YAAM,WAAW,gBAAgB,IAAI,IAAI,CAAC;AAG1C,UAAI,OAAO;AACX,UAAI,WAAW,EAAG,SAAQ,EAAE,OAAO;AACnC,UAAI,WAAW,EAAG,SAAQ,EAAE,OAAO;AACnC,UAAI,YAAY,EAAG,SAAQ,EAAE,QAAQ;AACrC,UAAI,YAAY,EAAG,SAAQ,EAAE,QAAQ;AAGrC,YAAM,YAAY,IAAI,QAAQ;AAC9B,QAAE,GAAG,IAAI,QAAQ,YAAY,IAAI,SAAS,EAAE,GAAG;AAAA,IACjD;AAGA,eAAW,KAAK,aAAa;AAC3B,YAAM,MAAM,eAAe,CAAC;AAG5B,YAAM,UAAU,gBAAgB,IAAI,IAAI,CAAC;AACzC,YAAM,UAAU,gBAAgB,IAAI,IAAI,CAAC;AACzC,YAAM,WAAW,gBAAgB,IAAI,IAAI,CAAC;AAC1C,YAAM,WAAW,gBAAgB,IAAI,IAAI,CAAC;AAG1C,UAAI,OAAO;AACX,UAAI,WAAW,EAAG,SAAQ,EAAE,OAAO;AACnC,UAAI,WAAW,EAAG,SAAQ,EAAE,OAAO;AACnC,UAAI,YAAY,EAAG,SAAQ,EAAE,QAAQ;AACrC,UAAI,YAAY,EAAG,SAAQ,EAAE,QAAQ;AAGrC,YAAM,YAAY,IAAI,QAAQ;AAC9B,QAAE,GAAG,IAAI,QAAQ,YAAY,IAAI,SAAS,EAAE,GAAG;AAAA,IACjD;AAAA,EACF;AAEA,MAAI,yBAAyB,oBAAoB;AAC/C,UAAM,UAAU,YAAY,IAAI,IAAI;AAEpC,YAAQ,IAAI,yCAAoC,KAAK,IAAI;AACzD,YAAQ,IAAI,mBAAmB,KAAK,OAAI,MAAM,EAAE;AAChD,YAAQ,IAAI,iBAAiB,UAAU,EAAE;AACzC,YAAQ,IAAI,WAAW,QAAQ,QAAQ,CAAC,CAAC,IAAI;AAC7C,YAAQ,IAAI,gCAAgC,UAAU,EAAE;AACxD,YAAQ,IAAI,aAAc,aAAa,cAAe,UAAU,MAAO,QAAQ,CAAC,CAAC,cAAc;AAAA,EACjG;AAEA,SAAO;AACT;AA+BO,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,WAAW;AACb;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/mesh-gradient.d.ts b/public/vendor/paper-shaders/shaders/mesh-gradient.d.ts
new file mode 100644
index 0000000..bb51942
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/mesh-gradient.d.ts
@@ -0,0 +1,52 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const meshGradientMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * A flowing composition of color spots, moving along distinct trajectories
+ * and transformed by organic distortion.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colors (vec4[]): Up to 10 color spots in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_distortion (float): Power of organic noise distortion (0 to 1)
+ * - u_swirl (float): Power of vortex distortion (0 to 1)
+ * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)
+ * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const meshGradientFragmentShader: string;
+export interface MeshGradientUniforms extends ShaderSizingUniforms {
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_distortion: number;
+ u_swirl: number;
+ u_grainMixer: number;
+ u_grainOverlay: number;
+}
+export interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ distortion?: number;
+ swirl?: number;
+ grainMixer?: number;
+ grainOverlay?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/mesh-gradient.js b/public/vendor/paper-shaders/shaders/mesh-gradient.js
new file mode 100644
index 0000000..49b4f2b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/mesh-gradient.js
@@ -0,0 +1,127 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {
+} from "../shader-sizing.js";
+import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
+const meshGradientMeta = {
+ maxColorCount: 10
+};
+const meshGradientFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform vec4 u_colors[${meshGradientMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_distortion;
+uniform float u_swirl;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+
+in vec2 v_objectUV;
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${proceduralHash21}
+
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = hash21(i);
+ float b = hash21(i + vec2(1.0, 0.0));
+ float c = hash21(i + vec2(0.0, 1.0));
+ float d = hash21(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float noise(vec2 n, vec2 seedOffset) {
+ return valueNoise(n + seedOffset);
+}
+
+vec2 getPosition(int i, float t) {
+ float a = float(i) * .37;
+ float b = .6 + fract(float(i) / 3.) * .9;
+ float c = .8 + fract(float(i + 1) / 4.);
+
+ float x = sin(t * b + a);
+ float y = cos(t * c + a * 1.5);
+
+ return .5 + .5 * vec2(x, y);
+}
+
+void main() {
+ vec2 uv = v_objectUV;
+ uv += .5;
+ vec2 grainUV = uv * 1000.;
+
+ float grain = noise(grainUV, vec2(0.));
+ float mixerGrain = .4 * u_grainMixer * (grain - .5);
+
+ const float firstFrameOffset = 41.5;
+ float t = .5 * (u_time + firstFrameOffset);
+
+ float radius = smoothstep(0., 1., length(uv - .5));
+ float center = 1. - radius;
+ for (float i = 1.; i <= 2.; i++) {
+ uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., uv.y));
+ uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., uv.x));
+ }
+
+ vec2 uvRotated = uv;
+ uvRotated -= vec2(.5);
+ float angle = 3. * u_swirl * radius;
+ uvRotated = rotate(uvRotated, -angle);
+ uvRotated += vec2(.5);
+
+ vec3 color = vec3(0.);
+ float opacity = 0.;
+ float totalWeight = 0.;
+
+ for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+
+ vec2 pos = getPosition(i, t) + mixerGrain;
+ vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;
+ float opacityFraction = u_colors[i].a;
+
+ float dist = length(uvRotated - pos);
+
+ dist = pow(dist, 3.5);
+ float weight = 1. / (dist + 1e-3);
+ color += colorFraction * weight;
+ opacity += opacityFraction * weight;
+ totalWeight += weight;
+ }
+
+ color /= max(1e-4, totalWeight);
+ opacity /= max(1e-4, totalWeight);
+
+ float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));
+ grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
+ grainOverlay = pow(grainOverlay, 1.3);
+
+ float grainOverlayV = grainOverlay * 2. - 1.;
+ vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
+ float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
+ grainOverlayStrength = pow(grainOverlayStrength, .8);
+ color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);
+
+ opacity += .5 * grainOverlayStrength;
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ meshGradientFragmentShader,
+ meshGradientMeta
+};
+//# sourceMappingURL=mesh-gradient.js.map
diff --git a/public/vendor/paper-shaders/shaders/mesh-gradient.js.map b/public/vendor/paper-shaders/shaders/mesh-gradient.js.map
new file mode 100644
index 0000000..baf1522
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/mesh-gradient.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/mesh-gradient.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const meshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A flowing composition of color spots, moving along distinct trajectories\n * and transformed by organic distortion.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colors (vec4[]): Up to 10 color spots in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_distortion (float): Power of organic noise distortion (0 to 1)\n * - u_swirl (float): Power of vortex distortion (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const meshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${meshGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_distortion;\nuniform float u_swirl;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${proceduralHash21}\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(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 noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + fract(float(i) / 3.) * .9;\n float c = .8 + fract(float(i + 1) / 4.);\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv += .5;\n vec2 grainUV = uv * 1000.;\n\n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n const float firstFrameOffset = 41.5;\n float t = .5 * (u_time + firstFrameOffset);\n\n float radius = smoothstep(0., 1., length(uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., uv.y));\n uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., uv.x));\n }\n\n vec2 uvRotated = uv;\n uvRotated -= vec2(.5);\n float angle = 3. * u_swirl * radius;\n uvRotated = rotate(uvRotated, -angle);\n uvRotated += vec2(.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n\n for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, t) + mixerGrain;\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float dist = length(uvRotated - pos);\n\n dist = pow(dist, 3.5);\n float weight = 1. / (dist + 1e-3);\n color += colorFraction * weight;\n opacity += opacityFraction * weight;\n totalWeight += weight;\n }\n\n color /= max(1e-4, totalWeight);\n opacity /= max(1e-4, totalWeight);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface MeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_distortion: number;\n u_swirl: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n distortion?: number;\n swirl?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
+ "mappings": ";;;;;AAEA;AAAA,OAGO;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAkCO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAK1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,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,wBA0DM,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;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/metaballs.d.ts b/public/vendor/paper-shaders/shaders/metaballs.d.ts
new file mode 100644
index 0000000..bf6cae2
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/metaballs.d.ts
@@ -0,0 +1,51 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const metaballsMeta: {
+ readonly maxColorCount: 8;
+ readonly maxBallsCount: 20;
+};
+/**
+ * Up to 20 colored gooey balls moving around the center and merging into smooth organic shapes.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 8 base colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_count (float): Number of balls (1 to 20)
+ * - u_size (float): Size of the balls (0 to 1)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const metaballsFragmentShader: string;
+export interface MetaballsUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_count: number;
+ u_size: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface MetaballsParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ count?: number;
+ size?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/metaballs.js b/public/vendor/paper-shaders/shaders/metaballs.js
new file mode 100644
index 0000000..36fb85a
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/metaballs.js
@@ -0,0 +1,112 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, textureRandomizerR, colorBandingFix } from "../shader-utils.js";
+const metaballsMeta = {
+ maxColorCount: 8,
+ maxBallsCount: 20
+};
+const metaballsFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${metaballsMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_size;
+uniform float u_sizeRange;
+uniform float u_count;
+
+in vec2 v_objectUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${textureRandomizerR}
+float noise(float x) {
+ float i = floor(x);
+ float f = fract(x);
+ float u = f * f * (3.0 - 2.0 * f);
+ vec2 p0 = vec2(i, 0.0);
+ vec2 p1 = vec2(i + 1.0, 0.0);
+ return mix(randomR(p0), randomR(p1), u);
+}
+
+float getBallShape(vec2 uv, vec2 c, float p) {
+ float s = .5 * length(uv - c);
+ s = 1. - clamp(s, 0., 1.);
+ s = pow(s, p);
+ return s;
+}
+
+void main() {
+ vec2 shape_uv = v_objectUV;
+
+ shape_uv += .5;
+
+ const float firstFrameOffset = 2503.4;
+ float t = .2 * (u_time + firstFrameOffset);
+
+ vec3 totalColor = vec3(0.);
+ float totalShape = 0.;
+ float totalOpacity = 0.;
+
+ for (int i = 0; i < ${metaballsMeta.maxBallsCount}; i++) {
+ if (i >= int(ceil(u_count))) break;
+
+ float idxFract = float(i) / float(${metaballsMeta.maxBallsCount});
+ float angle = TWO_PI * idxFract;
+
+ float speed = 1. - .2 * idxFract;
+ float noiseX = noise(angle * 10. + float(i) + t * speed);
+ float noiseY = noise(angle * 20. + float(i) - t * speed);
+
+ vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noiseX, noiseY) - .5);
+
+ int safeIndex = i % int(u_colorsCount + 0.5);
+ vec4 ballColor = u_colors[safeIndex];
+ ballColor.rgb *= ballColor.a;
+
+ float sizeFrac = 1.;
+ if (float(i) > floor(u_count - 1.)) {
+ sizeFrac *= fract(u_count);
+ }
+
+ float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);
+ shape *= pow(u_size, .2);
+ shape = smoothstep(0., 1., shape);
+
+ totalColor += ballColor.rgb * shape;
+ totalShape += shape;
+ totalOpacity += ballColor.a * shape;
+ }
+
+ totalColor /= max(totalShape, 1e-4);
+ totalOpacity /= max(totalShape, 1e-4);
+
+ float edge_width = fwidth(totalShape);
+ float finalShape = smoothstep(.4, .4 + edge_width, totalShape);
+
+ vec3 color = totalColor * finalShape;
+ float opacity = totalOpacity * finalShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1. - opacity);
+ opacity = opacity + u_colorBack.a * (1. - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ metaballsFragmentShader,
+ metaballsMeta
+};
+//# sourceMappingURL=metaballs.js.map
diff --git a/public/vendor/paper-shaders/shaders/metaballs.js.map b/public/vendor/paper-shaders/shaders/metaballs.js.map
new file mode 100644
index 0000000..82beb34
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/metaballs.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/metaballs.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerR, colorBandingFix } from '../shader-utils.js';\n\nexport const metaballsMeta = {\n maxColorCount: 8,\n maxBallsCount: 20,\n} as const;\n\n/**\n * Up to 20 colored gooey balls moving around the center and merging into smooth organic shapes.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 8 base colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_count (float): Number of balls (1 to 20)\n * - u_size (float): Size of the balls (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const metaballsFragmentShader: 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[${ metaballsMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_size;\nuniform float u_sizeRange;\nuniform float u_count;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ textureRandomizerR }\nfloat noise(float x) {\n float i = floor(x);\n float f = fract(x);\n float u = f * f * (3.0 - 2.0 * f);\n vec2 p0 = vec2(i, 0.0);\n vec2 p1 = vec2(i + 1.0, 0.0);\n return mix(randomR(p0), randomR(p1), u);\n}\n\nfloat getBallShape(vec2 uv, vec2 c, float p) {\n float s = .5 * length(uv - c);\n s = 1. - clamp(s, 0., 1.);\n s = pow(s, p);\n return s;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n shape_uv += .5;\n\n const float firstFrameOffset = 2503.4;\n float t = .2 * (u_time + firstFrameOffset);\n\n vec3 totalColor = vec3(0.);\n float totalShape = 0.;\n float totalOpacity = 0.;\n\n for (int i = 0; i < ${ metaballsMeta.maxBallsCount }; i++) {\n if (i >= int(ceil(u_count))) break;\n\n float idxFract = float(i) / float(${ metaballsMeta.maxBallsCount });\n float angle = TWO_PI * idxFract;\n\n float speed = 1. - .2 * idxFract;\n float noiseX = noise(angle * 10. + float(i) + t * speed);\n float noiseY = noise(angle * 20. + float(i) - t * speed);\n\n vec2 pos = vec2(.5) + 1e-4 + .9 * (vec2(noiseX, noiseY) - .5);\n\n int safeIndex = i % int(u_colorsCount + 0.5);\n vec4 ballColor = u_colors[safeIndex];\n ballColor.rgb *= ballColor.a;\n\n float sizeFrac = 1.;\n if (float(i) > floor(u_count - 1.)) {\n sizeFrac *= fract(u_count);\n }\n\n float shape = getBallShape(shape_uv, pos, 45. - 30. * u_size * sizeFrac);\n shape *= pow(u_size, .2);\n shape = smoothstep(0., 1., shape);\n\n totalColor += ballColor.rgb * shape;\n totalShape += shape;\n totalOpacity += ballColor.a * shape;\n }\n\n totalColor /= max(totalShape, 1e-4);\n totalOpacity /= max(totalShape, 1e-4);\n\n float edge_width = fwidth(totalShape);\n float finalShape = smoothstep(.4, .4 + edge_width, totalShape);\n\n vec3 color = totalColor * finalShape;\n float opacity = totalOpacity * finalShape;\n\n 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 MetaballsUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_count: number;\n u_size: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface MetaballsParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n count?: number;\n size?: number;\n}\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,eAAe;AACjB;AAiCO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQtB,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUlD,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA6BG,cAAc,aAAc;AAAA;AAAA;AAAA,wCAGZ,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAwChE,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/neuro-noise.d.ts b/public/vendor/paper-shaders/shaders/neuro-noise.d.ts
new file mode 100644
index 0000000..7ee1883
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/neuro-noise.d.ts
@@ -0,0 +1,49 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * A glowing, web-like structure of fluid lines and soft intersections.
+ * Great for creating atmospheric, organic-yet-futuristic visuals.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_colorFront (vec4): Graphics highlight color in RGBA
+ * - u_colorMid (vec4): Graphics main color in RGBA
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_brightness (float): Luminosity of the crossing points (0 to 1)
+ * - u_contrast (float): Sharpness of the bright-dark transition (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ * Original algorithm: https://x.com/zozuar/status/1625182758745128981/
+ */
+export declare const neuroNoiseFragmentShader: string;
+export interface NeuroNoiseUniforms extends ShaderSizingUniforms {
+ u_colorFront: [number, number, number, number];
+ u_colorMid: [number, number, number, number];
+ u_colorBack: [number, number, number, number];
+ u_brightness: number;
+ u_contrast: number;
+}
+export interface NeuroNoiseParams extends ShaderSizingParams, ShaderMotionParams {
+ colorFront?: string;
+ colorMid?: string;
+ colorBack?: string;
+ brightness?: number;
+ contrast?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/neuro-noise.js b/public/vendor/paper-shaders/shaders/neuro-noise.js
new file mode 100644
index 0000000..29a5533
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/neuro-noise.js
@@ -0,0 +1,79 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { rotation2, colorBandingFix } from "../shader-utils.js";
+const neuroNoiseFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+uniform vec2 u_resolution;
+uniform float u_pixelRatio;
+
+uniform vec4 u_colorFront;
+uniform vec4 u_colorMid;
+uniform vec4 u_colorBack;
+uniform float u_brightness;
+uniform float u_contrast;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${rotation2}
+
+float neuroShape(vec2 uv, float t) {
+ vec2 sine_acc = vec2(0.);
+ vec2 res = vec2(0.);
+ float scale = 8.;
+
+ for (int j = 0; j < 15; j++) {
+ uv = rotate(uv, 1.);
+ sine_acc = rotate(sine_acc, 1.);
+ vec2 layer = uv * scale + float(j) + sine_acc - t;
+ sine_acc += sin(layer);
+ res += (.5 + .5 * cos(layer)) / scale;
+ scale *= (1.2);
+ }
+ return res.x + res.y;
+}
+
+void main() {
+ vec2 shape_uv = v_patternUV;
+ shape_uv *= .13;
+
+ float t = .5 * u_time;
+
+ float noise = neuroShape(shape_uv, t);
+
+ noise = (1. + u_brightness) * noise * noise;
+ noise = pow(noise, .7 + 6. * u_contrast);
+ noise = min(1.4, noise);
+
+ float blend = smoothstep(0.7, 1.4, noise);
+
+ vec4 frontC = u_colorFront;
+ frontC.rgb *= frontC.a;
+ vec4 midC = u_colorMid;
+ midC.rgb *= midC.a;
+ vec4 blendFront = mix(midC, frontC, blend);
+
+ float safeNoise = max(noise, 0.0);
+ vec3 color = blendFront.rgb * safeNoise;
+ float opacity = clamp(blendFront.a * safeNoise, 0., 1.);
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1. - opacity);
+ opacity = opacity + u_colorBack.a * (1. - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ neuroNoiseFragmentShader
+};
+//# sourceMappingURL=neuro-noise.js.map
diff --git a/public/vendor/paper-shaders/shaders/neuro-noise.js.map b/public/vendor/paper-shaders/shaders/neuro-noise.js.map
new file mode 100644
index 0000000..9280f31
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/neuro-noise.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/neuro-noise.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, colorBandingFix } from '../shader-utils.js';\n\n/**\n * A glowing, web-like structure of fluid lines and soft intersections.\n * Great for creating atmospheric, organic-yet-futuristic visuals.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_colorFront (vec4): Graphics highlight color in RGBA\n * - u_colorMid (vec4): Graphics main color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_brightness (float): Luminosity of the crossing points (0 to 1)\n * - u_contrast (float): Sharpness of the bright-dark transition (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n * Original algorithm: https://x.com/zozuar/status/1625182758745128981/\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\nin vec2 v_patternUV;\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) * noise * noise;\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"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,uBAAuB;AAoCpC,MAAM,2BAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB7C,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8CR,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/paper-texture.d.ts b/public/vendor/paper-shaders/shaders/paper-texture.d.ts
new file mode 100644
index 0000000..9e8b324
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/paper-texture.d.ts
@@ -0,0 +1,78 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * A static texture built from multiple noise layers, usable for realistic paper and cardboard surfaces.
+ * Can be used as an image filter or as a standalone texture.
+ *
+ * Fragment shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_image (sampler2D): Optional source image texture
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorFront (vec4): Foreground color in RGBA
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_contrast (float): Blending behavior, sharper vs smoother color transitions (0 to 1)
+ * - u_roughness (float): Pixel noise, related to canvas and not scalable (0 to 1)
+ * - u_fiber (float): Curly-shaped noise intensity (0 to 1)
+ * - u_fiberSize (float): Curly-shaped noise scale (0 to 1)
+ * - u_crumples (float): Cell-based crumple pattern intensity (0 to 1)
+ * - u_crumpleSize (float): Cell-based crumple pattern scale (0 to 1)
+ * - u_folds (float): Depth of the folds (0 to 1)
+ * - u_foldCount (float): Number of folds (1 to 15)
+ * - u_fade (float): Big-scale noise mask applied to the pattern (0 to 1)
+ * - u_drops (float): Visibility of speckle pattern (0 to 1)
+ * - u_seed (float): Seed applied to folds, crumples and dots (0 to 1000)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const paperTextureFragmentShader: string;
+export interface PaperTextureUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string | undefined;
+ u_noiseTexture?: HTMLImageElement;
+ u_colorFront: [number, number, number, number];
+ u_colorBack: [number, number, number, number];
+ u_contrast: number;
+ u_roughness: number;
+ u_fiber: number;
+ u_fiberSize: number;
+ u_crumples: number;
+ u_foldCount: number;
+ u_folds: number;
+ u_fade: number;
+ u_crumpleSize: number;
+ u_drops: number;
+ u_seed: number;
+}
+export interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {
+ image?: HTMLImageElement | string;
+ colorFront?: string;
+ colorBack?: string;
+ contrast?: number;
+ roughness?: number;
+ fiber?: number;
+ fiberSize?: number;
+ crumples?: number;
+ foldCount?: number;
+ folds?: number;
+ fade?: number;
+ crumpleSize?: number;
+ drops?: number;
+ seed?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/paper-texture.js b/public/vendor/paper-shaders/shaders/paper-texture.js
new file mode 100644
index 0000000..f926128
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/paper-texture.js
@@ -0,0 +1,248 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { rotation2, declarePI, fiberNoise, textureRandomizerR } from "../shader-utils.js";
+const paperTextureFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec2 u_resolution;
+uniform float u_pixelRatio;
+
+uniform vec4 u_colorFront;
+uniform vec4 u_colorBack;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform float u_contrast;
+uniform float u_roughness;
+uniform float u_fiber;
+uniform float u_fiberSize;
+uniform float u_crumples;
+uniform float u_crumpleSize;
+uniform float u_folds;
+uniform float u_foldCount;
+uniform float u_drops;
+uniform float u_seed;
+uniform float u_fade;
+
+uniform sampler2D u_noiseTexture;
+
+in vec2 v_imageUV;
+
+out vec4 fragColor;
+
+float getUvFrame(vec2 uv) {
+ float aax = 2. * fwidth(uv.x);
+ float aay = 2. * fwidth(uv.y);
+
+ float left = smoothstep(0., aax, uv.x);
+ float right = 1. - smoothstep(1. - aax, 1., uv.x);
+ float bottom = smoothstep(0., aay, uv.y);
+ float top = 1. - smoothstep(1. - aay, 1., uv.y);
+
+ return left * right * bottom * top;
+}
+
+${declarePI}
+${rotation2}
+${textureRandomizerR}
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = randomR(i);
+ float b = randomR(i + vec2(1.0, 0.0));
+ float c = randomR(i + vec2(0.0, 1.0));
+ float d = randomR(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+float fbm(vec2 n) {
+ float total = 0.0, amplitude = .4;
+ for (int i = 0; i < 3; i++) {
+ total += valueNoise(n) * amplitude;
+ n *= 1.99;
+ amplitude *= 0.65;
+ }
+ return total;
+}
+
+
+float randomG(vec2 p) {
+ vec2 uv = floor(p) / 50. + .5;
+ return texture(u_noiseTexture, fract(uv)).g;
+}
+float roughness(vec2 p) {
+ p *= .1;
+ float o = 0.;
+ for (float i = 0.; ++i < 4.; p *= 2.1) {
+ vec4 w = vec4(floor(p), ceil(p));
+ vec2 f = fract(p);
+ o += mix(
+ mix(randomG(w.xy), randomG(w.xw), f.y),
+ mix(randomG(w.zy), randomG(w.zw), f.y),
+ f.x);
+ o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));
+ }
+ return o / 3.;
+}
+
+${fiberNoise}
+
+vec2 randomGB(vec2 p) {
+ vec2 uv = floor(p) / 50. + .5;
+ return texture(u_noiseTexture, fract(uv)).gb;
+}
+float crumpledNoise(vec2 t, float pw) {
+ vec2 p = floor(t);
+ float wsum = 0.;
+ float cl = 0.;
+ for (int y = -1; y < 2; y += 1) {
+ for (int x = -1; x < 2; x += 1) {
+ vec2 b = vec2(float(x), float(y));
+ vec2 q = b + p;
+ vec2 q2 = q - floor(q / 8.) * 8.;
+ vec2 c = q + randomGB(q2);
+ vec2 r = c - t;
+ float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);
+ cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;
+ wsum += w;
+ }
+ }
+ return pow(wsum != 0.0 ? cl / wsum : 0.0, .5) * 2.;
+}
+float crumplesShape(vec2 uv) {
+ return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);
+}
+
+
+vec2 folds(vec2 uv) {
+ vec3 pp = vec3(0.);
+ float l = 9.;
+ for (float i = 0.; i < 15.; i++) {
+ if (i >= u_foldCount) break;
+ vec2 rand = randomGB(vec2(i, i * u_seed));
+ float an = rand.x * TWO_PI;
+ vec2 p = vec2(cos(an), sin(an)) * rand.y;
+ float dist = distance(uv, p);
+ l = min(l, dist);
+
+ if (l == dist) {
+ pp.xy = (uv - p.xy);
+ pp.z = dist;
+ }
+ }
+ return mix(pp.xy, vec2(0.), pow(pp.z, .25));
+}
+
+float drops(vec2 uv) {
+ vec2 iDropsUV = floor(uv);
+ vec2 fDropsUV = fract(uv);
+ float dropsMinDist = 1.;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 neighbor = vec2(float(i), float(j));
+ vec2 offset = randomGB(iDropsUV + neighbor);
+ offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset);
+ vec2 pos = neighbor + offset - fDropsUV;
+ float dist = length(pos);
+ dropsMinDist = min(dropsMinDist, dropsMinDist*dist);
+ }
+ }
+ return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));
+}
+
+float lst(float edge0, float edge1, float x) {
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+}
+
+void main() {
+
+ vec2 imageUV = v_imageUV;
+ vec2 patternUV = v_imageUV - .5;
+ patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.));
+
+ vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;
+ float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));
+
+ vec2 crumplesUV = fract(patternUV * .02 / u_crumpleSize - u_seed) * 32.;
+ float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));
+
+ vec2 fiberUV = 2. / u_fiberSize * patternUV;
+ float fiber = fiberNoise(fiberUV, vec2(0.));
+ fiber = .5 * u_fiber * (fiber - 1.);
+
+ vec2 normal = vec2(0.);
+ vec2 normalImage = vec2(0.);
+
+ vec2 foldsUV = patternUV * .12;
+ foldsUV = rotate(foldsUV, 4. * u_seed);
+ vec2 w = folds(foldsUV);
+ foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed));
+ vec2 w2 = folds(foldsUV);
+
+ float drops = u_drops * drops(patternUV * 2.);
+
+ float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed);
+ fade = clamp(8. * fade * fade * fade, 0., 1.);
+
+ w = mix(w, vec2(0.), fade);
+ w2 = mix(w2, vec2(0.), fade);
+ crumples = mix(crumples, 0., fade);
+ drops = mix(drops, 0., fade);
+ fiber *= mix(1., .5, fade);
+ roughness *= mix(1., .5, fade);
+
+ normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);
+ normalImage.xy += u_folds * 2. * w;
+
+ normal.xy += crumples;
+ normalImage.xy += 1.5 * crumples;
+
+ normal.xy += 3. * drops;
+ normalImage.xy += .2 * drops;
+
+ normal.xy += u_roughness * 1.5 * roughness;
+ normal.xy += fiber;
+
+ normalImage += u_roughness * .75 * roughness;
+ normalImage += .2 * fiber;
+
+ vec3 lightPos = vec3(1., 2., 1.);
+ float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos));
+
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+
+ imageUV += .02 * normalImage;
+ float frame = getUvFrame(imageUV);
+ vec4 image = texture(u_image, imageUV);
+ image.rgb += .6 * pow(u_contrast, .4) * (res - .7);
+
+ frame *= image.a;
+
+ vec3 color = fgColor * res;
+ float opacity = fgOpacity * res;
+
+ color += bgColor * (1. - opacity);
+ opacity += bgOpacity * (1. - opacity);
+ opacity = mix(opacity, 1., frame);
+
+ color -= .007 * drops;
+
+ color.rgb = mix(color, image.rgb, frame);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ paperTextureFragmentShader
+};
+//# sourceMappingURL=paper-texture.js.map
diff --git a/public/vendor/paper-shaders/shaders/paper-texture.js.map b/public/vendor/paper-shaders/shaders/paper-texture.js.map
new file mode 100644
index 0000000..d189405
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/paper-texture.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/paper-texture.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * A static texture built from multiple noise layers, usable for realistic paper and cardboard surfaces.\n * Can be used as an image filter or as a standalone texture.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_image (sampler2D): Optional source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_contrast (float): Blending behavior, sharper vs smoother color transitions (0 to 1)\n * - u_roughness (float): Pixel noise, related to canvas and not scalable (0 to 1)\n * - u_fiber (float): Curly-shaped noise intensity (0 to 1)\n * - u_fiberSize (float): Curly-shaped noise scale (0 to 1)\n * - u_crumples (float): Cell-based crumple pattern intensity (0 to 1)\n * - u_crumpleSize (float): Cell-based crumple pattern scale (0 to 1)\n * - u_folds (float): Depth of the folds (0 to 1)\n * - u_foldCount (float): Number of folds (1 to 15)\n * - u_fade (float): Big-scale noise mask applied to the pattern (0 to 1)\n * - u_drops (float): Visibility of speckle pattern (0 to 1)\n * - u_seed (float): Seed applied to folds, crumples and dots (0 to 1000)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\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_fiberSize;\nuniform float u_crumples;\nuniform float u_crumpleSize;\nuniform float u_folds;\nuniform float u_foldCount;\nuniform float u_drops;\nuniform float u_seed;\nuniform float u_fade;\n\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_imageUV;\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 = 1. - smoothstep(1. - aax, 1., uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = 1. - smoothstep(1. - aay, 1., 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(wsum != 0.0 ? cl / wsum : 0.0, .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_foldCount) 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\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\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 * .02 / u_crumpleSize - u_seed) * 32.;\n float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));\n\n vec2 fiberUV = 2. / u_fiberSize * 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 float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed);\n fade = clamp(8. * fade * fade * fade, 0., 1.);\n\n w = mix(w, vec2(0.), fade);\n w2 = mix(w2, vec2(0.), fade);\n crumples = mix(crumples, 0., fade);\n drops = mix(drops, 0., fade);\n fiber *= mix(1., .5, fade);\n roughness *= mix(1., .5, fade);\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 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 vec4 image = texture(u_image, imageUV);\n image.rgb += .6 * pow(u_contrast, .4) * (res - .7);\n\n frame *= image.a;\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 color.rgb = mix(color, image.rgb, frame);\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_fiberSize: number;\n u_crumples: number;\n u_foldCount: number;\n u_folds: number;\n u_fade: number;\n u_crumpleSize: number;\n u_drops: number;\n u_seed: number;\n}\n\nexport interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n contrast?: number;\n roughness?: number;\n fiber?: number;\n fiberSize?: number;\n crumples?: number;\n foldCount?: number;\n folds?: number;\n fade?: number;\n crumpleSize?: number;\n drops?: number;\n seed?: number;\n}\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,YAAY,0BAA0B;AA8C9D,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0C/C,SAAU;AAAA,EACV,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2CnB,UAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/perlin-noise.d.ts b/public/vendor/paper-shaders/shaders/perlin-noise.d.ts
new file mode 100644
index 0000000..b7cf4aa
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/perlin-noise.d.ts
@@ -0,0 +1,52 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Classic animated 3D Perlin noise with exposed controls.
+ * Original algorithm: https://www.shadertoy.com/view/NlSGDz
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorFront (vec4): Foreground color in RGBA
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_proportion (float): Blend point between 2 colors, 0.5 = equal distribution (0 to 1)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ * - u_octaveCount (float): Perlin noise octaves number, more octaves for more detailed patterns (1 to 8)
+ * - u_persistence (float): Roughness, falloff between octaves (0.3 to 1)
+ * - u_lacunarity (float): Frequency step, defines how compressed the pattern is (1.5 to 10)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const perlinNoiseFragmentShader: string;
+export interface PerlinNoiseUniforms extends ShaderSizingUniforms {
+ u_colorFront: [number, number, number, number];
+ u_colorBack: [number, number, number, number];
+ u_proportion: number;
+ u_softness: number;
+ u_octaveCount: number;
+ u_persistence: number;
+ u_lacunarity: number;
+}
+export interface PerlinNoiseParams extends ShaderSizingParams, ShaderMotionParams {
+ colorFront?: string;
+ colorBack?: string;
+ proportion?: number;
+ softness?: number;
+ octaveCount?: number;
+ persistence?: number;
+ lacunarity?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/perlin-noise.js b/public/vendor/paper-shaders/shaders/perlin-noise.js
new file mode 100644
index 0000000..941bff1
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/perlin-noise.js
@@ -0,0 +1,173 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, colorBandingFix, proceduralHash11, proceduralHash21 } from "../shader-utils.js";
+const perlinNoiseFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform vec4 u_colorFront;
+uniform vec4 u_colorBack;
+uniform float u_proportion;
+uniform float u_softness;
+uniform float u_octaveCount;
+uniform float u_persistence;
+uniform float u_lacunarity;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${proceduralHash11}
+${proceduralHash21}
+
+float hash31(vec3 p) {
+ p = fract(p * 0.3183099) + 0.1;
+ p += dot(p, p.yzx + 19.19);
+ return fract(p.x * (p.y + p.z));
+}
+
+vec3 gradientPredefined(float hash) {
+ int idx = int(hash * 12.0) % 12;
+
+ if (idx == 0) return vec3(1, 1, 0);
+ if (idx == 1) return vec3(-1, 1, 0);
+ if (idx == 2) return vec3(1, -1, 0);
+ if (idx == 3) return vec3(-1, -1, 0);
+ if (idx == 4) return vec3(1, 0, 1);
+ if (idx == 5) return vec3(-1, 0, 1);
+ if (idx == 6) return vec3(1, 0, -1);
+ if (idx == 7) return vec3(-1, 0, -1);
+ if (idx == 8) return vec3(0, 1, 1);
+ if (idx == 9) return vec3(0, -1, 1);
+ if (idx == 10) return vec3(0, 1, -1);
+ return vec3(0, -1, -1);// idx == 11
+}
+
+float interpolateSafe(float v000, float v001, float v010, float v011,
+float v100, float v101, float v110, float v111, vec3 t) {
+ t = clamp(t, 0.0, 1.0);
+
+ float v00 = mix(v000, v100, t.x);
+ float v01 = mix(v001, v101, t.x);
+ float v10 = mix(v010, v110, t.x);
+ float v11 = mix(v011, v111, t.x);
+
+ float v0 = mix(v00, v10, t.y);
+ float v1 = mix(v01, v11, t.y);
+
+ return mix(v0, v1, t.z);
+}
+
+vec3 fade(vec3 t) {
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
+}
+
+float perlinNoise(vec3 position, float seed) {
+ position += vec3(seed * 127.1, seed * 311.7, seed * 74.7);
+
+ vec3 i = floor(position);
+ vec3 f = fract(position);
+ float h000 = hash31(i);
+ float h001 = hash31(i + vec3(0, 0, 1));
+ float h010 = hash31(i + vec3(0, 1, 0));
+ float h011 = hash31(i + vec3(0, 1, 1));
+ float h100 = hash31(i + vec3(1, 0, 0));
+ float h101 = hash31(i + vec3(1, 0, 1));
+ float h110 = hash31(i + vec3(1, 1, 0));
+ float h111 = hash31(i + vec3(1, 1, 1));
+ vec3 g000 = gradientPredefined(h000);
+ vec3 g001 = gradientPredefined(h001);
+ vec3 g010 = gradientPredefined(h010);
+ vec3 g011 = gradientPredefined(h011);
+ vec3 g100 = gradientPredefined(h100);
+ vec3 g101 = gradientPredefined(h101);
+ vec3 g110 = gradientPredefined(h110);
+ vec3 g111 = gradientPredefined(h111);
+ float v000 = dot(g000, f - vec3(0, 0, 0));
+ float v001 = dot(g001, f - vec3(0, 0, 1));
+ float v010 = dot(g010, f - vec3(0, 1, 0));
+ float v011 = dot(g011, f - vec3(0, 1, 1));
+ float v100 = dot(g100, f - vec3(1, 0, 0));
+ float v101 = dot(g101, f - vec3(1, 0, 1));
+ float v110 = dot(g110, f - vec3(1, 1, 0));
+ float v111 = dot(g111, f - vec3(1, 1, 1));
+
+ vec3 u = fade(f);
+ return interpolateSafe(v000, v001, v010, v011, v100, v101, v110, v111, u);
+}
+
+float p_noise(vec3 position, int octaveCount, float persistence, float lacunarity) {
+ float value = 0.0;
+ float amplitude = 1.0;
+ float frequency = 10.0;
+ float maxValue = 0.0;
+ octaveCount = clamp(octaveCount, 1, 8);
+
+ for (int i = 0; i < octaveCount; i++) {
+ float seed = float(i) * 0.7319;
+ value += perlinNoise(position * frequency, seed) * amplitude;
+ maxValue += amplitude;
+ amplitude *= persistence;
+ frequency *= lacunarity;
+ }
+ return value;
+}
+
+float get_max_amp(float persistence, float octaveCount) {
+ persistence = clamp(persistence * 0.999, 0.0, 0.999);
+ octaveCount = clamp(octaveCount, 1.0, 8.0);
+
+ if (abs(persistence - 1.0) < 0.001) {
+ return octaveCount;
+ }
+
+ return (1.0 - pow(persistence, octaveCount)) / max(1e-4, (1.0 - persistence));
+}
+
+void main() {
+ vec2 uv = v_patternUV;
+ uv *= .5;
+
+ float t = .2 * u_time;
+
+ vec3 p = vec3(uv, t);
+
+ float octCount = floor(u_octaveCount);
+ float noise = p_noise(p, int(octCount), u_persistence, u_lacunarity);
+
+ float max_amp = get_max_amp(u_persistence, octCount);
+ float noise_normalized = clamp((noise + max_amp) / max(1e-4, (2. * max_amp)) + (u_proportion - .5), 0.0, 1.0);
+ float sharpness = clamp(u_softness, 0., 1.);
+ float smooth_w = 0.5 * max(fwidth(noise_normalized), 0.001);
+ float res = smoothstep(
+ .5 - .5 * sharpness - smooth_w,
+ .5 + .5 * sharpness + smooth_w,
+ noise_normalized
+ );
+
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+
+ vec3 color = fgColor * res;
+ float opacity = fgOpacity * res;
+
+ color += bgColor * (1. - opacity);
+ opacity += bgOpacity * (1. - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ perlinNoiseFragmentShader
+};
+//# sourceMappingURL=perlin-noise.js.map
diff --git a/public/vendor/paper-shaders/shaders/perlin-noise.js.map b/public/vendor/paper-shaders/shaders/perlin-noise.js.map
new file mode 100644
index 0000000..500a8d6
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/perlin-noise.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/perlin-noise.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, colorBandingFix, proceduralHash11, proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Classic animated 3D Perlin noise with exposed controls.\n * Original algorithm: https://www.shadertoy.com/view/NlSGDz\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_proportion (float): Blend point between 2 colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_octaveCount (float): Perlin noise octaves number, more octaves for more detailed patterns (1 to 8)\n * - u_persistence (float): Roughness, falloff between octaves (0.3 to 1)\n * - u_lacunarity (float): Frequency step, defines how compressed the pattern is (1.5 to 10)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const perlinNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform float u_proportion;\nuniform float u_softness;\nuniform float u_octaveCount;\nuniform float u_persistence;\nuniform float u_lacunarity;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ proceduralHash11 }\n${ proceduralHash21 }\n\nfloat hash31(vec3 p) {\n p = fract(p * 0.3183099) + 0.1;\n p += dot(p, p.yzx + 19.19);\n return fract(p.x * (p.y + p.z));\n}\n\nvec3 gradientPredefined(float hash) {\n int idx = int(hash * 12.0) % 12;\n\n if (idx == 0) return vec3(1, 1, 0);\n if (idx == 1) return vec3(-1, 1, 0);\n if (idx == 2) return vec3(1, -1, 0);\n if (idx == 3) return vec3(-1, -1, 0);\n if (idx == 4) return vec3(1, 0, 1);\n if (idx == 5) return vec3(-1, 0, 1);\n if (idx == 6) return vec3(1, 0, -1);\n if (idx == 7) return vec3(-1, 0, -1);\n if (idx == 8) return vec3(0, 1, 1);\n if (idx == 9) return vec3(0, -1, 1);\n if (idx == 10) return vec3(0, 1, -1);\n return vec3(0, -1, -1);// idx == 11\n}\n\nfloat interpolateSafe(float v000, float v001, float v010, float v011,\nfloat v100, float v101, float v110, float v111, vec3 t) {\n t = clamp(t, 0.0, 1.0);\n\n float v00 = mix(v000, v100, t.x);\n float v01 = mix(v001, v101, t.x);\n float v10 = mix(v010, v110, t.x);\n float v11 = mix(v011, v111, t.x);\n\n float v0 = mix(v00, v10, t.y);\n float v1 = mix(v01, v11, t.y);\n\n return mix(v0, v1, t.z);\n}\n\nvec3 fade(vec3 t) {\n return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n}\n\nfloat perlinNoise(vec3 position, float seed) {\n position += vec3(seed * 127.1, seed * 311.7, seed * 74.7);\n\n vec3 i = floor(position);\n vec3 f = fract(position);\n float h000 = hash31(i);\n float h001 = hash31(i + vec3(0, 0, 1));\n float h010 = hash31(i + vec3(0, 1, 0));\n float h011 = hash31(i + vec3(0, 1, 1));\n float h100 = hash31(i + vec3(1, 0, 0));\n float h101 = hash31(i + vec3(1, 0, 1));\n float h110 = hash31(i + vec3(1, 1, 0));\n float h111 = hash31(i + vec3(1, 1, 1));\n vec3 g000 = gradientPredefined(h000);\n vec3 g001 = gradientPredefined(h001);\n vec3 g010 = gradientPredefined(h010);\n vec3 g011 = gradientPredefined(h011);\n vec3 g100 = gradientPredefined(h100);\n vec3 g101 = gradientPredefined(h101);\n vec3 g110 = gradientPredefined(h110);\n vec3 g111 = gradientPredefined(h111);\n float v000 = dot(g000, f - vec3(0, 0, 0));\n float v001 = dot(g001, f - vec3(0, 0, 1));\n float v010 = dot(g010, f - vec3(0, 1, 0));\n float v011 = dot(g011, f - vec3(0, 1, 1));\n float v100 = dot(g100, f - vec3(1, 0, 0));\n float v101 = dot(g101, f - vec3(1, 0, 1));\n float v110 = dot(g110, f - vec3(1, 1, 0));\n float v111 = dot(g111, f - vec3(1, 1, 1));\n\n vec3 u = fade(f);\n return interpolateSafe(v000, v001, v010, v011, v100, v101, v110, v111, u);\n}\n\nfloat p_noise(vec3 position, int octaveCount, float persistence, float lacunarity) {\n float value = 0.0;\n float amplitude = 1.0;\n float frequency = 10.0;\n float maxValue = 0.0;\n octaveCount = clamp(octaveCount, 1, 8);\n\n for (int i = 0; i < octaveCount; i++) {\n float seed = float(i) * 0.7319;\n value += perlinNoise(position * frequency, seed) * amplitude;\n maxValue += amplitude;\n amplitude *= persistence;\n frequency *= lacunarity;\n }\n return value;\n}\n\nfloat get_max_amp(float persistence, float octaveCount) {\n persistence = clamp(persistence * 0.999, 0.0, 0.999);\n octaveCount = clamp(octaveCount, 1.0, 8.0);\n\n if (abs(persistence - 1.0) < 0.001) {\n return octaveCount;\n }\n\n return (1.0 - pow(persistence, octaveCount)) / max(1e-4, (1.0 - persistence));\n}\n\nvoid main() {\n vec2 uv = v_patternUV;\n uv *= .5;\n\n float t = .2 * u_time;\n\n vec3 p = vec3(uv, t);\n\n float octCount = floor(u_octaveCount);\n float noise = p_noise(p, int(octCount), u_persistence, u_lacunarity);\n\n float max_amp = get_max_amp(u_persistence, octCount);\n float noise_normalized = clamp((noise + max_amp) / max(1e-4, (2. * max_amp)) + (u_proportion - .5), 0.0, 1.0);\n float sharpness = clamp(u_softness, 0., 1.);\n float smooth_w = 0.5 * max(fwidth(noise_normalized), 0.001);\n float res = smoothstep(\n .5 - .5 * sharpness - smooth_w,\n .5 + .5 * sharpness + smooth_w,\n noise_normalized\n );\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 ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PerlinNoiseUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_proportion: number;\n u_softness: number;\n u_octaveCount: number;\n u_persistence: number;\n u_lacunarity: number;\n}\n\nexport interface PerlinNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colorFront?: string;\n colorBack?: string;\n proportion?: number;\n softness?: number;\n octaveCount?: number;\n persistence?: number;\n lacunarity?: number;\n}\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,iBAAiB,kBAAkB,wBAAwB;AAmCxE,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB9C,SAAU;AAAA,EACV,gBAAiB;AAAA,EACjB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA0If,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/pulsing-border.d.ts b/public/vendor/paper-shaders/shaders/pulsing-border.d.ts
new file mode 100644
index 0000000..06dace6
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/pulsing-border.d.ts
@@ -0,0 +1,98 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const pulsingBorderMeta: {
+ readonly maxColorCount: 5;
+ readonly maxSpots: 4;
+};
+/**
+ * Luminous trails of color merging into a glowing gradient contour.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 5 spot colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_roundness (float): Border radius (0 to 1)
+ * - u_thickness (float): Border base width (0 to 1)
+ * - u_softness (float): Border edge sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1)
+ * - u_marginRight (float): Distance from the right edge to the effect (0 to 1)
+ * - u_marginTop (float): Distance from the top edge to the effect (0 to 1)
+ * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1)
+ * - u_aspectRatio (float): Aspect ratio mode (0 = auto, 1 = square)
+ * - u_intensity (float): Thickness of individual color spots (0 to 1)
+ * - u_bloom (float): Power of glow, 0 = normal blending, 1 = additive blending (0 to 1)
+ * - u_spots (float): Number of spots added for each color (1 to 20)
+ * - u_spotSize (float): Angular size of spots (0 to 1)
+ * - u_pulse (float): Optional pulsing animation intensity (0 to 1)
+ * - u_smoke (float): Optional noisy shape extending the border (0 to 1)
+ * - u_smokeSize (float): Size of the smoke effect (0 to 1)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio
+ * - v_responsiveBoxGivenSize (vec2): Given size of the responsive bounding box
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for smoke calculation)
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const pulsingBorderFragmentShader: string;
+export interface PulsingBorderUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_roundness: number;
+ u_thickness: number;
+ u_marginLeft: number;
+ u_marginRight: number;
+ u_marginTop: number;
+ u_marginBottom: number;
+ u_aspectRatio: (typeof PulsingBorderAspectRatios)[PulsingBorderAspectRatio];
+ u_softness: number;
+ u_intensity: number;
+ u_bloom: number;
+ u_spots: number;
+ u_spotSize: number;
+ u_pulse: number;
+ u_smoke: number;
+ u_smokeSize: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ roundness?: number;
+ thickness?: number;
+ margin?: number;
+ marginLeft?: number;
+ marginRight?: number;
+ marginTop?: number;
+ marginBottom?: number;
+ aspectRatio?: PulsingBorderAspectRatio;
+ softness?: number;
+ intensity?: number;
+ bloom?: number;
+ spots?: number;
+ spotSize?: number;
+ pulse?: number;
+ smoke?: number;
+ smokeSize?: number;
+}
+export declare const PulsingBorderAspectRatios: {
+ readonly auto: 0;
+ readonly square: 1;
+};
+export type PulsingBorderAspectRatio = keyof typeof PulsingBorderAspectRatios;
diff --git a/public/vendor/paper-shaders/shaders/pulsing-border.js b/public/vendor/paper-shaders/shaders/pulsing-border.js
new file mode 100644
index 0000000..464e5f7
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/pulsing-border.js
@@ -0,0 +1,239 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, textureRandomizerGB, colorBandingFix } from "../shader-utils.js";
+const pulsingBorderMeta = {
+ maxColorCount: 5,
+ maxSpots: 4
+};
+const pulsingBorderFragmentShader = `#version 300 es
+precision lowp float;
+
+uniform float u_time;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_roundness;
+uniform float u_thickness;
+uniform float u_marginLeft;
+uniform float u_marginRight;
+uniform float u_marginTop;
+uniform float u_marginBottom;
+uniform float u_aspectRatio;
+uniform float u_softness;
+uniform float u_intensity;
+uniform float u_bloom;
+uniform float u_spotSize;
+uniform float u_spots;
+uniform float u_pulse;
+uniform float u_smoke;
+uniform float u_smokeSize;
+
+uniform sampler2D u_noiseTexture;
+
+in vec2 v_responsiveUV;
+in vec2 v_responsiveBoxGivenSize;
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+
+float beat(float time) {
+ float first = pow(abs(sin(time * TWO_PI)), 10.);
+ float second = pow(abs(sin((time - .15) * TWO_PI)), 10.);
+
+ return clamp(first + 0.6 * second, 0.0, 1.0);
+}
+
+float sst(float edge0, float edge1, float x) {
+ return smoothstep(edge0, edge1, x);
+}
+
+float roundedBox(vec2 uv, vec2 halfSize, float distance, float cornerDistance, float thickness, float softness) {
+ float borderDistance = abs(distance);
+ float aa = 2. * fwidth(distance);
+ float border = 1. - sst(min(mix(thickness, -thickness, softness), thickness + aa), max(mix(thickness, -thickness, softness), thickness + aa), borderDistance);
+ float cornerFadeCircles = 0.;
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv + halfSize) / thickness)));
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(-halfSize.x, halfSize.y)) / thickness)));
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(halfSize.x, -halfSize.y)) / thickness)));
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - halfSize) / thickness)));
+ aa = fwidth(cornerDistance);
+ float cornerFade = sst(0., mix(aa, thickness, softness), cornerDistance);
+ cornerFade *= cornerFadeCircles;
+ border += cornerFade;
+ return border;
+}
+
+${textureRandomizerGB}
+
+float randomG(vec2 p) {
+ vec2 uv = floor(p) / 100. + .5;
+ return texture(u_noiseTexture, fract(uv)).g;
+}
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = randomG(i);
+ float b = randomG(i + vec2(1.0, 0.0));
+ float c = randomG(i + vec2(0.0, 1.0));
+ float d = randomG(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+void main() {
+ const float firstFrameOffset = 109.;
+ float t = 1.2 * (u_time + firstFrameOffset);
+
+ vec2 borderUV = v_responsiveUV;
+ float pulse = u_pulse * beat(.18 * u_time);
+
+ float canvasRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
+ vec2 halfSize = vec2(.5);
+ borderUV.x *= max(canvasRatio, 1.);
+ borderUV.y /= min(canvasRatio, 1.);
+ halfSize.x *= max(canvasRatio, 1.);
+ halfSize.y /= min(canvasRatio, 1.);
+
+ float mL = u_marginLeft;
+ float mR = u_marginRight;
+ float mT = u_marginTop;
+ float mB = u_marginBottom;
+ float mX = mL + mR;
+ float mY = mT + mB;
+
+ if (u_aspectRatio > 0.) {
+ float shapeRatio = canvasRatio * (1. - mX) / max(1. - mY, 1e-6);
+ float freeX = shapeRatio > 1. ? (1. - mX) * (1. - 1. / max(abs(shapeRatio), 1e-6)) : 0.;
+ float freeY = shapeRatio < 1. ? (1. - mY) * (1. - shapeRatio) : 0.;
+ mL += freeX * 0.5;
+ mR += freeX * 0.5;
+ mT += freeY * 0.5;
+ mB += freeY * 0.5;
+ mX = mL + mR;
+ mY = mT + mB;
+ }
+
+ float thickness = .5 * u_thickness * min(halfSize.x, halfSize.y);
+
+ halfSize.x *= (1. - mX);
+ halfSize.y *= (1. - mY);
+
+ vec2 centerShift = vec2(
+ (mL - mR) * max(canvasRatio, 1.) * 0.5,
+ (mB - mT) / min(canvasRatio, 1.) * 0.5
+ );
+
+ borderUV -= centerShift;
+ halfSize -= mix(thickness, 0., u_softness);
+
+ float radius = mix(0., min(halfSize.x, halfSize.y), u_roundness);
+ vec2 d = abs(borderUV) - halfSize + radius;
+ float outsideDistance = length(max(d, .0001)) - radius;
+ float insideDistance = min(max(d.x, d.y), .0001);
+ float cornerDistance = abs(min(max(d.x, d.y) - .45 * radius, .0));
+ float distance = outsideDistance + insideDistance;
+
+ float borderThickness = mix(thickness, 3. * thickness, u_softness);
+ float border = roundedBox(borderUV, halfSize, distance, cornerDistance, borderThickness, u_softness);
+ border = pow(border, 1. + u_softness);
+
+ vec2 smokeUV = .3 * u_smokeSize * v_patternUV;
+ float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);
+ smoke -= valueNoise(3.4 * smokeUV - .5 * t);
+ float smokeThickness = thickness + .2;
+ smokeThickness = min(.4, max(smokeThickness, .1));
+ smoke *= roundedBox(borderUV, halfSize, distance, cornerDistance, smokeThickness, 1.);
+ smoke = 30. * smoke * smoke;
+ smoke *= mix(0., .5, pow(u_smoke, 2.));
+ smoke *= mix(1., pulse, u_pulse);
+ smoke = clamp(smoke, 0., 1.);
+ border += smoke;
+
+ border = clamp(border, 0., 1.);
+
+ vec3 blendColor = vec3(0.);
+ float blendAlpha = 0.;
+ vec3 addColor = vec3(0.);
+ float addAlpha = 0.;
+
+ float bloom = 4. * u_bloom;
+ float intensity = 1. + (1. + 4. * u_softness) * u_intensity;
+
+ float angle = atan(borderUV.y, borderUV.x) / TWO_PI;
+
+ for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {
+ if (colorIdx >= int(u_colorsCount)) break;
+ float colorIdxF = float(colorIdx);
+
+ vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a;
+ float a = u_colors[colorIdx].a;
+
+ for (int spotIdx = 0; spotIdx < ${pulsingBorderMeta.maxSpots}; spotIdx++) {
+ if (spotIdx >= int(u_spots)) break;
+ float spotIdxF = float(spotIdx);
+
+ vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));
+
+ float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;
+ time *= mix(1., -1., step(.5, randVal.y));
+
+ float mask = .5 + .5 * mix(
+ sin(t + spotIdxF * (5. - 1.5 * colorIdxF)),
+ cos(t + spotIdxF * (3. + 1.3 * colorIdxF)),
+ step(mod(colorIdxF, 2.), .5)
+ );
+
+ float p = clamp(2. * u_pulse - randVal.x, 0., 1.);
+ mask = mix(mask, pulse, p);
+
+ float atg1 = fract(angle + time);
+ float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;
+ spotSize = mix(spotSize, .1, p);
+ float sector = sst(.5 - spotSize, .5, atg1) * (1. - sst(.5, .5 + spotSize, atg1));
+
+ sector *= mask;
+ sector *= border;
+ sector *= intensity;
+ sector = clamp(sector, 0., 1.);
+
+ vec3 srcColor = c * sector;
+ float srcAlpha = a * sector;
+
+ blendColor += ((1. - blendAlpha) * srcColor);
+ blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha;
+ addColor += srcColor;
+ addAlpha += srcAlpha;
+ }
+ }
+
+ vec3 accumColor = mix(blendColor, addColor, bloom);
+ float accumAlpha = mix(blendAlpha, addAlpha, bloom);
+ accumAlpha = clamp(accumAlpha, 0., 1.);
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ vec3 color = accumColor + (1. - accumAlpha) * bgColor;
+ float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}`;
+const PulsingBorderAspectRatios = {
+ auto: 0,
+ square: 1
+};
+export {
+ PulsingBorderAspectRatios,
+ pulsingBorderFragmentShader,
+ pulsingBorderMeta
+};
+//# sourceMappingURL=pulsing-border.js.map
diff --git a/public/vendor/paper-shaders/shaders/pulsing-border.js.map b/public/vendor/paper-shaders/shaders/pulsing-border.js.map
new file mode 100644
index 0000000..7bef2aa
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/pulsing-border.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/pulsing-border.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { 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 * Luminous trails of color merging into a glowing gradient contour.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 5 spot colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_roundness (float): Border radius (0 to 1)\n * - u_thickness (float): Border base width (0 to 1)\n * - u_softness (float): Border edge sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_marginLeft (float): Distance from the left edge to the effect (0 to 1)\n * - u_marginRight (float): Distance from the right edge to the effect (0 to 1)\n * - u_marginTop (float): Distance from the top edge to the effect (0 to 1)\n * - u_marginBottom (float): Distance from the bottom edge to the effect (0 to 1)\n * - u_aspectRatio (float): Aspect ratio mode (0 = auto, 1 = square)\n * - u_intensity (float): Thickness of individual color spots (0 to 1)\n * - u_bloom (float): Power of glow, 0 = normal blending, 1 = additive blending (0 to 1)\n * - u_spots (float): Number of spots added for each color (1 to 20)\n * - u_spotSize (float): Angular size of spots (0 to 1)\n * - u_pulse (float): Optional pulsing animation intensity (0 to 1)\n * - u_smoke (float): Optional noisy shape extending the border (0 to 1)\n * - u_smokeSize (float): Size of the smoke effect (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio\n * - v_responsiveBoxGivenSize (vec2): Given size of the responsive bounding box\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for smoke calculation)\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\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_marginLeft;\nuniform float u_marginRight;\nuniform float u_marginTop;\nuniform float u_marginBottom;\nuniform float u_aspectRatio;\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\nin vec2 v_responsiveUV;\nin vec2 v_responsiveBoxGivenSize;\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n\nfloat beat(float time) {\n float first = pow(abs(sin(time * TWO_PI)), 10.);\n float second = pow(abs(sin((time - .15) * TWO_PI)), 10.);\n\n return clamp(first + 0.6 * second, 0.0, 1.0);\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nfloat roundedBox(vec2 uv, vec2 halfSize, float distance, float cornerDistance, float thickness, float softness) {\n float borderDistance = abs(distance);\n float aa = 2. * fwidth(distance);\n float border = 1. - sst(min(mix(thickness, -thickness, softness), thickness + aa), max(mix(thickness, -thickness, softness), thickness + aa), borderDistance);\n float cornerFadeCircles = 0.;\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv + halfSize) / thickness)));\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(-halfSize.x, halfSize.y)) / thickness)));\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(halfSize.x, -halfSize.y)) / thickness)));\n cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - halfSize) / thickness)));\n aa = fwidth(cornerDistance);\n float cornerFade = sst(0., mix(aa, thickness, softness), cornerDistance);\n cornerFade *= cornerFadeCircles;\n border += cornerFade;\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\nvoid main() {\n const float firstFrameOffset = 109.;\n float t = 1.2 * (u_time + firstFrameOffset);\n\n vec2 borderUV = v_responsiveUV;\n float pulse = u_pulse * beat(.18 * u_time);\n\n float canvasRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 halfSize = vec2(.5);\n borderUV.x *= max(canvasRatio, 1.);\n borderUV.y /= min(canvasRatio, 1.);\n halfSize.x *= max(canvasRatio, 1.);\n halfSize.y /= min(canvasRatio, 1.);\n\n float mL = u_marginLeft;\n float mR = u_marginRight;\n float mT = u_marginTop;\n float mB = u_marginBottom;\n float mX = mL + mR;\n float mY = mT + mB;\n\n if (u_aspectRatio > 0.) {\n float shapeRatio = canvasRatio * (1. - mX) / max(1. - mY, 1e-6);\n float freeX = shapeRatio > 1. ? (1. - mX) * (1. - 1. / max(abs(shapeRatio), 1e-6)) : 0.;\n float freeY = shapeRatio < 1. ? (1. - mY) * (1. - shapeRatio) : 0.;\n mL += freeX * 0.5;\n mR += freeX * 0.5;\n mT += freeY * 0.5;\n mB += freeY * 0.5;\n mX = mL + mR;\n mY = mT + mB;\n }\n\n float thickness = .5 * u_thickness * min(halfSize.x, halfSize.y);\n\n halfSize.x *= (1. - mX);\n halfSize.y *= (1. - mY);\n\n vec2 centerShift = vec2(\n (mL - mR) * max(canvasRatio, 1.) * 0.5,\n (mB - mT) / min(canvasRatio, 1.) * 0.5\n );\n\n borderUV -= centerShift;\n halfSize -= mix(thickness, 0., u_softness);\n\n float radius = mix(0., min(halfSize.x, halfSize.y), u_roundness);\n vec2 d = abs(borderUV) - halfSize + radius;\n float outsideDistance = length(max(d, .0001)) - radius;\n float insideDistance = min(max(d.x, d.y), .0001);\n float cornerDistance = abs(min(max(d.x, d.y) - .45 * radius, .0));\n float distance = outsideDistance + insideDistance;\n\n float borderThickness = mix(thickness, 3. * thickness, u_softness);\n float border = roundedBox(borderUV, halfSize, distance, cornerDistance, borderThickness, u_softness);\n border = pow(border, 1. + u_softness);\n\n vec2 smokeUV = .3 * 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 float smokeThickness = thickness + .2;\n smokeThickness = min(.4, max(smokeThickness, .1));\n smoke *= roundedBox(borderUV, halfSize, distance, cornerDistance, smokeThickness, 1.);\n smoke = 30. * smoke * smoke;\n smoke *= mix(0., .5, pow(u_smoke, 2.));\n smoke *= mix(1., pulse, u_pulse);\n smoke = clamp(smoke, 0., 1.);\n border += smoke;\n\n border = clamp(border, 0., 1.);\n\n vec3 blendColor = vec3(0.);\n float blendAlpha = 0.;\n vec3 addColor = vec3(0.);\n float addAlpha = 0.;\n\n float bloom = 4. * u_bloom;\n float intensity = 1. + (1. + 4. * u_softness) * u_intensity;\n\n float angle = atan(borderUV.y, borderUV.x) / TWO_PI;\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 = sst(.5 - spotSize, .5, atg1) * (1. - sst(.5, .5 + spotSize, 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_marginLeft: number;\n u_marginRight: number;\n u_marginTop: number;\n u_marginBottom: number;\n u_aspectRatio: (typeof PulsingBorderAspectRatios)[PulsingBorderAspectRatio];\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 margin?: number;\n marginLeft?: number;\n marginRight?: number;\n marginTop?: number;\n marginBottom?: number;\n aspectRatio?: PulsingBorderAspectRatio;\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\nexport const PulsingBorderAspectRatios = {\n auto: 0,\n square: 1,\n} as const;\n\nexport type PulsingBorderAspectRatio = keyof typeof PulsingBorderAspectRatios;\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,qBAAqB,uBAAuB;AAEzD,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AACZ;AAgDO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM1B,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BtD,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BV,mBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAoGgB,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAOhC,kBAAkB,QAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8C7D,eAAgB;AAAA;AAAA;AAAA;AAgDd,MAAM,4BAA4B;AAAA,EACvC,MAAM;AAAA,EACN,QAAQ;AACV;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/simplex-noise.d.ts b/public/vendor/paper-shaders/shaders/simplex-noise.d.ts
new file mode 100644
index 0000000..3d409a4
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/simplex-noise.d.ts
@@ -0,0 +1,46 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const simplexNoiseMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * A multi-color gradient mapped into smooth, animated curves built as a combination of 2 Simplex noises.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_scale (float): Overall zoom level, used for anti-aliasing calculations
+ * - u_colors (vec4[]): Up to 10 base colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2×N, etc. (1 to 10)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const simplexNoiseFragmentShader: string;
+export interface SimplexNoiseUniforms extends ShaderSizingUniforms {
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_stepsPerColor: number;
+ u_softness: number;
+}
+export interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ stepsPerColor?: number;
+ softness?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/simplex-noise.js b/public/vendor/paper-shaders/shaders/simplex-noise.js
new file mode 100644
index 0000000..5ececb0
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/simplex-noise.js
@@ -0,0 +1,100 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { simplexNoise, colorBandingFix } from "../shader-utils.js";
+const simplexNoiseMeta = {
+ maxColorCount: 10
+};
+const simplexNoiseFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+uniform float u_scale;
+
+uniform vec4 u_colors[${simplexNoiseMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_stepsPerColor;
+uniform float u_softness;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${simplexNoise}
+
+float getNoise(vec2 uv, float t) {
+ float noise = .5 * snoise(uv - vec2(0., .3 * t));
+ noise += .5 * snoise(2. * uv + vec2(0., .32 * t));
+
+ return noise;
+}
+
+float steppedSmooth(float m, float steps, float softness) {
+ float stepT = floor(m * steps) / steps;
+ float f = m * steps - floor(m * steps);
+ float fw = steps * fwidth(m);
+ float smoothed = smoothstep(.5 - softness, min(1., .5 + softness + fw), f);
+ return stepT + smoothed / steps;
+}
+
+void main() {
+ vec2 shape_uv = v_patternUV;
+ shape_uv *= .1;
+
+ float t = .2 * u_time;
+
+ float shape = .5 + .5 * getNoise(shape_uv, t);
+
+ bool u_extraSides = true;
+
+ float mixer = shape * (u_colorsCount - 1.);
+ if (u_extraSides == true) {
+ mixer = (shape - .5 / u_colorsCount) * u_colorsCount;
+ }
+
+ float steps = max(1., u_stepsPerColor);
+
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+ for (int i = 1; i < ${simplexNoiseMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+
+ float localM = clamp(mixer - float(i - 1), 0., 1.);
+ localM = steppedSmooth(localM, steps, .5 * u_softness);
+
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, localM);
+ }
+
+ if (u_extraSides == true) {
+ if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {
+ float localM = mixer + 1.;
+ if (mixer > (u_colorsCount - 1.)) {
+ localM = mixer - (u_colorsCount - 1.);
+ }
+ localM = steppedSmooth(localM, steps, .5 * u_softness);
+ vec4 cFst = u_colors[0];
+ cFst.rgb *= cFst.a;
+ vec4 cLast = u_colors[int(u_colorsCount - 1.)];
+ cLast.rgb *= cLast.a;
+ gradient = mix(cLast, cFst, localM);
+ }
+ }
+
+ vec3 color = gradient.rgb;
+ float opacity = gradient.a;
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ simplexNoiseFragmentShader,
+ simplexNoiseMeta
+};
+//# sourceMappingURL=simplex-noise.js.map
diff --git a/public/vendor/paper-shaders/shaders/simplex-noise.js.map b/public/vendor/paper-shaders/shaders/simplex-noise.js.map
new file mode 100644
index 0000000..b1febb3
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/simplex-noise.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/simplex-noise.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { 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 * A multi-color gradient mapped into smooth, animated curves built as a combination of 2 Simplex noises.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 10 base colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2\u00D7N, etc. (1 to 10)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\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\nin vec2 v_patternUV;\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"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,cAAc,uBAAuB;AAEvC,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAgCO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMzB,iBAAiB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrD,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAoCS,iBAAiB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA6BnD,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/smoke-ring.d.ts b/public/vendor/paper-shaders/shaders/smoke-ring.d.ts
new file mode 100644
index 0000000..07bd17e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/smoke-ring.d.ts
@@ -0,0 +1,61 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const smokeRingMeta: {
+ readonly maxColorCount: 10;
+ readonly maxNoiseIterations: 8;
+};
+/**
+ * Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic.
+ *
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 10 gradient colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_thickness (float): Thickness of the ring shape (0.01 to 1)
+ * - u_radius (float): Radius of the ring shape (0 to 1)
+ * - u_innerShape (float): Ring inner fill amount (0 to 4)
+ * - u_noiseIterations (float): Number of noise layers, more layers gives more details (1 to 8)
+ * - u_noiseScale (float): Noise frequency (0.01 to 5)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const smokeRingFragmentShader: string;
+export interface SmokeRingUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_noiseScale: number;
+ u_thickness: number;
+ u_radius: number;
+ u_innerShape: number;
+ u_noiseIterations: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ noiseScale?: number;
+ thickness?: number;
+ radius?: number;
+ innerShape?: number;
+ noiseIterations?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/smoke-ring.js b/public/vendor/paper-shaders/shaders/smoke-ring.js
new file mode 100644
index 0000000..aa6f126
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/smoke-ring.js
@@ -0,0 +1,133 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, textureRandomizerR, colorBandingFix } from "../shader-utils.js";
+const smokeRingMeta = {
+ maxColorCount: 10,
+ maxNoiseIterations: 8
+};
+const smokeRingFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${smokeRingMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_thickness;
+uniform float u_radius;
+uniform float u_innerShape;
+uniform float u_noiseScale;
+uniform float u_noiseIterations;
+
+in vec2 v_objectUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${textureRandomizerR}
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = randomR(i);
+ float b = randomR(i + vec2(1.0, 0.0));
+ float c = randomR(i + vec2(0.0, 1.0));
+ float d = randomR(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+vec2 fbm(vec2 n0, vec2 n1) {
+ vec2 total = vec2(0.0);
+ float amplitude = .4;
+ for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) {
+ if (i >= int(u_noiseIterations)) break;
+ total.x += valueNoise(n0) * amplitude;
+ total.y += valueNoise(n1) * amplitude;
+ n0 *= 1.99;
+ n1 *= 1.99;
+ amplitude *= 0.65;
+ }
+ return total;
+}
+
+float getNoise(vec2 uv, vec2 pUv, float t) {
+ vec2 pUvLeft = pUv + .03 * t;
+ float period = max(abs(u_noiseScale * TWO_PI), 1e-6);
+ vec2 pUvRight = vec2(fract(pUv.x / period) * period, pUv.y) + .03 * t;
+ vec2 noise = fbm(pUvLeft, pUvRight);
+ return mix(noise.y, noise.x, smoothstep(-.25, .25, uv.x));
+}
+
+float getRingShape(vec2 uv) {
+ float radius = u_radius;
+ float thickness = u_thickness;
+
+ float distance = length(uv);
+ float ringValue = 1. - smoothstep(radius, radius + thickness, distance);
+ ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance);
+
+ return ringValue;
+}
+
+void main() {
+ vec2 shape_uv = v_objectUV;
+
+ float t = u_time;
+
+ float cycleDuration = 3.;
+ float period2 = 2.0 * cycleDuration;
+ float localTime1 = fract((0.1 * t + cycleDuration) / period2) * period2;
+ float localTime2 = fract((0.1 * t) / period2) * period2;
+ float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI);
+
+ float atg = atan(shape_uv.y, shape_uv.x) + .001;
+ float l = length(shape_uv);
+ float radialOffset = .5 * l - inversesqrt(max(1e-4, l));
+ vec2 polar_uv1 = vec2(atg, localTime1 - radialOffset) * u_noiseScale;
+ vec2 polar_uv2 = vec2(atg, localTime2 - radialOffset) * u_noiseScale;
+
+ float noise1 = getNoise(shape_uv, polar_uv1, t);
+ float noise2 = getNoise(shape_uv, polar_uv2, t);
+
+ float noise = mix(noise1, noise2, timeBlend);
+
+ shape_uv *= (.8 + 1.2 * noise);
+
+ float ringShape = getRingShape(shape_uv);
+
+ float mixer = ringShape * ringShape * (u_colorsCount - 1.);
+ int idxLast = int(u_colorsCount) - 1;
+ vec4 gradient = u_colors[idxLast];
+ gradient.rgb *= gradient.a;
+ for (int i = ${smokeRingMeta.maxColorCount} - 2; i >= 0; i--) {
+ float localT = clamp(mixer - float(idxLast - i - 1), 0., 1.);
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, localT);
+ }
+
+ vec3 color = gradient.rgb * ringShape;
+ float opacity = gradient.a * ringShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1. - opacity);
+ opacity = opacity + u_colorBack.a * (1. - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ smokeRingFragmentShader,
+ smokeRingMeta
+};
+//# sourceMappingURL=smoke-ring.js.map
diff --git a/public/vendor/paper-shaders/shaders/smoke-ring.js.map b/public/vendor/paper-shaders/shaders/smoke-ring.js.map
new file mode 100644
index 0000000..0923f68
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/smoke-ring.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/smoke-ring.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { 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 multi-colored gradient shaped with layered noise for a natural, smoky aesthetic.\n *\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_thickness (float): Thickness of the ring shape (0.01 to 1)\n * - u_radius (float): Radius of the ring shape (0 to 1)\n * - u_innerShape (float): Ring inner fill amount (0 to 4)\n * - u_noiseIterations (float): Number of noise layers, more layers gives more details (1 to 8)\n * - u_noiseScale (float): Noise frequency (0.01 to 5)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\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\nin vec2 v_objectUV;\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}\nvec2 fbm(vec2 n0, vec2 n1) {\n vec2 total = vec2(0.0);\n float amplitude = .4;\n for (int i = 0; i < ${ smokeRingMeta.maxNoiseIterations }; i++) {\n if (i >= int(u_noiseIterations)) break;\n total.x += valueNoise(n0) * amplitude;\n total.y += valueNoise(n1) * amplitude;\n n0 *= 1.99;\n n1 *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\nfloat getNoise(vec2 uv, vec2 pUv, float t) {\n vec2 pUvLeft = pUv + .03 * t;\n float period = max(abs(u_noiseScale * TWO_PI), 1e-6);\n vec2 pUvRight = vec2(fract(pUv.x / period) * period, pUv.y) + .03 * t;\n vec2 noise = fbm(pUvLeft, pUvRight);\n return mix(noise.y, noise.x, 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 period2 = 2.0 * cycleDuration;\n float localTime1 = fract((0.1 * t + cycleDuration) / period2) * period2;\n float localTime2 = fract((0.1 * t) / period2) * period2;\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 float radialOffset = .5 * l - inversesqrt(max(1e-4, l));\n vec2 polar_uv1 = vec2(atg, localTime1 - radialOffset) * u_noiseScale;\n vec2 polar_uv2 = vec2(atg, localTime2 - radialOffset) * u_noiseScale;\n \n float noise1 = getNoise(shape_uv, polar_uv1, t);\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 = ringShape * ringShape * (u_colorsCount - 1.);\n int idxLast = int(u_colorsCount) - 1;\n vec4 gradient = u_colors[idxLast];\n gradient.rgb *= gradient.a;\n for (int i = ${ smokeRingMeta.maxColorCount } - 2; i >= 0; i--) {\n float localT = clamp(mixer - float(idxLast - 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"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,oBAAoB;AACtB;AAqCO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQtB,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAalD,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAgBG,cAAc,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBA4DxC,cAAc,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAczC,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/spiral.d.ts b/public/vendor/paper-shaders/shaders/spiral.d.ts
new file mode 100644
index 0000000..ff53cef
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/spiral.d.ts
@@ -0,0 +1,61 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * A single-colored animated spiral that morphs across a wide range of shapes -
+ * from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings.
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorFront (vec4): Foreground (ink) color in RGBA
+ * - u_density (float): Spacing falloff simulating perspective, 0 = flat spiral (0 to 1)
+ * - u_distortion (float): Power of shape distortion applied along the spiral (0 to 1)
+ * - u_strokeWidth (float): Thickness of spiral curve (0 to 1)
+ * - u_strokeTaper (float): How much stroke loses width away from center, 0 = full visibility (0 to 1)
+ * - u_strokeCap (float): Extra stroke width at the center, no effect with strokeWidth = 0.5 (0 to 1)
+ * - u_noise (float): Noise distortion applied over the canvas, no effect with noiseFrequency = 0 (0 to 1)
+ * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ *
+ */
+export declare const spiralFragmentShader: string;
+export interface SpiralUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colorFront: [number, number, number, number];
+ u_density: number;
+ u_distortion: number;
+ u_strokeWidth: number;
+ u_strokeTaper: number;
+ u_strokeCap: number;
+ u_noise: number;
+ u_noiseFrequency: number;
+ u_softness: number;
+}
+export interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colorFront?: string;
+ density?: number;
+ distortion?: number;
+ strokeWidth?: number;
+ strokeTaper?: number;
+ strokeCap?: number;
+ noise?: number;
+ noiseFrequency?: number;
+ softness?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/spiral.js b/public/vendor/paper-shaders/shaders/spiral.js
new file mode 100644
index 0000000..76152d9
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/spiral.js
@@ -0,0 +1,81 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { simplexNoise, declarePI, colorBandingFix } from "../shader-utils.js";
+const spiralFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorFront;
+uniform float u_density;
+uniform float u_distortion;
+uniform float u_strokeWidth;
+uniform float u_strokeCap;
+uniform float u_strokeTaper;
+uniform float u_noise;
+uniform float u_noiseFrequency;
+uniform float u_softness;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${simplexNoise}
+
+void main() {
+ vec2 uv = 2. * v_patternUV;
+
+ float t = u_time;
+ float l = length(uv);
+ float density = clamp(u_density, 0., 1.);
+ l = pow(max(l, 1e-6), density);
+ float angle = atan(uv.y, uv.x) - t;
+ float angleNormalised = angle / TWO_PI;
+
+ angleNormalised += .125 * u_noise * snoise(16. * pow(u_noiseFrequency, 3.) * uv);
+
+ float offset = l + angleNormalised;
+ offset -= u_distortion * (sin(4. * l - .5 * t) * cos(PI + l + .5 * t));
+ float stripe = fract(offset);
+
+ float shape = 2. * abs(stripe - .5);
+ float width = 1. - clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);
+
+
+ float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.)));
+ width = mix(width, wCap, u_strokeCap);
+ width *= (1. - clamp(u_strokeTaper, 0., 1.) * l);
+
+ float fw = fwidth(offset);
+ float fwMult = 4. - 3. * (smoothstep(.05, .4, 2. * u_strokeWidth) * smoothstep(.05, .4, 2. * (1. - u_strokeWidth)));
+ float pixelSize = mix(fwMult * fw, fwidth(shape), clamp(fw, 0., 1.));
+ pixelSize = mix(pixelSize, .002, u_strokeCap * (1. - clamp(l, 0., 1.)));
+
+ float res = smoothstep(width - pixelSize - u_softness, width + pixelSize + u_softness, shape);
+
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+
+ vec3 color = fgColor * res;
+ float opacity = fgOpacity * res;
+
+ color += bgColor * (1. - opacity);
+ opacity += bgOpacity * (1. - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ spiralFragmentShader
+};
+//# sourceMappingURL=spiral.js.map
diff --git a/public/vendor/paper-shaders/shaders/spiral.js.map b/public/vendor/paper-shaders/shaders/spiral.js.map
new file mode 100644
index 0000000..9b1d972
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/spiral.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/spiral.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, declarePI, colorBandingFix } from '../shader-utils.js';\n\n/**\n * A single-colored animated spiral that morphs across a wide range of shapes -\n * from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings.\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates in pixels (scaled by 0.01 for precision), with rotation and offset applied\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorFront (vec4): Foreground (ink) color in RGBA\n * - u_density (float): Spacing falloff simulating perspective, 0 = flat spiral (0 to 1)\n * - u_distortion (float): Power of shape distortion applied along the spiral (0 to 1)\n * - u_strokeWidth (float): Thickness of spiral curve (0 to 1)\n * - u_strokeTaper (float): How much stroke loses width away from center, 0 = full visibility (0 to 1)\n * - u_strokeCap (float): Extra stroke width at the center, no effect with strokeWidth = 0.5 (0 to 1)\n * - u_noise (float): Noise distortion applied over the canvas, no effect with noiseFrequency = 0 (0 to 1)\n * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n *\n */\n\n// language=GLSL\nexport const spiralFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_density;\nuniform float u_distortion;\nuniform float u_strokeWidth;\nuniform float u_strokeCap;\nuniform float u_strokeTaper;\nuniform float u_noise;\nuniform float u_noiseFrequency;\nuniform float u_softness;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n\nvoid main() {\n vec2 uv = 2. * v_patternUV;\n\n float t = u_time;\n float l = length(uv);\n float density = clamp(u_density, 0., 1.);\n l = pow(max(l, 1e-6), density);\n float angle = atan(uv.y, uv.x) - t;\n float angleNormalised = angle / TWO_PI;\n\n angleNormalised += .125 * u_noise * snoise(16. * pow(u_noiseFrequency, 3.) * uv);\n\n float offset = l + angleNormalised;\n offset -= u_distortion * (sin(4. * l - .5 * t) * cos(PI + l + .5 * t));\n float stripe = fract(offset);\n\n float shape = 2. * abs(stripe - .5);\n float width = 1. - clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);\n\n\n float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.)));\n width = mix(width, wCap, u_strokeCap);\n width *= (1. - clamp(u_strokeTaper, 0., 1.) * l);\n\n float fw = fwidth(offset);\n float fwMult = 4. - 3. * (smoothstep(.05, .4, 2. * u_strokeWidth) * smoothstep(.05, .4, 2. * (1. - u_strokeWidth)));\n float pixelSize = mix(fwMult * fw, fwidth(shape), clamp(fw, 0., 1.));\n pixelSize = mix(pixelSize, .002, u_strokeCap * (1. - clamp(l, 0., 1.)));\n\n float res = smoothstep(width - pixelSize - u_softness, width + pixelSize + u_softness, shape);\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 ${ colorBandingFix }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SpiralUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_density: number;\n u_distortion: number;\n u_strokeWidth: number;\n u_strokeTaper: number;\n u_strokeCap: number;\n u_noise: number;\n u_noiseFrequency: number;\n u_softness: number;\n}\n\nexport interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n density?: number;\n distortion?: number;\n strokeWidth?: number;\n strokeTaper?: number;\n strokeCap?: number;\n noise?: number;\n noiseFrequency?: number;\n softness?: number;\n}\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,cAAc,WAAW,uBAAuB;AAsClD,MAAM,uBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBzC,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4CX,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts b/public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts
new file mode 100644
index 0000000..aa8ff75
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/static-mesh-gradient.d.ts
@@ -0,0 +1,63 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const staticMeshGradientMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * Multi-point mesh gradient with up to 10 color spots, enhanced by two-direction warping,
+ * adjustable blend sharpness, and grain controls.
+ *
+ * Fragment shader uniforms:
+ * - u_colors (vec4[]): Up to 10 gradient colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_positions (float): Color spots placement seed (0 to 100)
+ * - u_waveX (float): Strength of sine wave distortion along X axis (0 to 1)
+ * - u_waveXShift (float): Phase offset applied to the X-axis wave (0 to 1)
+ * - u_waveY (float): Strength of sine wave distortion along Y axis (0 to 1)
+ * - u_waveYShift (float): Phase offset applied to the Y-axis wave (0 to 1)
+ * - u_mixing (float): Blending behavior, 0 = hard stripes, 0.5 = smooth, 1 = gradual blend (0 to 1)
+ * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)
+ * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const staticMeshGradientFragmentShader: string;
+export interface StaticMeshGradientUniforms extends ShaderSizingUniforms {
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_positions: number;
+ u_waveX: number;
+ u_waveXShift: number;
+ u_waveY: number;
+ u_waveYShift: number;
+ u_mixing: number;
+ u_grainMixer: number;
+ u_grainOverlay: number;
+}
+export interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ positions?: number;
+ waveX?: number;
+ waveXShift?: number;
+ waveY?: number;
+ waveYShift?: number;
+ mixing?: number;
+ grainMixer?: number;
+ grainOverlay?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/static-mesh-gradient.js b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js
new file mode 100644
index 0000000..32701a8
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js
@@ -0,0 +1,128 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {
+} from "../shader-sizing.js";
+import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
+const staticMeshGradientMeta = {
+ maxColorCount: 10
+};
+const staticMeshGradientFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec4 u_colors[${staticMeshGradientMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_positions;
+uniform float u_waveX;
+uniform float u_waveXShift;
+uniform float u_waveY;
+uniform float u_waveYShift;
+uniform float u_mixing;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+
+in vec2 v_objectUV;
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${proceduralHash21}
+
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = hash21(i);
+ float b = hash21(i + vec2(1.0, 0.0));
+ float c = hash21(i + vec2(0.0, 1.0));
+ float d = hash21(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float noise(vec2 n, vec2 seedOffset) {
+ return valueNoise(n + seedOffset);
+}
+
+vec2 getPosition(int i, float t) {
+ float a = float(i) * .37;
+ float b = .6 + mod(float(i), 3.) * .3;
+ float c = .8 + mod(float(i + 1), 4.) * 0.25;
+
+ float x = sin(t * b + a);
+ float y = cos(t * c + a * 1.5);
+
+ return .5 + .5 * vec2(x, y);
+}
+
+void main() {
+ vec2 uv = v_objectUV;
+ uv += .5;
+ vec2 grainUV = uv * 1000.;
+
+ float grain = noise(grainUV, vec2(0.));
+ float mixerGrain = .4 * u_grainMixer * (grain - .5);
+
+ float radius = smoothstep(0., 1., length(uv - .5));
+ float center = 1. - radius;
+ for (float i = 1.; i <= 2.; i++) {
+ uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y));
+ uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x));
+ }
+
+ vec3 color = vec3(0.);
+ float opacity = 0.;
+ float totalWeight = 0.;
+ float positionSeed = 25. + .33 * u_positions;
+
+ for (int i = 0; i < ${staticMeshGradientMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+
+ vec2 pos = getPosition(i, positionSeed) + mixerGrain;
+ float dist = length(uv - pos);
+ dist = length(uv - pos);
+
+ vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;
+ float opacityFraction = u_colors[i].a;
+
+ float mixing = pow(u_mixing, .7);
+ float power = mix(2., 1., mixing);
+ dist = pow(dist, power);
+
+ float w = 1. / (dist + 1e-3);
+ float baseSharpness = mix(.0, 8., clamp(w, 0., 1.));
+ float sharpness = mix(baseSharpness, 1., mixing);
+ w = pow(w, sharpness);
+ color += colorFraction * w;
+ opacity += opacityFraction * w;
+ totalWeight += w;
+ }
+
+ color /= max(1e-4, totalWeight);
+ opacity /= max(1e-4, totalWeight);
+
+ float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));
+ grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
+ grainOverlay = pow(grainOverlay, 1.3);
+
+ float grainOverlayV = grainOverlay * 2. - 1.;
+ vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
+ float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
+ grainOverlayStrength = pow(grainOverlayStrength, .8);
+ color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);
+
+ opacity += .5 * grainOverlayStrength;
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ staticMeshGradientFragmentShader,
+ staticMeshGradientMeta
+};
+//# sourceMappingURL=static-mesh-gradient.js.map
diff --git a/public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map
new file mode 100644
index 0000000..cee90ec
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/static-mesh-gradient.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/static-mesh-gradient.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const staticMeshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Multi-point mesh gradient with up to 10 color spots, enhanced by two-direction warping,\n * adjustable blend sharpness, and grain controls.\n *\n * Fragment shader uniforms:\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_positions (float): Color spots placement seed (0 to 100)\n * - u_waveX (float): Strength of sine wave distortion along X axis (0 to 1)\n * - u_waveXShift (float): Phase offset applied to the X-axis wave (0 to 1)\n * - u_waveY (float): Strength of sine wave distortion along Y axis (0 to 1)\n * - u_waveYShift (float): Phase offset applied to the Y-axis wave (0 to 1)\n * - u_mixing (float): Blending behavior, 0 = hard stripes, 0.5 = smooth, 1 = gradual blend (0 to 1)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const staticMeshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colors[${ staticMeshGradientMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_positions;\nuniform float u_waveX;\nuniform float u_waveXShift;\nuniform float u_waveY;\nuniform float u_waveYShift;\nuniform float u_mixing;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(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 noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + mod(float(i), 3.) * .3;\n float c = .8 + mod(float(i + 1), 4.) * 0.25;\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = v_objectUV;\n uv += .5;\n vec2 grainUV = uv * 1000.;\n\n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n float radius = smoothstep(0., 1., length(uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y));\n uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x));\n }\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n float positionSeed = 25. + .33 * u_positions;\n\n for (int i = 0; i < ${ staticMeshGradientMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, positionSeed) + mixerGrain;\n float dist = length(uv - pos);\n dist = length(uv - pos);\n\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float mixing = pow(u_mixing, .7);\n float power = mix(2., 1., mixing);\n dist = pow(dist, power);\n\n float w = 1. / (dist + 1e-3);\n float baseSharpness = mix(.0, 8., clamp(w, 0., 1.));\n float sharpness = mix(baseSharpness, 1., mixing);\n w = pow(w, sharpness);\n color += colorFraction * w;\n opacity += opacityFraction * w;\n totalWeight += w;\n }\n\n color /= max(1e-4, totalWeight);\n opacity /= max(1e-4, totalWeight);\n\n float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticMeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_positions: number;\n u_waveX: number;\n u_waveXShift: number;\n u_waveY: number;\n u_waveYShift: number;\n u_mixing: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n positions?: number;\n waveX?: number;\n waveXShift?: number;\n waveY?: number;\n waveYShift?: number;\n mixing?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
+ "mappings": ";;;;;AAEA;AAAA,OAGO;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,yBAAyB;AAAA,EACpC,eAAe;AACjB;AAqCO,MAAM,mCAA2C;AAAA;AAAA;AAAA,wBAG/B,uBAAuB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe3D,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAkDK,uBAAuB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts b/public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts
new file mode 100644
index 0000000..6c0cd5b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/static-radial-gradient.d.ts
@@ -0,0 +1,72 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const staticRadialGradientMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * Radial gradient with up to 10 blended colors, featuring advanced mixing modes, focal point controls,
+ * shape distortion, and grain effects.
+ *
+ * Fragment shader uniforms:
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 10 gradient colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_radius (float): Size of the shape (0 to 3)
+ * - u_focalDistance (float): Distance of the focal point from center (0 to 3)
+ * - u_focalAngle (float): Angle of the focal point in degrees, effective with focalDistance > 0 (0 to 360)
+ * - u_falloff (float): Gradient decay, 0 = linear gradient (-1 to 1)
+ * - u_mixing (float): Blending behavior, 0 = hard stripes, 1 = smooth gradient (0 to 1)
+ * - u_distortion (float): Strength of radial distortion (0 to 1)
+ * - u_distortionShift (float): Radial distortion offset, effective with distortion > 0 (-1 to 1)
+ * - u_distortionFreq (float): Radial distortion frequency, effective with distortion > 0 (0 to 20)
+ * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)
+ * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const staticRadialGradientFragmentShader: string;
+export interface StaticRadialGradientUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_radius: number;
+ u_focalDistance: number;
+ u_focalAngle: number;
+ u_falloff: number;
+ u_mixing: number;
+ u_distortion: number;
+ u_distortionShift: number;
+ u_distortionFreq: number;
+ u_grainMixer: number;
+ u_grainOverlay: number;
+}
+export interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ radius?: number;
+ focalDistance?: number;
+ focalAngle?: number;
+ falloff?: number;
+ mixing?: number;
+ distortion?: number;
+ distortionShift?: number;
+ distortionFreq?: number;
+ grainMixer?: number;
+ grainOverlay?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/static-radial-gradient.js b/public/vendor/paper-shaders/shaders/static-radial-gradient.js
new file mode 100644
index 0000000..b52ae09
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/static-radial-gradient.js
@@ -0,0 +1,184 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {
+} from "../shader-sizing.js";
+import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
+const staticRadialGradientMeta = {
+ maxColorCount: 10
+};
+const staticRadialGradientFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${staticRadialGradientMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_radius;
+uniform float u_focalDistance;
+uniform float u_focalAngle;
+uniform float u_falloff;
+uniform float u_mixing;
+uniform float u_distortion;
+uniform float u_distortionShift;
+uniform float u_distortionFreq;
+uniform float u_grainMixer;
+uniform float u_grainOverlay;
+
+in vec2 v_objectUV;
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${proceduralHash21}
+
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = hash21(i);
+ float b = hash21(i + vec2(1.0, 0.0));
+ float c = hash21(i + vec2(0.0, 1.0));
+ float d = hash21(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+float noise(vec2 n, vec2 seedOffset) {
+ return valueNoise(n + seedOffset);
+}
+
+vec2 getPosition(int i, float t) {
+ float a = float(i) * .37;
+ float b = .6 + mod(float(i), 3.) * .3;
+ float c = .8 + mod(float(i + 1), 4.) * 0.25;
+
+ float x = sin(t * b + a);
+ float y = cos(t * c + a * 1.5);
+
+ return .5 + .5 * vec2(x, y);
+}
+
+void main() {
+ vec2 uv = 2. * v_objectUV;
+ vec2 grainUV = uv * 1000.;
+
+ vec2 center = vec2(0.);
+ float angleRad = -radians(u_focalAngle + 90.);
+ vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance;
+ float radius = u_radius;
+
+ vec2 c_to_uv = uv - center;
+ vec2 f_to_uv = uv - focalPoint;
+ vec2 f_to_c = center - focalPoint;
+ float r = length(c_to_uv);
+
+ float fragAngle = atan(c_to_uv.y, c_to_uv.x);
+ float angleDiff = fract((fragAngle - angleRad + PI) / TWO_PI) * TWO_PI - PI;
+
+ float halfAngle = acos(clamp(radius / max(u_focalDistance, 1e-4), 0.0, 1.0));
+ float e0 = 0.6 * PI, e1 = halfAngle;
+ float lo = min(e0, e1), hi = max(e0, e1);
+ float s = smoothstep(lo, hi, abs(angleDiff));
+ float isInSector = (e1 >= e0) ? (1.0 - s) : s;
+
+ float a = dot(f_to_uv, f_to_uv);
+ float b = -2.0 * dot(f_to_uv, f_to_c);
+ float c = dot(f_to_c, f_to_c) - radius * radius;
+
+ float discriminant = b * b - 4.0 * a * c;
+ float t = 1.0;
+
+ if (discriminant >= 0.0) {
+ float sqrtD = sqrt(discriminant);
+ float div = max(1e-4, 2.0 * a);
+ float t0 = (-b - sqrtD) / div;
+ float t1 = (-b + sqrtD) / div;
+ t = max(t0, t1);
+ if (t < 0.0) t = 0.0;
+ }
+
+ float dist = length(f_to_uv);
+ float normalized = dist / max(1e-4, length(f_to_uv * t));
+ float shape = clamp(normalized, 0.0, 1.0);
+
+ float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., u_falloff * u_falloff), step(.0, u_falloff));
+
+ float falloffExp = mix(falloffMapped, 1., shape);
+ shape = pow(shape, falloffExp);
+ shape = 1. - clamp(shape, 0., 1.);
+
+
+ float outerMask = .002;
+ float outer = 1.0 - smoothstep(radius - outerMask, radius + outerMask, r);
+ outer = mix(outer, 1., isInSector);
+
+ shape = mix(0., shape, outer);
+ shape *= 1. - smoothstep(radius - .01, radius, r);
+
+ float angle = atan(f_to_uv.y, f_to_uv.x);
+ shape -= pow(u_distortion, 2.) * shape * pow(abs(sin(PI * clamp(length(f_to_uv) - 0.2 + u_distortionShift, 0.0, 1.0))), 4.0) * (sin(u_distortionFreq * angle) + cos(floor(0.65 * u_distortionFreq) * angle));
+
+ float grain = noise(grainUV, vec2(0.));
+ float mixerGrain = .4 * u_grainMixer * (grain - .5);
+
+ float mixer = shape * u_colorsCount + mixerGrain;
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+
+ float outerShape = 0.;
+ for (int i = 1; i < ${staticRadialGradientMeta.maxColorCount + 1}; i++) {
+ if (i > int(u_colorsCount)) break;
+ float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0);
+
+ float aa = fwidth(mLinear);
+ float width = min(u_mixing, 0.5);
+ float t = clamp((mLinear - (0.5 - width - aa)) / (2. * width + 2. * aa), 0., 1.);
+ float p = mix(2., 1., clamp((u_mixing - 0.5) * 2., 0., 1.));
+ float m = t < 0.5
+ ? 0.5 * pow(2. * t, p)
+ : 1. - 0.5 * pow(2. * (1. - t), p);
+
+ float quadBlend = clamp((u_mixing - 0.5) * 2., 0., 1.);
+ m = mix(m, m * m, 0.5 * quadBlend);
+
+ if (i == 1) {
+ outerShape = m;
+ }
+
+ vec4 c = u_colors[i - 1];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, m);
+ }
+
+ vec3 color = gradient.rgb * outerShape;
+ float opacity = gradient.a * outerShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1.0 - opacity);
+ opacity = opacity + u_colorBack.a * (1.0 - opacity);
+
+ float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));
+ grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);
+ grainOverlay = pow(grainOverlay, 1.3);
+
+ float grainOverlayV = grainOverlay * 2. - 1.;
+ vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
+ float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
+ grainOverlayStrength = pow(grainOverlayStrength, .8);
+ color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);
+
+ opacity += .5 * grainOverlayStrength;
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ staticRadialGradientFragmentShader,
+ staticRadialGradientMeta
+};
+//# sourceMappingURL=static-radial-gradient.js.map
diff --git a/public/vendor/paper-shaders/shaders/static-radial-gradient.js.map b/public/vendor/paper-shaders/shaders/static-radial-gradient.js.map
new file mode 100644
index 0000000..c27e009
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/static-radial-gradient.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/static-radial-gradient.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const staticRadialGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Radial gradient with up to 10 blended colors, featuring advanced mixing modes, focal point controls,\n * shape distortion, and grain effects.\n *\n * Fragment shader uniforms:\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_radius (float): Size of the shape (0 to 3)\n * - u_focalDistance (float): Distance of the focal point from center (0 to 3)\n * - u_focalAngle (float): Angle of the focal point in degrees, effective with focalDistance > 0 (0 to 360)\n * - u_falloff (float): Gradient decay, 0 = linear gradient (-1 to 1)\n * - u_mixing (float): Blending behavior, 0 = hard stripes, 1 = smooth gradient (0 to 1)\n * - u_distortion (float): Strength of radial distortion (0 to 1)\n * - u_distortionShift (float): Radial distortion offset, effective with distortion > 0 (-1 to 1)\n * - u_distortionFreq (float): Radial distortion frequency, effective with distortion > 0 (0 to 20)\n * - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)\n * - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const staticRadialGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ staticRadialGradientMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_radius;\nuniform float u_focalDistance;\nuniform float u_focalAngle;\nuniform float u_falloff;\nuniform float u_mixing;\nuniform float u_distortion;\nuniform float u_distortionShift;\nuniform float u_distortionFreq;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nin vec2 v_objectUV;\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\n${ proceduralHash21 }\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(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 noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + mod(float(i), 3.) * .3;\n float c = .8 + mod(float(i + 1), 4.) * 0.25;\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 uv = 2. * v_objectUV;\n vec2 grainUV = uv * 1000.;\n\n vec2 center = vec2(0.);\n float angleRad = -radians(u_focalAngle + 90.);\n vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance;\n float radius = u_radius;\n\n vec2 c_to_uv = uv - center;\n vec2 f_to_uv = uv - focalPoint;\n vec2 f_to_c = center - focalPoint;\n float r = length(c_to_uv);\n\n float fragAngle = atan(c_to_uv.y, c_to_uv.x);\n float angleDiff = fract((fragAngle - angleRad + PI) / TWO_PI) * TWO_PI - PI;\n\n float halfAngle = acos(clamp(radius / max(u_focalDistance, 1e-4), 0.0, 1.0));\n float e0 = 0.6 * PI, e1 = halfAngle;\n float lo = min(e0, e1), hi = max(e0, e1);\n float s = smoothstep(lo, hi, abs(angleDiff));\n float isInSector = (e1 >= e0) ? (1.0 - s) : s;\n\n float a = dot(f_to_uv, f_to_uv);\n float b = -2.0 * dot(f_to_uv, f_to_c);\n float c = dot(f_to_c, f_to_c) - radius * radius;\n\n float discriminant = b * b - 4.0 * a * c;\n float t = 1.0;\n\n if (discriminant >= 0.0) {\n float sqrtD = sqrt(discriminant);\n float div = max(1e-4, 2.0 * a);\n float t0 = (-b - sqrtD) / div;\n float t1 = (-b + sqrtD) / div;\n t = max(t0, t1);\n if (t < 0.0) t = 0.0;\n }\n\n float dist = length(f_to_uv);\n float normalized = dist / max(1e-4, length(f_to_uv * t));\n float shape = clamp(normalized, 0.0, 1.0);\n\n float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., u_falloff * u_falloff), step(.0, u_falloff));\n\n float falloffExp = mix(falloffMapped, 1., shape);\n shape = pow(shape, falloffExp);\n shape = 1. - clamp(shape, 0., 1.);\n\n\n float outerMask = .002;\n float outer = 1.0 - smoothstep(radius - outerMask, radius + outerMask, r);\n outer = mix(outer, 1., isInSector);\n\n shape = mix(0., shape, outer);\n shape *= 1. - smoothstep(radius - .01, radius, r);\n\n float angle = atan(f_to_uv.y, f_to_uv.x);\n shape -= pow(u_distortion, 2.) * shape * pow(abs(sin(PI * clamp(length(f_to_uv) - 0.2 + u_distortionShift, 0.0, 1.0))), 4.0) * (sin(u_distortionFreq * angle) + cos(floor(0.65 * u_distortionFreq) * angle));\n\n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n float mixer = shape * u_colorsCount + mixerGrain;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n\n float outerShape = 0.;\n for (int i = 1; i < ${ staticRadialGradientMeta.maxColorCount + 1 }; i++) {\n if (i > int(u_colorsCount)) break;\n float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0);\n\n float aa = fwidth(mLinear);\n float width = min(u_mixing, 0.5);\n float t = clamp((mLinear - (0.5 - width - aa)) / (2. * width + 2. * aa), 0., 1.);\n float p = mix(2., 1., clamp((u_mixing - 0.5) * 2., 0., 1.));\n float m = t < 0.5\n ? 0.5 * pow(2. * t, p)\n : 1. - 0.5 * pow(2. * (1. - t), p);\n\n float quadBlend = clamp((u_mixing - 0.5) * 2., 0., 1.);\n m = mix(m, m * m, 0.5 * quadBlend);\n \n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 float grainOverlay = valueNoise(rotate(grainUV, 1.) + vec2(3.));\n grainOverlay = mix(grainOverlay, valueNoise(rotate(grainUV, 2.) + vec2(-1.)), .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .35 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticRadialGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_radius: number;\n u_focalDistance: number;\n u_focalAngle: number;\n u_falloff: number;\n u_mixing: number;\n u_distortion: number;\n u_distortionShift: number;\n u_distortionFreq: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n radius?: number;\n focalDistance?: number;\n focalAngle?: number;\n falloff?: number;\n mixing?: number;\n distortion?: number;\n distortionShift?: number;\n distortionFreq?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
+ "mappings": ";;;;;AAEA;AAAA,OAGO;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,2BAA2B;AAAA,EACtC,eAAe;AACjB;AAwCO,MAAM,qCAA6C;AAAA;AAAA;AAAA;AAAA,wBAIjC,yBAAyB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiB7D,SAAU;AAAA,EACV,SAAU;AAAA,EACV,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAkGK,yBAAyB,gBAAgB,CAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/swirl.d.ts b/public/vendor/paper-shaders/shaders/swirl.d.ts
new file mode 100644
index 0000000..9d8845f
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/swirl.d.ts
@@ -0,0 +1,63 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const swirlMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colors (vec4[]): Up to 10 stripe colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_bandCount (float): Number of color bands, 0 = concentric ripples (0 to 15)
+ * - u_twist (float): Vortex power, 0 = straight sectoral shapes (0 to 1)
+ * - u_center (float): How far from the center the swirl colors begin to appear (0 to 1)
+ * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ * - u_noise (float): Strength of noise distortion, no effect with noiseFrequency = 0 (0 to 1)
+ * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const swirlFragmentShader: string;
+export interface SwirlUniforms extends ShaderSizingUniforms {
+ u_colorBack: [number, number, number, number];
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_bandCount: number;
+ u_twist: number;
+ u_center: number;
+ u_proportion: number;
+ u_softness: number;
+ u_noiseFrequency: number;
+ u_noise: number;
+}
+export interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {
+ colorBack?: string;
+ colors?: string[];
+ bandCount?: number;
+ twist?: number;
+ center?: number;
+ proportion?: number;
+ softness?: number;
+ noiseFrequency?: number;
+ noise?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/swirl.js b/public/vendor/paper-shaders/shaders/swirl.js
new file mode 100644
index 0000000..ed7d21e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/swirl.js
@@ -0,0 +1,102 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { simplexNoise, declarePI, rotation2, colorBandingFix } from "../shader-utils.js";
+const swirlMeta = {
+ maxColorCount: 10
+};
+const swirlFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colors[${swirlMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_bandCount;
+uniform float u_twist;
+uniform float u_center;
+uniform float u_proportion;
+uniform float u_softness;
+uniform float u_noise;
+uniform float u_noiseFrequency;
+
+in vec2 v_objectUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${simplexNoise}
+${rotation2}
+
+void main() {
+ vec2 shape_uv = v_objectUV;
+
+ float l = length(shape_uv);
+ l = max(1e-4, l);
+
+ float t = u_time;
+
+ float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t;
+ float angle_norm = angle / TWO_PI;
+
+ float twist = 3. * clamp(u_twist, 0., 1.);
+ float offset = pow(l, -twist) + angle_norm;
+
+ float shape = fract(offset);
+ shape = 1. - abs(2. * shape - 1.);
+ shape += u_noise * snoise(15. * pow(u_noiseFrequency, 2.) * shape_uv);
+
+ float mid = smoothstep(.2, .2 + .8 * u_center, pow(l, twist));
+ shape = mix(0., shape, mid);
+
+ float proportion = clamp(u_proportion, 0., 1.);
+ float exponent = mix(.25, 1., proportion * 2.);
+ exponent = mix(exponent, 10., max(0., proportion * 2. - 1.));
+ shape = pow(shape, exponent);
+
+ float mixer = shape * u_colorsCount;
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+
+ float outerShape = 0.;
+ for (int i = 1; i < ${swirlMeta.maxColorCount + 1}; i++) {
+ if (i > int(u_colorsCount)) break;
+
+ float m = clamp(mixer - float(i - 1), 0., 1.);
+ float aa = fwidth(m);
+ m = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, m);
+
+ if (i == 1) {
+ outerShape = m;
+ }
+
+ vec4 c = u_colors[i - 1];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, m);
+ }
+
+ float midAA = .1 * fwidth(pow(l, -twist));
+ float outerMid = smoothstep(.2, .2 + midAA, pow(l, twist));
+ outerShape = mix(0., outerShape, outerMid);
+
+ vec3 color = gradient.rgb * outerShape;
+ float opacity = gradient.a * outerShape;
+
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ color = color + bgColor * (1.0 - opacity);
+ opacity = opacity + u_colorBack.a * (1.0 - opacity);
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ swirlFragmentShader,
+ swirlMeta
+};
+//# sourceMappingURL=swirl.js.map
diff --git a/public/vendor/paper-shaders/shaders/swirl.js.map b/public/vendor/paper-shaders/shaders/swirl.js.map
new file mode 100644
index 0000000..7a8b2fa
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/swirl.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/swirl.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, declarePI, rotation2, colorBandingFix } from '../shader-utils.js';\n\nexport const swirlMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 10 stripe colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_bandCount (float): Number of color bands, 0 = concentric ripples (0 to 15)\n * - u_twist (float): Vortex power, 0 = straight sectoral shapes (0 to 1)\n * - u_center (float): How far from the center the swirl colors begin to appear (0 to 1)\n * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_noise (float): Strength of noise distortion, no effect with noiseFrequency = 0 (0 to 1)\n * - u_noiseFrequency (float): Noise frequency, no effect with noise = 0 (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const swirlFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ swirlMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_bandCount;\nuniform float u_twist;\nuniform float u_center;\nuniform float u_proportion;\nuniform float u_softness;\nuniform float u_noise;\nuniform float u_noiseFrequency;\n\nin vec2 v_objectUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n${ rotation2 }\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float l = length(shape_uv);\n l = max(1e-4, l);\n\n float t = u_time;\n\n float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t;\n float angle_norm = angle / TWO_PI;\n\n float twist = 3. * clamp(u_twist, 0., 1.);\n float offset = pow(l, -twist) + angle_norm;\n\n float shape = fract(offset);\n shape = 1. - abs(2. * shape - 1.);\n shape += u_noise * snoise(15. * pow(u_noiseFrequency, 2.) * shape_uv);\n\n float mid = smoothstep(.2, .2 + .8 * u_center, pow(l, twist));\n shape = mix(0., shape, mid);\n\n float proportion = clamp(u_proportion, 0., 1.);\n float exponent = mix(.25, 1., proportion * 2.);\n exponent = mix(exponent, 10., max(0., proportion * 2. - 1.));\n shape = pow(shape, exponent);\n\n float mixer = shape * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n\n float outerShape = 0.;\n for (int i = 1; i < ${ swirlMeta.maxColorCount + 1 }; i++) {\n if (i > int(u_colorsCount)) break;\n\n float m = clamp(mixer - float(i - 1), 0., 1.);\n float aa = fwidth(m);\n m = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, m);\n\n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n float midAA = .1 * fwidth(pow(l, -twist));\n float outerMid = smoothstep(.2, .2 + midAA, pow(l, twist));\n outerShape = mix(0., outerShape, outerMid);\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 SwirlUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_bandCount: number;\n u_twist: number;\n u_center: number;\n u_proportion: number;\n u_softness: number;\n u_noiseFrequency: number;\n u_noise: number;\n}\n\nexport interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n bandCount?: number;\n twist?: number;\n center?: number;\n proportion?: number;\n softness?: number;\n noiseFrequency?: number;\n noise?: number;\n}\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,cAAc,WAAW,WAAW,uBAAuB;AAE7D,MAAM,YAAY;AAAA,EACvB,eAAe;AACjB;AAqCO,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMlB,UAAU,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc9C,SAAU;AAAA,EACV,YAAa;AAAA,EACb,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiCY,UAAU,gBAAgB,CAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2BhD,eAAgB;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/voronoi.d.ts b/public/vendor/paper-shaders/shaders/voronoi.d.ts
new file mode 100644
index 0000000..8d6bc6e
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/voronoi.d.ts
@@ -0,0 +1,65 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const voronoiMeta: {
+ readonly maxColorCount: 5;
+};
+/**
+ * Anti-aliased animated Voronoi pattern with smooth and customizable edges.
+ *
+ * Double-pass Voronoi pattern cell edges.
+ * Original algorithm: https://www.shadertoy.com/view/ldl3W8
+ *
+ * Note: gaps can't be removed completely due to natural artifacts of Voronoi cells borders
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_scale (float): Overall zoom level, used for anti-aliasing calculations
+ * - u_colors (vec4[]): Up to 5 base cell colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2×N, etc. (1 to 3)
+ * - u_colorGlow (vec4): Color tint for radial inner shadow inside cells in RGBA, effective with glow > 0
+ * - u_colorGap (vec4): Color used for cell borders/gaps in RGBA
+ * - u_distortion (float): Strength of noise-driven displacement of cell centers (0 to 0.5)
+ * - u_gap (float): Width of the border/gap between cells (0 to 0.1)
+ * - u_glow (float): Strength of the radial inner shadow inside cells (0 to 1)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const voronoiFragmentShader: string;
+export interface VoronoiUniforms extends ShaderSizingUniforms {
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_stepsPerColor: number;
+ u_colorGap: [number, number, number, number];
+ u_colorGlow: [number, number, number, number];
+ u_distortion: number;
+ u_gap: number;
+ u_glow: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface VoronoiParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ stepsPerColor?: number;
+ colorGap?: string;
+ colorGlow?: string;
+ distortion?: number;
+ gap?: number;
+ glow?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/voronoi.js b/public/vendor/paper-shaders/shaders/voronoi.js
new file mode 100644
index 0000000..82dcc9d
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/voronoi.js
@@ -0,0 +1,139 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, textureRandomizerGB } from "../shader-utils.js";
+const voronoiMeta = {
+ maxColorCount: 5
+};
+const voronoiFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform float u_scale;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colors[${voronoiMeta.maxColorCount}];
+uniform float u_colorsCount;
+
+uniform float u_stepsPerColor;
+uniform vec4 u_colorGlow;
+uniform vec4 u_colorGap;
+uniform float u_distortion;
+uniform float u_gap;
+uniform float u_glow;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${textureRandomizerGB}
+
+vec4 voronoi(vec2 x, float t) {
+ vec2 ip = floor(x);
+ vec2 fp = fract(x);
+
+ vec2 mg, mr;
+ float md = 8.;
+ float rand = 0.;
+
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 g = vec2(float(i), float(j));
+ vec2 o = randomGB(ip + g);
+ float raw_hash = o.x;
+ o = .5 + u_distortion * sin(t + TWO_PI * o);
+ vec2 r = g + o - fp;
+ float d = dot(r, r);
+
+ if (d < md) {
+ md = d;
+ mr = r;
+ mg = g;
+ rand = raw_hash;
+ }
+ }
+ }
+
+ md = 8.;
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec2 g = mg + vec2(float(i), float(j));
+ vec2 o = randomGB(ip + g);
+ o = .5 + u_distortion * sin(t + TWO_PI * o);
+ vec2 r = g + o - fp;
+ if (dot(mr - r, mr - r) > .00001) {
+ md = min(md, dot(.5 * (mr + r), normalize(r - mr)));
+ }
+ }
+ }
+
+ return vec4(md, mr, rand);
+}
+
+void main() {
+ vec2 shape_uv = v_patternUV;
+ shape_uv *= 1.25;
+
+ float t = u_time;
+
+ vec4 voronoiRes = voronoi(shape_uv, t);
+
+ float shape = clamp(voronoiRes.w, 0., 1.);
+ float mixer = shape * (u_colorsCount - 1.);
+ mixer = (shape - .5 / u_colorsCount) * u_colorsCount;
+ float steps = max(1., u_stepsPerColor);
+
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+ for (int i = 1; i < ${voronoiMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+ float localT = clamp(mixer - float(i - 1), 0.0, 1.0);
+ localT = round(localT * steps) / steps;
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, localT);
+ }
+
+ if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {
+ float localT = mixer + 1.;
+ if (mixer > (u_colorsCount - 1.)) {
+ localT = mixer - (u_colorsCount - 1.);
+ }
+ localT = round(localT * steps) / steps;
+ vec4 cFst = u_colors[0];
+ cFst.rgb *= cFst.a;
+ vec4 cLast = u_colors[int(u_colorsCount - 1.)];
+ cLast.rgb *= cLast.a;
+ gradient = mix(cLast, cFst, localT);
+ }
+
+ vec3 cellColor = gradient.rgb;
+ float cellOpacity = gradient.a;
+
+ float glows = length(voronoiRes.yz * u_glow);
+ glows = pow(glows, 1.5);
+
+ vec3 color = mix(cellColor, u_colorGlow.rgb * u_colorGlow.a, u_colorGlow.a * glows);
+ float opacity = cellOpacity + u_colorGlow.a * glows;
+
+ float edge = voronoiRes.x;
+ float smoothEdge = .02 / (2. * u_scale) * (1. + .5 * u_gap);
+ edge = smoothstep(u_gap - smoothEdge, u_gap + smoothEdge, edge);
+
+ color = mix(u_colorGap.rgb * u_colorGap.a, color, edge);
+ opacity = mix(u_colorGap.a, opacity, edge);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ voronoiFragmentShader,
+ voronoiMeta
+};
+//# sourceMappingURL=voronoi.js.map
diff --git a/public/vendor/paper-shaders/shaders/voronoi.js.map b/public/vendor/paper-shaders/shaders/voronoi.js.map
new file mode 100644
index 0000000..8f90cb7
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/voronoi.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/voronoi.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, textureRandomizerGB } from '../shader-utils.js';\n\nexport const voronoiMeta = {\n maxColorCount: 5,\n} as const;\n\n/**\n * Anti-aliased animated Voronoi pattern with smooth and customizable edges.\n *\n * Double-pass Voronoi pattern cell edges.\n * Original algorithm: https://www.shadertoy.com/view/ldl3W8\n *\n * Note: gaps can't be removed completely due to natural artifacts of Voronoi cells borders\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 5 base cell colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_stepsPerColor (float): Number of extra colors between base colors, 1 = N colors, 2 = 2\u00D7N, etc. (1 to 3)\n * - u_colorGlow (vec4): Color tint for radial inner shadow inside cells in RGBA, effective with glow > 0\n * - u_colorGap (vec4): Color used for cell borders/gaps in RGBA\n * - u_distortion (float): Strength of noise-driven displacement of cell centers (0 to 0.5)\n * - u_gap (float): Width of the border/gap between cells (0 to 0.1)\n * - u_glow (float): Strength of the radial inner shadow inside cells (0 to 1)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const voronoiFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform float u_scale;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colors[${ voronoiMeta.maxColorCount }];\nuniform float u_colorsCount;\n\nuniform float u_stepsPerColor;\nuniform vec4 u_colorGlow;\nuniform vec4 u_colorGap;\nuniform float u_distortion;\nuniform float u_gap;\nuniform float u_glow;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ textureRandomizerGB }\n\nvec4 voronoi(vec2 x, float t) {\n vec2 ip = floor(x);\n vec2 fp = fract(x);\n\n vec2 mg, mr;\n float md = 8.;\n float rand = 0.;\n\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 g = vec2(float(i), float(j));\n vec2 o = randomGB(ip + g);\n float raw_hash = o.x;\n o = .5 + u_distortion * sin(t + TWO_PI * o);\n vec2 r = g + o - fp;\n float d = dot(r, r);\n\n if (d < md) {\n md = d;\n mr = r;\n mg = g;\n rand = raw_hash;\n }\n }\n }\n\n md = 8.;\n for (int j = -2; j <= 2; j++) {\n for (int i = -2; i <= 2; i++) {\n vec2 g = mg + vec2(float(i), float(j));\n vec2 o = randomGB(ip + g);\n o = .5 + u_distortion * sin(t + TWO_PI * o);\n vec2 r = g + o - fp;\n if (dot(mr - r, mr - r) > .00001) {\n md = min(md, dot(.5 * (mr + r), normalize(r - mr)));\n }\n }\n }\n\n return vec4(md, mr, rand);\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= 1.25;\n\n float t = u_time;\n\n vec4 voronoiRes = voronoi(shape_uv, t);\n\n float shape = clamp(voronoiRes.w, 0., 1.);\n float mixer = shape * (u_colorsCount - 1.);\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ voronoiMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0.0, 1.0);\n localT = round(localT * steps) / steps;\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localT = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localT = mixer - (u_colorsCount - 1.);\n }\n localT = round(localT * steps) / steps;\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localT);\n }\n\n vec3 cellColor = gradient.rgb;\n float cellOpacity = gradient.a;\n\n float glows = length(voronoiRes.yz * u_glow);\n glows = pow(glows, 1.5);\n\n vec3 color = mix(cellColor, u_colorGlow.rgb * u_colorGlow.a, u_colorGlow.a * glows);\n float opacity = cellOpacity + u_colorGlow.a * glows;\n\n float edge = voronoiRes.x;\n float smoothEdge = .02 / (2. * u_scale) * (1. + .5 * u_gap);\n edge = smoothstep(u_gap - smoothEdge, u_gap + smoothEdge, edge);\n\n color = mix(u_colorGap.rgb * u_colorGap.a, color, edge);\n opacity = mix(u_colorGap.a, opacity, edge);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface VoronoiUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_colorGap: [number, number, number, number];\n u_colorGlow: [number, number, number, number];\n u_distortion: number;\n u_gap: number;\n u_glow: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface VoronoiParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n colorGap?: string;\n colorGlow?: string;\n distortion?: number;\n gap?: number;\n glow?: number;\n}\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,2BAA2B;AAExC,MAAM,cAAc;AAAA,EACzB,eAAe;AACjB;AA0CO,MAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASpB,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAchD,SAAU;AAAA,EACV,mBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA2DE,YAAY,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/warp.d.ts b/public/vendor/paper-shaders/shaders/warp.d.ts
new file mode 100644
index 0000000..e70d457
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/warp.d.ts
@@ -0,0 +1,72 @@
+import type { vec4 } from '../types.js';
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+export declare const warpMeta: {
+ readonly maxColorCount: 10;
+};
+/**
+ * Animated color fields warped by noise and swirls, applied over base patterns
+ * (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution,
+ * softness, distortion, and swirl. Great for fluid, smoky, or marbled effects.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_scale (float): Overall zoom level, used for anti-aliasing calculations
+ * - u_colors (vec4[]): Up to 10 gradient colors in RGBA
+ * - u_colorsCount (float): Number of active colors
+ * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ * - u_shape (float): Base pattern type (0 = checks, 1 = stripes, 2 = edge)
+ * - u_shapeScale (float): Zoom level of the base pattern (0 to 1)
+ * - u_distortion (float): Strength of noise-based distortion (0 to 1)
+ * - u_swirl (float): Strength of the swirl distortion (0 to 1)
+ * - u_swirlIterations (float): Number of layered swirl passes, effective with swirl > 0 (0 to 20)
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const warpFragmentShader: string;
+export interface WarpUniforms extends ShaderSizingUniforms {
+ u_colors: vec4[];
+ u_colorsCount: number;
+ u_proportion: number;
+ u_softness: number;
+ u_shape: (typeof WarpPatterns)[WarpPattern];
+ u_shapeScale: number;
+ u_distortion: number;
+ u_swirl: number;
+ u_swirlIterations: number;
+ u_noiseTexture?: HTMLImageElement;
+}
+export interface WarpParams extends ShaderSizingParams, ShaderMotionParams {
+ colors?: string[];
+ rotation?: number;
+ proportion?: number;
+ softness?: number;
+ shape?: WarpPattern;
+ shapeScale?: number;
+ distortion?: number;
+ swirl?: number;
+ swirlIterations?: number;
+}
+export declare const WarpPatterns: {
+ readonly checks: 0;
+ readonly stripes: 1;
+ readonly edge: 2;
+};
+export type WarpPattern = keyof typeof WarpPatterns;
diff --git a/public/vendor/paper-shaders/shaders/warp.js b/public/vendor/paper-shaders/shaders/warp.js
new file mode 100644
index 0000000..2da4d50
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/warp.js
@@ -0,0 +1,132 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, colorBandingFix } from "../shader-utils.js";
+const warpMeta = {
+ maxColorCount: 10
+};
+const warpFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+uniform float u_scale;
+
+uniform sampler2D u_noiseTexture;
+
+uniform vec4 u_colors[${warpMeta.maxColorCount}];
+uniform float u_colorsCount;
+uniform float u_proportion;
+uniform float u_softness;
+uniform float u_shape;
+uniform float u_shapeScale;
+uniform float u_distortion;
+uniform float u_swirl;
+uniform float u_swirlIterations;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+float randomG(vec2 p) {
+ vec2 uv = floor(p) / 100. + .5;
+ return texture(u_noiseTexture, fract(uv)).g;
+}
+float valueNoise(vec2 st) {
+ vec2 i = floor(st);
+ vec2 f = fract(st);
+ float a = randomG(i);
+ float b = randomG(i + vec2(1.0, 0.0));
+ float c = randomG(i + vec2(0.0, 1.0));
+ float d = randomG(i + vec2(1.0, 1.0));
+ vec2 u = f * f * (3.0 - 2.0 * f);
+ float x1 = mix(a, b, u.x);
+ float x2 = mix(c, d, u.x);
+ return mix(x1, x2, u.y);
+}
+
+
+void main() {
+ vec2 uv = v_patternUV;
+ uv *= .5;
+
+ const float firstFrameOffset = 118.;
+ float t = 0.0625 * (u_time + firstFrameOffset);
+
+ float n1 = valueNoise(uv * 1. + t);
+ float n2 = valueNoise(uv * 2. - t);
+ float angle = n1 * TWO_PI;
+ uv.x += 4. * u_distortion * n2 * cos(angle);
+ uv.y += 4. * u_distortion * n2 * sin(angle);
+
+ float swirl = u_swirl;
+ for (int i = 1; i <= 20; i++) {
+ if (i >= int(u_swirlIterations)) break;
+ float iFloat = float(i);
+ // swirl *= (1. - smoothstep(.0, .25, length(fwidth(uv))));
+ uv.x += swirl / iFloat * cos(t + iFloat * 1.5 * uv.y);
+ uv.y += swirl / iFloat * cos(t + iFloat * 1. * uv.x);
+ }
+
+ float proportion = clamp(u_proportion, 0., 1.);
+
+ float shape = 0.;
+ if (u_shape < .5) {
+ vec2 checksShape_uv = uv * (.5 + 3.5 * u_shapeScale);
+ shape = .5 + .5 * sin(checksShape_uv.x) * cos(checksShape_uv.y);
+ shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5);
+ } else if (u_shape < 1.5) {
+ vec2 stripesShape_uv = uv * (2. * u_shapeScale);
+ float f = fract(stripesShape_uv.y);
+ shape = smoothstep(.0, .55, f) * (1.0 - smoothstep(.45, 1., f));
+ shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5);
+ } else {
+ float shapeScaling = 5. * (1. - u_shapeScale);
+ float e0 = 0.45 - shapeScaling;
+ float e1 = 0.55 + shapeScaling;
+ shape = smoothstep(min(e0, e1), max(e0, e1), 1.0 - uv.y + 0.3 * (proportion - 0.5));
+ }
+
+ float mixer = shape * (u_colorsCount - 1.);
+ vec4 gradient = u_colors[0];
+ gradient.rgb *= gradient.a;
+ float aa = fwidth(shape);
+ for (int i = 1; i < ${warpMeta.maxColorCount}; i++) {
+ if (i >= int(u_colorsCount)) break;
+ float m = clamp(mixer - float(i - 1), 0.0, 1.0);
+
+ float localMixerStart = floor(m);
+ float softness = .5 * u_softness + fwidth(m);
+ float smoothed = smoothstep(max(0., .5 - softness - aa), min(1., .5 + softness + aa), m - localMixerStart);
+ float stepped = localMixerStart + smoothed;
+
+ m = mix(stepped, m, u_softness);
+
+ vec4 c = u_colors[i];
+ c.rgb *= c.a;
+ gradient = mix(gradient, c, m);
+ }
+
+ vec3 color = gradient.rgb;
+ float opacity = gradient.a;
+
+ ${colorBandingFix}
+
+ fragColor = vec4(color, opacity);
+}
+`;
+const WarpPatterns = {
+ checks: 0,
+ stripes: 1,
+ edge: 2
+};
+export {
+ WarpPatterns,
+ warpFragmentShader,
+ warpMeta
+};
+//# sourceMappingURL=warp.js.map
diff --git a/public/vendor/paper-shaders/shaders/warp.js.map b/public/vendor/paper-shaders/shaders/warp.js.map
new file mode 100644
index 0000000..e2acd7a
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/warp.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/warp.ts"],
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, colorBandingFix } from '../shader-utils.js';\n\nexport const warpMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Animated color fields warped by noise and swirls, applied over base patterns\n * (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution,\n * softness, distortion, and swirl. Great for fluid, smoky, or marbled effects.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_scale (float): Overall zoom level, used for anti-aliasing calculations\n * - u_colors (vec4[]): Up to 10 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_proportion (float): Blend point between colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_shape (float): Base pattern type (0 = checks, 1 = stripes, 2 = edge)\n * - u_shapeScale (float): Zoom level of the base pattern (0 to 1)\n * - u_distortion (float): Strength of noise-based distortion (0 to 1)\n * - u_swirl (float): Strength of the swirl distortion (0 to 1)\n * - u_swirlIterations (float): Number of layered swirl passes, effective with swirl > 0 (0 to 20)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const warpFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colors[${ warpMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_proportion;\nuniform float u_softness;\nuniform float u_shape;\nuniform float u_shapeScale;\nuniform float u_distortion;\nuniform float u_swirl;\nuniform float u_swirlIterations;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ rotation2 }\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\n\nvoid main() {\n vec2 uv = v_patternUV;\n uv *= .5;\n\n const float firstFrameOffset = 118.;\n float t = 0.0625 * (u_time + firstFrameOffset);\n\n float n1 = valueNoise(uv * 1. + t);\n float n2 = valueNoise(uv * 2. - t);\n float angle = n1 * TWO_PI;\n uv.x += 4. * u_distortion * n2 * cos(angle);\n uv.y += 4. * u_distortion * n2 * sin(angle);\n\n float swirl = u_swirl;\n for (int i = 1; i <= 20; i++) {\n if (i >= int(u_swirlIterations)) break;\n float iFloat = float(i);\n // swirl *= (1. - smoothstep(.0, .25, length(fwidth(uv))));\n uv.x += swirl / iFloat * cos(t + iFloat * 1.5 * uv.y);\n uv.y += swirl / iFloat * cos(t + iFloat * 1. * uv.x);\n }\n\n float proportion = clamp(u_proportion, 0., 1.);\n\n float shape = 0.;\n if (u_shape < .5) {\n vec2 checksShape_uv = uv * (.5 + 3.5 * u_shapeScale);\n shape = .5 + .5 * sin(checksShape_uv.x) * cos(checksShape_uv.y);\n shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5);\n } else if (u_shape < 1.5) {\n vec2 stripesShape_uv = uv * (2. * u_shapeScale);\n float f = fract(stripesShape_uv.y);\n shape = smoothstep(.0, .55, f) * (1.0 - smoothstep(.45, 1., f));\n shape += .48 * sign(proportion - .5) * pow(abs(proportion - .5), .5);\n } else {\n float shapeScaling = 5. * (1. - u_shapeScale);\n float e0 = 0.45 - shapeScaling;\n float e1 = 0.55 + shapeScaling;\n shape = smoothstep(min(e0, e1), max(e0, e1), 1.0 - uv.y + 0.3 * (proportion - 0.5));\n }\n\n float mixer = shape * (u_colorsCount - 1.);\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n float aa = fwidth(shape);\n for (int i = 1; i < ${ warpMeta.maxColorCount }; i++) {\n if (i >= int(u_colorsCount)) break;\n float m = clamp(mixer - float(i - 1), 0.0, 1.0);\n\n float localMixerStart = floor(m);\n float softness = .5 * u_softness + fwidth(m);\n float smoothed = smoothstep(max(0., .5 - softness - aa), min(1., .5 + softness + aa), m - localMixerStart);\n float stepped = localMixerStart + smoothed;\n\n m = mix(stepped, m, u_softness);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\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 WarpUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_proportion: number;\n u_softness: number;\n u_shape: (typeof WarpPatterns)[WarpPattern];\n u_shapeScale: number;\n u_distortion: number;\n u_swirl: number;\n u_swirlIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface WarpParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n rotation?: number;\n proportion?: number;\n softness?: number;\n shape?: WarpPattern;\n shapeScale?: number;\n distortion?: number;\n swirl?: number;\n swirlIterations?: number;\n}\n\nexport const WarpPatterns = {\n checks: 0,\n stripes: 1,\n edge: 2,\n} as const;\n\nexport type WarpPattern = keyof typeof WarpPatterns;\n"],
+ "mappings": ";;;;;AAEA,eAAmE;AACnE,SAAS,WAAW,WAAW,uBAAuB;AAE/C,MAAM,WAAW;AAAA,EACtB,eAAe;AACjB;AAwCO,MAAM,qBAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQjB,SAAS,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc7C,SAAU;AAAA,EACV,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAgEY,SAAS,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmB3C,eAAgB;AAAA;AAAA;AAAA;AAAA;AA+Bd,MAAM,eAAe;AAAA,EAC1B,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/water.d.ts b/public/vendor/paper-shaders/shaders/water.d.ts
new file mode 100644
index 0000000..11bff99
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/water.d.ts
@@ -0,0 +1,59 @@
+import type { ShaderMotionParams } from '../shader-mount.js';
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Water-like surface distortion with natural caustic realism. Works as an image filter or standalone animated texture.
+ *
+ * Fragment shader uniforms:
+ * - u_time (float): Animation time
+ * - u_image (sampler2D): Optional source image texture
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_colorHighlight (vec4): Highlight color in RGBA
+ * - u_highlights (float): Coloring added over image/background following caustic shape (0 to 1)
+ * - u_layering (float): Power of 2nd layer of caustic distortion (0 to 1)
+ * - u_edges (float): Caustic distortion power on the image edges (0 to 1)
+ * - u_waves (float): Additional distortion based on simplex noise, independent from caustic (0 to 1)
+ * - u_caustic (float): Power of caustic distortion (0 to 1)
+ * - u_size (float): Pattern scale relative to the image (0.01 to 7)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
+ *
+ */
+export declare const waterFragmentShader: string;
+export interface WaterUniforms extends ShaderSizingUniforms {
+ u_image: HTMLImageElement | string | undefined;
+ u_colorBack: [number, number, number, number];
+ u_colorHighlight: [number, number, number, number];
+ u_highlights: number;
+ u_layering: number;
+ u_edges: number;
+ u_caustic: number;
+ u_waves: number;
+ u_size: number;
+}
+export interface WaterParams extends ShaderSizingParams, ShaderMotionParams {
+ image?: HTMLImageElement | string;
+ colorBack?: string;
+ colorHighlight?: string;
+ highlights?: number;
+ layering?: number;
+ edges?: number;
+ caustic?: number;
+ waves?: number;
+ size?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/water.js b/public/vendor/paper-shaders/shaders/water.js
new file mode 100644
index 0000000..6c0ff86
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/water.js
@@ -0,0 +1,120 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI, rotation2, simplexNoise } from "../shader-utils.js";
+const waterFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform float u_time;
+
+uniform vec4 u_colorBack;
+uniform vec4 u_colorHighlight;
+
+uniform sampler2D u_image;
+uniform float u_imageAspectRatio;
+
+uniform float u_size;
+uniform float u_highlights;
+uniform float u_layering;
+uniform float u_edges;
+uniform float u_caustic;
+uniform float u_waves;
+
+in vec2 v_imageUV;
+
+out vec4 fragColor;
+
+${declarePI}
+${rotation2}
+${simplexNoise}
+
+float getUvFrame(vec2 uv) {
+ float aax = 2. * fwidth(uv.x);
+ float aay = 2. * fwidth(uv.y);
+
+ float left = smoothstep(0., aax, uv.x);
+ float right = 1.0 - smoothstep(1. - aax, 1., uv.x);
+ float bottom = smoothstep(0., aay, uv.y);
+ float top = 1.0 - smoothstep(1. - aay, 1., uv.y);
+
+ return left * right * bottom * top;
+}
+
+mat2 rotate2D(float r) {
+ return mat2(cos(r), sin(r), -sin(r), cos(r));
+}
+
+float getCausticNoise(vec2 uv, float t, float scale) {
+ vec2 n = vec2(.1);
+ vec2 N = vec2(.1);
+ mat2 m = rotate2D(.5);
+ for (int j = 0; j < 6; j++) {
+ uv *= m;
+ n *= m;
+ vec2 q = uv * scale + float(j) + n + (.5 + .5 * float(j)) * (mod(float(j), 2.) - 1.) * t;
+ n += sin(q);
+ N += cos(q) / scale;
+ scale *= 1.1;
+ }
+ return (N.x + N.y + 1.);
+}
+
+void main() {
+ vec2 imageUV = v_imageUV;
+ vec2 patternUV = v_imageUV - .5;
+ patternUV = (patternUV * vec2(u_imageAspectRatio, 1.));
+ patternUV /= (.01 + .09 * u_size);
+
+ float t = u_time;
+
+ float wavesNoise = snoise((.3 + .1 * sin(t)) * .1 * patternUV + vec2(0., .4 * t));
+
+ float causticNoise = getCausticNoise(patternUV + u_waves * vec2(1., -1.) * wavesNoise, 2. * t, 1.5);
+
+ causticNoise += u_layering * getCausticNoise(patternUV + 2. * u_waves * vec2(1., -1.) * wavesNoise, 1.5 * t, 2.);
+ causticNoise = causticNoise * causticNoise;
+
+ float edgesDistortion = smoothstep(0., .1, imageUV.x);
+ edgesDistortion *= smoothstep(0., .1, imageUV.y);
+ edgesDistortion *= (smoothstep(1., 1.1, imageUV.x) + (1.0 - smoothstep(.8, .95, imageUV.x)));
+ edgesDistortion *= (1.0 - smoothstep(.9, 1., imageUV.y));
+ edgesDistortion = mix(edgesDistortion, 1., u_edges);
+
+ float causticNoiseDistortion = .02 * causticNoise * edgesDistortion;
+
+ float wavesDistortion = .1 * u_waves * wavesNoise;
+
+ imageUV += vec2(wavesDistortion, -wavesDistortion);
+ imageUV += (u_caustic * causticNoiseDistortion);
+
+ float frame = getUvFrame(imageUV);
+
+ vec4 image = texture(u_image, imageUV);
+ vec4 backColor = u_colorBack;
+ backColor.rgb *= backColor.a;
+
+ vec3 color = mix(backColor.rgb, image.rgb, image.a * frame);
+ float opacity = backColor.a + image.a * frame;
+
+ causticNoise = max(-.2, causticNoise);
+
+ float hightlight = .025 * u_highlights * causticNoise;
+ hightlight *= u_colorHighlight.a;
+ color = mix(color, u_colorHighlight.rgb, .05 * u_highlights * causticNoise);
+ opacity += hightlight;
+
+ color += hightlight * (.5 + .5 * wavesNoise);
+ opacity += hightlight * (.5 + .5 * wavesNoise);
+
+ opacity = clamp(opacity, 0., 1.);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ waterFragmentShader
+};
+//# sourceMappingURL=water.js.map
diff --git a/public/vendor/paper-shaders/shaders/water.js.map b/public/vendor/paper-shaders/shaders/water.js.map
new file mode 100644
index 0000000..35ced9b
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/water.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/water.ts"],
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise } from '../shader-utils.js';\n\n/**\n * Water-like surface distortion with natural caustic realism. Works as an image filter or standalone animated texture.\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_image (sampler2D): Optional source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorHighlight (vec4): Highlight color in RGBA\n * - u_highlights (float): Coloring added over image/background following caustic shape (0 to 1)\n * - u_layering (float): Power of 2nd layer of caustic distortion (0 to 1)\n * - u_edges (float): Caustic distortion power on the image edges (0 to 1)\n * - u_waves (float): Additional distortion based on simplex noise, independent from caustic (0 to 1)\n * - u_caustic (float): Power of caustic distortion (0 to 1)\n * - u_size (float): Pattern scale relative to the image (0.01 to 7)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\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_size;\nuniform float u_highlights;\nuniform float u_layering;\nuniform float u_edges;\nuniform float u_caustic;\nuniform float u_waves;\n\nin vec2 v_imageUV;\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 = 1.0 - smoothstep(1. - aax, 1., uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = 1.0 - smoothstep(1. - aay, 1., 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 = (patternUV * vec2(u_imageAspectRatio, 1.));\n patternUV /= (.01 + .09 * u_size);\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 = causticNoise * causticNoise;\n\n float edgesDistortion = smoothstep(0., .1, imageUV.x);\n edgesDistortion *= smoothstep(0., .1, imageUV.y);\n edgesDistortion *= (smoothstep(1., 1.1, imageUV.x) + (1.0 - smoothstep(.8, .95, imageUV.x)));\n edgesDistortion *= (1.0 - smoothstep(.9, 1., 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_size: number;\n}\n\nexport interface WaterParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorHighlight?: string;\n highlights?: number;\n layering?: number;\n edges?: number;\n caustic?: number;\n waves?: number;\n size?: number;\n}\n"],
+ "mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,WAAW,WAAW,oBAAoB;AAsC5C,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBxC,SAAU;AAAA,EACV,SAAU;AAAA,EACV,YAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/shaders/waves.d.ts b/public/vendor/paper-shaders/shaders/waves.d.ts
new file mode 100644
index 0000000..e5265fd
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/waves.d.ts
@@ -0,0 +1,53 @@
+import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
+/**
+ * Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves.
+ *
+ * Fragment shader uniforms:
+ * - u_colorFront (vec4): Foreground color in RGBA
+ * - u_colorBack (vec4): Background color in RGBA
+ * - u_shape (float): Line shape, 0 = zigzag, 1 = sine, 2-3 = irregular waves, fractional values morph between shapes (0 to 3)
+ * - u_amplitude (float): Wave amplitude (0 to 1)
+ * - u_frequency (float): Wave frequency (0 to 2)
+ * - u_spacing (float): Space between every two wavy lines (0 to 2)
+ * - u_proportion (float): Blend point between front and back colors, 0.5 = equal distribution (0 to 1)
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
+ *
+ * Vertex shader outputs (used in fragment shader):
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied
+ *
+ * Vertex shader uniforms:
+ * - u_resolution (vec2): Canvas resolution in pixels
+ * - u_pixelRatio (float): Device pixel ratio
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
+ *
+ */
+export declare const wavesFragmentShader: string;
+export interface WavesUniforms extends ShaderSizingUniforms {
+ u_colorFront: [number, number, number, number];
+ u_colorBack: [number, number, number, number];
+ u_shape: number;
+ u_frequency: number;
+ u_amplitude: number;
+ u_spacing: number;
+ u_proportion: number;
+ u_softness: number;
+}
+export interface WavesParams extends ShaderSizingParams {
+ colorFront?: string;
+ colorBack?: string;
+ rotation?: number;
+ shape?: number;
+ frequency?: number;
+ amplitude?: number;
+ spacing?: number;
+ proportion?: number;
+ softness?: number;
+}
diff --git a/public/vendor/paper-shaders/shaders/waves.js b/public/vendor/paper-shaders/shaders/waves.js
new file mode 100644
index 0000000..887b7f7
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/waves.js
@@ -0,0 +1,66 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import {} from "../shader-sizing.js";
+import { declarePI } from "../shader-utils.js";
+const wavesFragmentShader = `#version 300 es
+precision mediump float;
+
+uniform vec4 u_colorFront;
+uniform vec4 u_colorBack;
+uniform float u_shape;
+uniform float u_frequency;
+uniform float u_amplitude;
+uniform float u_spacing;
+uniform float u_proportion;
+uniform float u_softness;
+
+in vec2 v_patternUV;
+
+out vec4 fragColor;
+
+${declarePI}
+
+void main() {
+ vec2 shape_uv = v_patternUV;
+ shape_uv *= 4.;
+
+ float wave = .5 * cos(shape_uv.x * u_frequency * TWO_PI);
+ float zigzag = 2. * abs(fract(shape_uv.x * u_frequency) - .5);
+ float irregular = sin(shape_uv.x * .25 * u_frequency * TWO_PI) * cos(shape_uv.x * u_frequency * TWO_PI);
+ float irregular2 = .75 * (sin(shape_uv.x * u_frequency * TWO_PI) + .5 * cos(shape_uv.x * .5 * u_frequency * TWO_PI));
+
+ float offset = mix(zigzag, wave, smoothstep(0., 1., u_shape));
+ offset = mix(offset, irregular, smoothstep(1., 2., u_shape));
+ offset = mix(offset, irregular2, smoothstep(2., 3., u_shape));
+ offset *= 2. * u_amplitude;
+
+ float spacing = (.001 + u_spacing);
+ float shape = .5 + .5 * sin((shape_uv.y + offset) * PI / spacing);
+
+ float aa = .0001 + fwidth(shape);
+ float dc = 1. - clamp(u_proportion, 0., 1.);
+ float e0 = dc - u_softness - aa;
+ float e1 = dc + u_softness + aa;
+ float res = smoothstep(min(e0, e1), max(e0, e1), shape);
+
+ vec3 fgColor = u_colorFront.rgb * u_colorFront.a;
+ float fgOpacity = u_colorFront.a;
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
+ float bgOpacity = u_colorBack.a;
+
+ vec3 color = fgColor * res;
+ float opacity = fgOpacity * res;
+
+ color += bgColor * (1. - opacity);
+ opacity += bgOpacity * (1. - opacity);
+
+ fragColor = vec4(color, opacity);
+}
+`;
+export {
+ wavesFragmentShader
+};
+//# sourceMappingURL=waves.js.map
diff --git a/public/vendor/paper-shaders/shaders/waves.js.map b/public/vendor/paper-shaders/shaders/waves.js.map
new file mode 100644
index 0000000..0d8ad65
--- /dev/null
+++ b/public/vendor/paper-shaders/shaders/waves.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../../src/shaders/waves.ts"],
+ "sourcesContent": ["import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI } from '../shader-utils.js';\n\n/**\n * Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves.\n *\n * Fragment shader uniforms:\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_shape (float): Line shape, 0 = zigzag, 1 = sine, 2-3 = irregular waves, fractional values morph between shapes (0 to 3)\n * - u_amplitude (float): Wave amplitude (0 to 1)\n * - u_frequency (float): Wave frequency (0 to 2)\n * - u_spacing (float): Space between every two wavy lines (0 to 2)\n * - u_proportion (float): Blend point between front and back colors, 0.5 = equal distribution (0 to 1)\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n *\n */\n\n// language=GLSL\nexport const wavesFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform float u_shape;\nuniform float u_frequency;\nuniform float u_amplitude;\nuniform float u_spacing;\nuniform float u_proportion;\nuniform float u_softness;\n\nin vec2 v_patternUV;\n\nout vec4 fragColor;\n\n${ declarePI }\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= 4.;\n\n float wave = .5 * cos(shape_uv.x * u_frequency * TWO_PI);\n float zigzag = 2. * abs(fract(shape_uv.x * u_frequency) - .5);\n float irregular = sin(shape_uv.x * .25 * u_frequency * TWO_PI) * cos(shape_uv.x * u_frequency * TWO_PI);\n float irregular2 = .75 * (sin(shape_uv.x * u_frequency * TWO_PI) + .5 * cos(shape_uv.x * .5 * u_frequency * TWO_PI));\n\n float offset = mix(zigzag, wave, smoothstep(0., 1., u_shape));\n offset = mix(offset, irregular, smoothstep(1., 2., u_shape));\n offset = mix(offset, irregular2, smoothstep(2., 3., u_shape));\n offset *= 2. * u_amplitude;\n\n float spacing = (.001 + u_spacing);\n float shape = .5 + .5 * sin((shape_uv.y + offset) * PI / spacing);\n\n float aa = .0001 + fwidth(shape);\n float dc = 1. - clamp(u_proportion, 0., 1.);\n float e0 = dc - u_softness - aa;\n float e1 = dc + u_softness + aa;\n float res = smoothstep(min(e0, e1), max(e0, e1), shape);\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 fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface WavesUniforms extends ShaderSizingUniforms {\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_shape: number;\n u_frequency: number;\n u_amplitude: number;\n u_spacing: number;\n u_proportion: number;\n u_softness: number;\n}\n\nexport interface WavesParams extends ShaderSizingParams {\n colorFront?: string;\n colorBack?: string;\n rotation?: number;\n shape?: number;\n frequency?: number;\n amplitude?: number;\n spacing?: number;\n proportion?: number;\n softness?: number;\n}\n"],
+ "mappings": ";;;;;AAAA,eAAmE;AACnE,SAAS,iBAAiB;AAkCnB,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBxC,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/types.d.ts b/public/vendor/paper-shaders/types.d.ts
new file mode 100644
index 0000000..d675c51
--- /dev/null
+++ b/public/vendor/paper-shaders/types.d.ts
@@ -0,0 +1,3 @@
+export type vec4 = [number, number, number, number];
+export type vec3 = [number, number, number];
+export type vec2 = [number, number];
diff --git a/public/vendor/paper-shaders/types.js b/public/vendor/paper-shaders/types.js
new file mode 100644
index 0000000..32b5358
--- /dev/null
+++ b/public/vendor/paper-shaders/types.js
@@ -0,0 +1,6 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+//# sourceMappingURL=types.js.map
diff --git a/public/vendor/paper-shaders/types.js.map b/public/vendor/paper-shaders/types.js.map
new file mode 100644
index 0000000..9865211
--- /dev/null
+++ b/public/vendor/paper-shaders/types.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": [],
+ "sourcesContent": [],
+ "mappings": "",
+ "names": []
+}
diff --git a/public/vendor/paper-shaders/vertex-shader.d.ts b/public/vendor/paper-shaders/vertex-shader.d.ts
new file mode 100644
index 0000000..7cf9b45
--- /dev/null
+++ b/public/vendor/paper-shaders/vertex-shader.d.ts
@@ -0,0 +1,2 @@
+/** Vertex shader for the shader mount */
+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;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nout vec2 v_objectUV;\nout vec2 v_objectBoxSize;\nout vec2 v_responsiveUV;\nout vec2 v_responsiveBoxGivenSize;\nout vec2 v_patternUV;\nout vec2 v_patternBoxSize;\nout vec2 v_imageUV;\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\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 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 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 vec2 responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy;\n vec2 responsiveBoxScale = u_resolution.xy / 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 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 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 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 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}";
diff --git a/public/vendor/paper-shaders/vertex-shader.js b/public/vendor/paper-shaders/vertex-shader.js
new file mode 100644
index 0000000..73d7aba
--- /dev/null
+++ b/public/vendor/paper-shaders/vertex-shader.js
@@ -0,0 +1,160 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Paper Shaders *
+ * https://github.com/paper-design/shaders *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+const vertexShaderSource = `#version 300 es
+precision mediump float;
+
+layout(location = 0) in vec4 a_position;
+
+uniform vec2 u_resolution;
+uniform float u_pixelRatio;
+uniform float u_imageAspectRatio;
+uniform float u_originX;
+uniform float u_originY;
+uniform float u_worldWidth;
+uniform float u_worldHeight;
+uniform float u_fit;
+uniform float u_scale;
+uniform float u_rotation;
+uniform float u_offsetX;
+uniform float u_offsetY;
+
+out vec2 v_objectUV;
+out vec2 v_objectBoxSize;
+out vec2 v_responsiveUV;
+out vec2 v_responsiveBoxGivenSize;
+out vec2 v_patternUV;
+out vec2 v_patternBoxSize;
+out vec2 v_imageUV;
+
+vec3 getBoxSize(float boxRatio, vec2 givenBoxSize) {
+ vec2 box = vec2(0.);
+ // fit = none
+ box.x = boxRatio * min(givenBoxSize.x / boxRatio, givenBoxSize.y);
+ float noFitBoxWidth = box.x;
+ if (u_fit == 1.) { // fit = contain
+ box.x = boxRatio * min(u_resolution.x / boxRatio, u_resolution.y);
+ } else if (u_fit == 2.) { // fit = cover
+ box.x = boxRatio * max(u_resolution.x / boxRatio, u_resolution.y);
+ }
+ box.y = box.x / boxRatio;
+ return vec3(box, noFitBoxWidth);
+}
+
+void main() {
+ gl_Position = a_position;
+
+ vec2 uv = gl_Position.xy * .5;
+ vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);
+ vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);
+ givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;
+ float r = u_rotation * 3.14159265358979323846 / 180.;
+ mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));
+ vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
+
+
+ // ===================================================
+
+ float fixedRatio = 1.;
+ vec2 fixedRatioBoxGivenSize = vec2(
+ (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
+ (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
+ );
+
+ v_objectBoxSize = getBoxSize(fixedRatio, fixedRatioBoxGivenSize).xy;
+ vec2 objectWorldScale = u_resolution.xy / v_objectBoxSize;
+
+ v_objectUV = uv;
+ v_objectUV *= objectWorldScale;
+ v_objectUV += boxOrigin * (objectWorldScale - 1.);
+ v_objectUV += graphicOffset;
+ v_objectUV /= u_scale;
+ v_objectUV = graphicRotation * v_objectUV;
+
+ // ===================================================
+
+ v_responsiveBoxGivenSize = vec2(
+ (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
+ (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
+ );
+ float responsiveRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
+ vec2 responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy;
+ vec2 responsiveBoxScale = u_resolution.xy / responsiveBoxSize;
+
+ #ifdef ADD_HELPERS
+ v_responsiveHelperBox = uv;
+ v_responsiveHelperBox *= responsiveBoxScale;
+ v_responsiveHelperBox += boxOrigin * (responsiveBoxScale - 1.);
+ #endif
+
+ v_responsiveUV = uv;
+ v_responsiveUV *= responsiveBoxScale;
+ v_responsiveUV += boxOrigin * (responsiveBoxScale - 1.);
+ v_responsiveUV += graphicOffset;
+ v_responsiveUV /= u_scale;
+ v_responsiveUV.x *= responsiveRatio;
+ v_responsiveUV = graphicRotation * v_responsiveUV;
+ v_responsiveUV.x /= responsiveRatio;
+
+ // ===================================================
+
+ float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;
+ vec2 patternBoxGivenSize = vec2(
+ (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,
+ (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y
+ );
+ patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;
+
+ vec3 boxSizeData = getBoxSize(patternBoxRatio, patternBoxGivenSize);
+ v_patternBoxSize = boxSizeData.xy;
+ float patternBoxNoFitBoxWidth = boxSizeData.z;
+ vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;
+
+ v_patternUV = uv;
+ v_patternUV += graphicOffset / patternBoxScale;
+ v_patternUV += boxOrigin;
+ v_patternUV -= boxOrigin / patternBoxScale;
+ v_patternUV *= u_resolution.xy;
+ v_patternUV /= u_pixelRatio;
+ if (u_fit > 0.) {
+ v_patternUV *= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);
+ }
+ v_patternUV /= u_scale;
+ v_patternUV = graphicRotation * v_patternUV;
+ v_patternUV += boxOrigin / patternBoxScale;
+ v_patternUV -= boxOrigin;
+ // x100 is a default multiplier between vertex and fragmant shaders
+ // we use it to avoid UV presision issues
+ v_patternUV *= .01;
+
+ // ===================================================
+
+ vec2 imageBoxSize;
+ if (u_fit == 1.) { // contain
+ imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
+ } else if (u_fit == 2.) { // cover
+ imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;
+ } else {
+ imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);
+ }
+ imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;
+ vec2 imageBoxScale = u_resolution.xy / imageBoxSize;
+
+ v_imageUV = uv;
+ v_imageUV *= imageBoxScale;
+ v_imageUV += boxOrigin * (imageBoxScale - 1.);
+ v_imageUV += graphicOffset;
+ v_imageUV /= u_scale;
+ v_imageUV.x *= u_imageAspectRatio;
+ v_imageUV = graphicRotation * v_imageUV;
+ v_imageUV.x /= u_imageAspectRatio;
+
+ v_imageUV += .5;
+ v_imageUV.y = 1. - v_imageUV.y;
+}`;
+export {
+ vertexShaderSource
+};
+//# sourceMappingURL=vertex-shader.js.map
diff --git a/public/vendor/paper-shaders/vertex-shader.js.map b/public/vendor/paper-shaders/vertex-shader.js.map
new file mode 100644
index 0000000..07cd0ca
--- /dev/null
+++ b/public/vendor/paper-shaders/vertex-shader.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["../src/vertex-shader.ts"],
+ "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;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nout vec2 v_objectUV;\nout vec2 v_objectBoxSize;\nout vec2 v_responsiveUV;\nout vec2 v_responsiveBoxGivenSize;\nout vec2 v_patternUV;\nout vec2 v_patternBoxSize;\nout vec2 v_imageUV;\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\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 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 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 vec2 responsiveBoxSize = getBoxSize(responsiveRatio, v_responsiveBoxGivenSize).xy;\n vec2 responsiveBoxScale = u_resolution.xy / 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 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 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 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 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"],
+ "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;",
+ "names": []
+}
diff --git a/scripts/serve-dev.mjs b/scripts/serve-dev.mjs
index 39fb5ae..ea45c70 100644
--- a/scripts/serve-dev.mjs
+++ b/scripts/serve-dev.mjs
@@ -21,7 +21,7 @@ function ensureEditsDir() {
function isLocalRequest(req) {
const host = (req.headers.host || "").split(":")[0];
- const ALLOWED = ["localhost", "127.0.0.1", "dev.mamadaevv.site", "f2ogw6fzi6trnp7cp43x8wsd.31.129.103.242.sslip.io"];
+ const ALLOWED = ["localhost", "127.0.0.1", "10.200.201.3", "dev.mamadaevv.site", "f2ogw6fzi6trnp7cp43x8wsd.31.129.103.242.sslip.io"];
return ALLOWED.includes(host);
}
diff --git a/src/pages/resume.en.html b/src/pages/resume.en.html
index 3eddfb1..746630f 100644
--- a/src/pages/resume.en.html
+++ b/src/pages/resume.en.html
@@ -9,220 +9,23 @@
/>
Resume — Nikolai Mamadaev
{{> head-links}}
-
{{> header-minimal}}
{{> fab-stack-resume}}
-
-