@paper-design/shaders 0.0.0-canary.0d8316e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +5 -0
  3. package/README.md +7 -0
  4. package/dist/empty-pixel.d.ts +1 -0
  5. package/dist/empty-pixel.js +10 -0
  6. package/dist/empty-pixel.js.map +7 -0
  7. package/dist/get-shader-color-from-string.d.ts +3 -0
  8. package/dist/get-shader-color-from-string.js +101 -0
  9. package/dist/get-shader-color-from-string.js.map +7 -0
  10. package/dist/get-shader-noise-texture.d.ts +1 -0
  11. package/dist/get-shader-noise-texture.js +18 -0
  12. package/dist/get-shader-noise-texture.js.map +7 -0
  13. package/dist/html-in-canvas.d.ts +35 -0
  14. package/dist/html-in-canvas.js +79 -0
  15. package/dist/html-in-canvas.js.map +7 -0
  16. package/dist/index.d.ts +69 -0
  17. package/dist/index.js +196 -0
  18. package/dist/index.js.map +7 -0
  19. package/dist/shader-color-spaces.d.ts +6 -0
  20. package/dist/shader-color-spaces.js +96 -0
  21. package/dist/shader-color-spaces.js.map +7 -0
  22. package/dist/shader-mount.d.ts +151 -0
  23. package/dist/shader-mount.js +605 -0
  24. package/dist/shader-mount.js.map +7 -0
  25. package/dist/shader-sizing.d.ts +30 -0
  26. package/dist/shader-sizing.js +38 -0
  27. package/dist/shader-sizing.js.map +7 -0
  28. package/dist/shader-utils.d.ts +10 -0
  29. package/dist/shader-utils.js +131 -0
  30. package/dist/shader-utils.js.map +7 -0
  31. package/dist/shaders/color-panels.d.ts +70 -0
  32. package/dist/shaders/color-panels.js +224 -0
  33. package/dist/shaders/color-panels.js.map +7 -0
  34. package/dist/shaders/dithering.d.ts +62 -0
  35. package/dist/shaders/dithering.js +271 -0
  36. package/dist/shaders/dithering.js.map +7 -0
  37. package/dist/shaders/dot-grid.d.ts +65 -0
  38. package/dist/shaders/dot-grid.js +110 -0
  39. package/dist/shaders/dot-grid.js.map +7 -0
  40. package/dist/shaders/dot-orbit.d.ts +57 -0
  41. package/dist/shaders/dot-orbit.js +123 -0
  42. package/dist/shaders/dot-orbit.js.map +7 -0
  43. package/dist/shaders/fluted-glass.d.ts +115 -0
  44. package/dist/shaders/fluted-glass.js +361 -0
  45. package/dist/shaders/fluted-glass.js.map +7 -0
  46. package/dist/shaders/gem-smoke.d.ts +96 -0
  47. package/dist/shaders/gem-smoke.js +573 -0
  48. package/dist/shaders/gem-smoke.js.map +7 -0
  49. package/dist/shaders/god-rays.d.ts +67 -0
  50. package/dist/shaders/god-rays.js +133 -0
  51. package/dist/shaders/god-rays.js.map +7 -0
  52. package/dist/shaders/grain-gradient.d.ts +80 -0
  53. package/dist/shaders/grain-gradient.js +301 -0
  54. package/dist/shaders/grain-gradient.js.map +7 -0
  55. package/dist/shaders/halftone-cmyk.d.ts +107 -0
  56. package/dist/shaders/halftone-cmyk.js +319 -0
  57. package/dist/shaders/halftone-cmyk.js.map +7 -0
  58. package/dist/shaders/halftone-dots.d.ts +83 -0
  59. package/dist/shaders/halftone-dots.js +345 -0
  60. package/dist/shaders/halftone-dots.js.map +7 -0
  61. package/dist/shaders/heatmap.d.ts +66 -0
  62. package/dist/shaders/heatmap.js +384 -0
  63. package/dist/shaders/heatmap.js.map +7 -0
  64. package/dist/shaders/image-dithering.d.ts +66 -0
  65. package/dist/shaders/image-dithering.js +209 -0
  66. package/dist/shaders/image-dithering.js.map +7 -0
  67. package/dist/shaders/lens-distortion.d.ts +100 -0
  68. package/dist/shaders/lens-distortion.js +290 -0
  69. package/dist/shaders/lens-distortion.js.map +7 -0
  70. package/dist/shaders/liquid-metal.d.ts +89 -0
  71. package/dist/shaders/liquid-metal.js +633 -0
  72. package/dist/shaders/liquid-metal.js.map +7 -0
  73. package/dist/shaders/mesh-gradient.d.ts +52 -0
  74. package/dist/shaders/mesh-gradient.js +131 -0
  75. package/dist/shaders/mesh-gradient.js.map +7 -0
  76. package/dist/shaders/metaballs.d.ts +51 -0
  77. package/dist/shaders/metaballs.js +111 -0
  78. package/dist/shaders/metaballs.js.map +7 -0
  79. package/dist/shaders/neuro-noise.d.ts +47 -0
  80. package/dist/shaders/neuro-noise.js +77 -0
  81. package/dist/shaders/neuro-noise.js.map +7 -0
  82. package/dist/shaders/paper-texture.d.ts +113 -0
  83. package/dist/shaders/paper-texture.js +541 -0
  84. package/dist/shaders/paper-texture.js.map +7 -0
  85. package/dist/shaders/perlin-noise.d.ts +52 -0
  86. package/dist/shaders/perlin-noise.js +167 -0
  87. package/dist/shaders/perlin-noise.js.map +7 -0
  88. package/dist/shaders/pulsing-border.d.ts +98 -0
  89. package/dist/shaders/pulsing-border.js +239 -0
  90. package/dist/shaders/pulsing-border.js.map +7 -0
  91. package/dist/shaders/simplex-noise.d.ts +45 -0
  92. package/dist/shaders/simplex-noise.js +92 -0
  93. package/dist/shaders/simplex-noise.js.map +7 -0
  94. package/dist/shaders/smoke-ring.d.ts +61 -0
  95. package/dist/shaders/smoke-ring.js +133 -0
  96. package/dist/shaders/smoke-ring.js.map +7 -0
  97. package/dist/shaders/spiral.d.ts +61 -0
  98. package/dist/shaders/spiral.js +83 -0
  99. package/dist/shaders/spiral.js.map +7 -0
  100. package/dist/shaders/static-mesh-gradient.d.ts +63 -0
  101. package/dist/shaders/static-mesh-gradient.js +131 -0
  102. package/dist/shaders/static-mesh-gradient.js.map +7 -0
  103. package/dist/shaders/static-radial-gradient.d.ts +72 -0
  104. package/dist/shaders/static-radial-gradient.js +188 -0
  105. package/dist/shaders/static-radial-gradient.js.map +7 -0
  106. package/dist/shaders/swirl.d.ts +63 -0
  107. package/dist/shaders/swirl.js +104 -0
  108. package/dist/shaders/swirl.js.map +7 -0
  109. package/dist/shaders/voronoi.d.ts +65 -0
  110. package/dist/shaders/voronoi.js +139 -0
  111. package/dist/shaders/voronoi.js.map +7 -0
  112. package/dist/shaders/warp.d.ts +70 -0
  113. package/dist/shaders/warp.js +130 -0
  114. package/dist/shaders/warp.js.map +7 -0
  115. package/dist/shaders/water.d.ts +63 -0
  116. package/dist/shaders/water.js +135 -0
  117. package/dist/shaders/water.js.map +7 -0
  118. package/dist/shaders/waves.d.ts +53 -0
  119. package/dist/shaders/waves.js +66 -0
  120. package/dist/shaders/waves.js.map +7 -0
  121. package/dist/types.d.ts +3 -0
  122. package/dist/types.js +6 -0
  123. package/dist/types.js.map +7 -0
  124. package/dist/vertex-shader.d.ts +2 -0
  125. package/dist/vertex-shader.js +163 -0
  126. package/dist/vertex-shader.js.map +7 -0
  127. package/package.json +29 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/shaders/gem-smoke.ts"],
4
+ "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_image (sampler2D): Pre-processed source image texture (R = edge gradient, G = alpha)\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, needs innerGlow > 0 (0 to 1)\n * - u_outerDistortion (float): Power of smoke distortion outside the input shape, needs outerGlow > 0 (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, needs innerGlow > 0 (-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 * - u_shape (float): Predefined shape mask, needs no image (0 = none, 1 = circle, 2 = daisy, 3 = diamond, 4 = metaballs)\n * - u_isImage (bool): Whether an image mask is provided; when true, u_shape is ignored\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 * - v_responsiveUV (vec2): Responsive UV coordinates that adapt to canvas aspect ratio (used by the 'none' shape)\n * - v_responsiveBoxGivenSize (vec2): Given size of the responsive bounding box (used by the 'none' shape)\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.1 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;\n \nout vec4 fragColor;\n\nuniform sampler2D u_image;\nuniform float u_shape;\nuniform bool u_isImage;\n\nuniform float u_time;\nuniform vec4 u_colors[${gemSmokeMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorInner;\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${declarePI}\n${rotation2}\n\n// 9x9 Gaussian blur on R and G channels\nvec2 gaussBlur9x9RG(sampler2D tex, vec2 uv, 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 // Blurred image: x = roundness, y = alpha\n vec2 blurred = gaussBlur9x9RG(u_image, imageUV, 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"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,67 @@
1
+ import type { vec4 } from '../types.js';
2
+ import type { ShaderMotionParams } from '../shader-mount.js';
3
+ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
4
+ export declare const godRaysMeta: {
5
+ readonly maxColorCount: 5;
6
+ };
7
+ /**
8
+ * Animated rays of light radiating from the center, blended with up to 5 colors.
9
+ *
10
+ * Fragment shader uniforms:
11
+ * - u_time (float): Animation time
12
+ * - u_colorBack (vec4): Background color in RGBA
13
+ * - u_colorBloom (vec4): Color overlay blended with the rays in RGBA, needs bloom > 0
14
+ * - u_colors (vec4[]): Up to 5 ray colors in RGBA
15
+ * - u_colorsCount (float): Number of active colors
16
+ * - u_bloom (float): Strength of the bloom/overlay effect, 0 = alpha blend, 1 = additive blend (0 to 1)
17
+ * - u_intensity (float): Visibility/strength of the rays (0 to 1)
18
+ * - u_density (float): The number of rays (0 to 1)
19
+ * - u_spotty (float): The length of the rays, higher = more spots/shorter rays (0 to 1)
20
+ * - u_midSize (float): Size of the circular glow shape in the center, needs midIntensity > 0 (0 to 1)
21
+ * - u_midIntensity (float): Brightness/intensity of the central glow, needs midSize > 0 (0 to 1)
22
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
23
+ *
24
+ * Vertex shader outputs (used in fragment shader):
25
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied
26
+ *
27
+ * The rays are adjustable by size, density, brightness and center glow.
28
+ *
29
+ * Vertex shader uniforms:
30
+ * - u_resolution (vec2): Canvas resolution in pixels
31
+ * - u_pixelRatio (float): Device pixel ratio
32
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
33
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
34
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
35
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
36
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
37
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
38
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
39
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
40
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
41
+ *
42
+ */
43
+ export declare const godRaysFragmentShader: string;
44
+ export interface GodRaysUniforms extends ShaderSizingUniforms {
45
+ u_colorBack: [number, number, number, number];
46
+ u_colorBloom: [number, number, number, number];
47
+ u_colors: vec4[];
48
+ u_colorsCount: number;
49
+ u_spotty: number;
50
+ u_midSize: number;
51
+ u_midIntensity: number;
52
+ u_density: number;
53
+ u_intensity: number;
54
+ u_bloom: number;
55
+ u_noiseTexture?: HTMLImageElement;
56
+ }
57
+ export interface GodRaysParams extends ShaderSizingParams, ShaderMotionParams {
58
+ colorBack?: string;
59
+ colorBloom?: string;
60
+ colors?: string[];
61
+ spotty?: number;
62
+ midSize?: number;
63
+ midIntensity?: number;
64
+ density?: number;
65
+ intensity?: number;
66
+ bloom?: number;
67
+ }
@@ -0,0 +1,133 @@
1
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
+ * Paper Shaders *
3
+ * https://github.com/paper-design/shaders *
4
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
+
6
+ import {} from "../shader-sizing.js";
7
+ import { declarePI, rotation2, textureRandomizerR, colorBandingFix, proceduralHash11 } from "../shader-utils.js";
8
+ const godRaysMeta = {
9
+ maxColorCount: 5
10
+ };
11
+ const godRaysFragmentShader = `#version 300 es
12
+ precision mediump float;
13
+
14
+ uniform float u_time;
15
+
16
+ uniform sampler2D u_noiseTexture;
17
+
18
+ uniform vec4 u_colorBack;
19
+ uniform vec4 u_colorBloom;
20
+ uniform vec4 u_colors[${godRaysMeta.maxColorCount}];
21
+ uniform float u_colorsCount;
22
+
23
+ uniform float u_density;
24
+ uniform float u_spotty;
25
+ uniform float u_midSize;
26
+ uniform float u_midIntensity;
27
+ uniform float u_intensity;
28
+ uniform float u_bloom;
29
+
30
+ in vec2 v_objectUV;
31
+
32
+ out vec4 fragColor;
33
+
34
+ ${declarePI}
35
+ ${rotation2}
36
+ ${textureRandomizerR}
37
+ float valueNoise(vec2 st) {
38
+ vec2 i = floor(st);
39
+ vec2 f = fract(st);
40
+ float a = randomR(i);
41
+ float b = randomR(i + vec2(1.0, 0.0));
42
+ float c = randomR(i + vec2(0.0, 1.0));
43
+ float d = randomR(i + vec2(1.0, 1.0));
44
+ vec2 u = f * f * (3.0 - 2.0 * f);
45
+ float x1 = mix(a, b, u.x);
46
+ float x2 = mix(c, d, u.x);
47
+ return mix(x1, x2, u.y);
48
+ }
49
+
50
+ ${proceduralHash11}
51
+
52
+ float raysShape(vec2 uv, float r, float freq, float intensity, float radius) {
53
+ float a = atan(uv.y, uv.x);
54
+ vec2 left = vec2(a * freq, r);
55
+ vec2 right = vec2(fract(a / TWO_PI) * TWO_PI * freq, r);
56
+ float n_left = pow(valueNoise(left), intensity);
57
+ float n_right = pow(valueNoise(right), intensity);
58
+ float shape = mix(n_right, n_left, smoothstep(-.15, .15, uv.x));
59
+ return shape;
60
+ }
61
+
62
+ void main() {
63
+ vec2 shape_uv = v_objectUV;
64
+
65
+ float t = .2 * u_time;
66
+
67
+ float radius = length(shape_uv);
68
+ float spots = 6.5 * abs(u_spotty);
69
+
70
+ float intensity = 4. - 3. * clamp(u_intensity, 0., 1.);
71
+
72
+ float delta = 1. - smoothstep(0., 1., radius);
73
+
74
+ float midSize = 10. * abs(u_midSize);
75
+ float ms_lo = 0.02 * midSize;
76
+ float ms_hi = max(midSize, 1e-6);
77
+ float middleShape = pow(u_midIntensity, 0.3) * (1. - smoothstep(ms_lo, ms_hi, 3.0 * radius));
78
+ middleShape = pow(middleShape, 5.0);
79
+
80
+ vec3 accumColor = vec3(0.0);
81
+ float accumAlpha = 0.0;
82
+
83
+ for (int i = 0; i < ${godRaysMeta.maxColorCount}; i++) {
84
+ if (i >= int(u_colorsCount)) break;
85
+
86
+ vec2 rotatedUV = rotate(shape_uv, float(i) + 1.0);
87
+
88
+ float r1 = radius * (1.0 + 0.4 * float(i)) - 3.0 * t;
89
+ float r2 = 0.5 * radius * (1.0 + spots) - 2.0 * t;
90
+ float density = 6. * u_density + step(.5, u_density) * pow(4.5 * (u_density - .5), 4.);
91
+ float f = mix(1.0, 3.0 + 0.5 * float(i), hash11(float(i) * 15.)) * density;
92
+
93
+ float ray = raysShape(rotatedUV, r1, 5.0 * f, intensity, radius);
94
+ ray *= raysShape(rotatedUV, r2, 4.0 * f, intensity, radius);
95
+ ray += (1. + 4. * ray) * middleShape;
96
+ ray = clamp(ray, 0.0, 1.0);
97
+
98
+ float srcAlpha = u_colors[i].a * ray;
99
+ vec3 srcColor = u_colors[i].rgb * srcAlpha;
100
+
101
+ vec3 alphaBlendColor = accumColor + (1.0 - accumAlpha) * srcColor;
102
+ float alphaBlendAlpha = accumAlpha + (1.0 - accumAlpha) * srcAlpha;
103
+
104
+ vec3 addBlendColor = accumColor + srcColor;
105
+ float addBlendAlpha = accumAlpha + srcAlpha;
106
+
107
+ accumColor = mix(alphaBlendColor, addBlendColor, u_bloom);
108
+ accumAlpha = mix(alphaBlendAlpha, addBlendAlpha, u_bloom);
109
+ }
110
+
111
+ float overlayAlpha = u_colorBloom.a;
112
+ vec3 overlayColor = u_colorBloom.rgb * overlayAlpha;
113
+
114
+ vec3 colorWithOverlay = accumColor + accumAlpha * overlayColor;
115
+ accumColor = mix(accumColor, colorWithOverlay, u_bloom);
116
+
117
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
118
+
119
+ vec3 color = accumColor + (1. - accumAlpha) * bgColor;
120
+ float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;
121
+ color = clamp(color, 0., 1.);
122
+ opacity = clamp(opacity, 0., 1.);
123
+
124
+ ${colorBandingFix}
125
+
126
+ fragColor = vec4(color, opacity);
127
+ }
128
+ `;
129
+ export {
130
+ godRaysFragmentShader,
131
+ godRaysMeta
132
+ };
133
+ //# sourceMappingURL=god-rays.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/shaders/god-rays.ts"],
4
+ "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, needs bloom > 0\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, needs midIntensity > 0 (0 to 1)\n * - u_midIntensity (float): Brightness/intensity of the central glow, needs midSize > 0 (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"],
5
+ "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;",
6
+ "names": []
7
+ }
@@ -0,0 +1,80 @@
1
+ import type { vec4 } from '../types.js';
2
+ import type { ShaderMotionParams } from '../shader-mount.js';
3
+ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
4
+ export declare const grainGradientMeta: {
5
+ readonly maxColorCount: 7;
6
+ };
7
+ /**
8
+ * Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms.
9
+ *
10
+ * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit
11
+ *
12
+ * Fragment shader uniforms:
13
+ * - u_time (float): Animation time
14
+ * - u_resolution (vec2): Canvas resolution in pixels
15
+ * - u_pixelRatio (float): Device pixel ratio
16
+ * - u_worldWidth (float): Virtual width of the graphic
17
+ * - u_worldHeight (float): Virtual height of the graphic
18
+ * - u_fit (float): Fit mode (0 = none, 1 = contain, 2 = cover)
19
+ * - u_scale (float): Overall zoom level (0.01 to 4)
20
+ * - u_rotation (float): Rotation angle in degrees (0 to 360)
21
+ * - u_offsetX (float): Horizontal offset (-1 to 1)
22
+ * - u_offsetY (float): Vertical offset (-1 to 1)
23
+ * - u_colorBack (vec4): Background color in RGBA
24
+ * - u_colors (vec4[]): Up to 7 gradient colors in RGBA
25
+ * - u_colorsCount (float): Number of active colors
26
+ * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)
27
+ * - u_intensity (float): Distortion between color bands (0 to 1)
28
+ * - u_noise (float): Grainy noise overlay (0 to 1)
29
+ * - u_shape (float): Shape type (1 = wave, 2 = dots, 3 = truchet, 4 = corners, 5 = ripple, 6 = blob, 7 = sphere)
30
+ * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
31
+ *
32
+ * Vertex shader outputs (used in fragment shader):
33
+ * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used for shapes 4-7)
34
+ * - v_objectBoxSize (vec2): Size of the object bounding box in pixels
35
+ * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for shapes 1-3)
36
+ * - v_patternBoxSize (vec2): Size of the pattern bounding box in pixels
37
+ *
38
+ * Vertex shader uniforms:
39
+ * - u_resolution (vec2): Canvas resolution in pixels
40
+ * - u_pixelRatio (float): Device pixel ratio
41
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
42
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
43
+ * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas
44
+ * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas
45
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
46
+ * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
47
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
48
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
49
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
50
+ *
51
+ */
52
+ export declare const grainGradientFragmentShader: string;
53
+ export interface GrainGradientUniforms extends ShaderSizingUniforms {
54
+ u_colorBack: [number, number, number, number];
55
+ u_colors: vec4[];
56
+ u_colorsCount: number;
57
+ u_softness: number;
58
+ u_intensity: number;
59
+ u_noise: number;
60
+ u_shape: (typeof GrainGradientShapes)[GrainGradientShape];
61
+ u_noiseTexture?: HTMLImageElement;
62
+ }
63
+ export interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {
64
+ colorBack?: string;
65
+ colors?: string[];
66
+ softness?: number;
67
+ intensity?: number;
68
+ noise?: number;
69
+ shape?: GrainGradientShape;
70
+ }
71
+ export declare const GrainGradientShapes: {
72
+ wave: number;
73
+ dots: number;
74
+ truchet: number;
75
+ corners: number;
76
+ ripple: number;
77
+ blob: number;
78
+ sphere: number;
79
+ };
80
+ export type GrainGradientShape = keyof typeof GrainGradientShapes;