@paper-design/shaders 0.0.54 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/get-empty-pixel.d.ts +1 -0
- package/dist/get-empty-pixel.js +19 -0
- package/dist/get-empty-pixel.js.map +7 -0
- package/dist/get-shader-noise-texture.js +1 -1
- package/dist/get-shader-noise-texture.js.map +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +2 -2
- package/dist/shaders/dithering.d.ts +1 -1
- package/dist/shaders/dithering.js.map +1 -1
- package/dist/shaders/fluted-glass.d.ts +3 -2
- package/dist/shaders/fluted-glass.js +4 -4
- package/dist/shaders/fluted-glass.js.map +2 -2
- package/dist/shaders/heatmap.d.ts +2 -2
- package/dist/shaders/heatmap.js +3 -3
- package/dist/shaders/heatmap.js.map +1 -1
- package/dist/shaders/image-dithering.d.ts +3 -3
- package/dist/shaders/image-dithering.js +1 -1
- package/dist/shaders/image-dithering.js.map +1 -1
- package/dist/shaders/paper-texture.d.ts +13 -13
- package/dist/shaders/paper-texture.js +26 -16
- package/dist/shaders/paper-texture.js.map +2 -2
- package/dist/shaders/pulsing-border.d.ts +17 -0
- package/dist/shaders/pulsing-border.js +82 -83
- package/dist/shaders/pulsing-border.js.map +2 -2
- package/dist/shaders/water.d.ts +1 -1
- package/dist/shaders/water.js +10 -10
- package/dist/shaders/water.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/heatmap.ts"],
|
|
4
|
-
"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// 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 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 *= smoothstep(1., 1. - th, uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= smoothstep(1., 1. - th, 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) * sst(.5, .2, 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) * sst(edge, .0, 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) * sst(.9, .8, 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) * sst(.45, .3, 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., sst(.54, .4, 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) * sst(.8, .6, 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) * sst(1., .6, 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 /= sst(1., .85, uv.y);\n }\n\n s = clamp(0., 1., s);\n return s;\n}\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 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 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) * sst(1., .65, 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 ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.filter = 'grayscale(100%) blur(' + maxBlur + 'px)';\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n const bigBlurData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.filter = 'grayscale(100%) blur(' + Math.round(0.12 * maxBlur) + 'px)';\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n const innerBlurSmallData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.filter = 'grayscale(100%) blur(5px)';\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n const contourData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n\n let processedImageData = ctx.createImageData(canvas.width, canvas.height);\n const totalPixels = canvas.width * canvas.height;\n for (let i = 0; i < totalPixels; i++) {\n const px = i * 4;\n processedImageData.data[px] = contourData[px]!;\n processedImageData.data[px + 1] = bigBlurData[px]!;\n processedImageData.data[px + 2] = innerBlurSmallData[px]!;\n processedImageData.data[px + 3] = 255;\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\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\nexport interface HeatmapUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\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 | undefined;\n contour?: number;\n angle?: number;\n noise?: number;\n innerGlow?: number;\n outerGlow?: number;\n colorBack?: string;\n colors?: string[];\n}\n"],
|
|
4
|
+
"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// 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 *= smoothstep(1., 1. - th, uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= smoothstep(1., 1. - th, 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) * sst(.5, .2, 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) * sst(edge, .0, 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) * sst(.9, .8, 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) * sst(.45, .3, 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., sst(.54, .4, 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) * sst(.8, .6, 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) * sst(1., .6, 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 /= sst(1., .85, uv.y);\n }\n\n s = clamp(0., 1., s);\n return s;\n}\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 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 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) * sst(1., .65, 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 ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.filter = 'grayscale(100%) blur(' + maxBlur + 'px)';\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n const bigBlurData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.filter = 'grayscale(100%) blur(' + Math.round(0.12 * maxBlur) + 'px)';\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n const innerBlurSmallData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.filter = 'grayscale(100%) blur(5px)';\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\n const contourData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\n\n let processedImageData = ctx.createImageData(canvas.width, canvas.height);\n const totalPixels = canvas.width * canvas.height;\n for (let i = 0; i < totalPixels; i++) {\n const px = i * 4;\n processedImageData.data[px] = contourData[px]!;\n processedImageData.data[px + 1] = bigBlurData[px]!;\n processedImageData.data[px + 2] = innerBlurSmallData[px]!;\n processedImageData.data[px + 3] = 255;\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\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\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"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -21,7 +21,7 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
21
21
|
*/
|
|
22
22
|
export declare const imageDitheringFragmentShader: string;
|
|
23
23
|
export interface ImageDitheringUniforms extends ShaderSizingUniforms {
|
|
24
|
-
u_image: HTMLImageElement | string
|
|
24
|
+
u_image: HTMLImageElement | string;
|
|
25
25
|
u_colorFront: [number, number, number, number];
|
|
26
26
|
u_colorBack: [number, number, number, number];
|
|
27
27
|
u_colorHighlight: [number, number, number, number];
|
|
@@ -31,12 +31,12 @@ export interface ImageDitheringUniforms extends ShaderSizingUniforms {
|
|
|
31
31
|
u_originalColors: boolean;
|
|
32
32
|
}
|
|
33
33
|
export interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {
|
|
34
|
-
image
|
|
34
|
+
image: HTMLImageElement | string;
|
|
35
35
|
colorFront?: string;
|
|
36
36
|
colorBack?: string;
|
|
37
37
|
colorHighlight?: string;
|
|
38
38
|
type?: DitheringType;
|
|
39
|
-
|
|
39
|
+
size?: number;
|
|
40
40
|
colorSteps?: number;
|
|
41
41
|
originalColors?: boolean;
|
|
42
42
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/image-dithering.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingUV, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Dithering effect over user texture using 3-color palette\n * or colors sampled from original image\n *\n * Uniforms:\n * - u_colorBack, u_colorFront, u_colorHighlight (RGBA)\n * (u_colorHighlight to be the lightest parts of u_colorFront pixels)\n * - pxSize: px size set relative to canvas resolution\n * - u_type (float used as integer)\n * ---- 1: random dithering\n * ---- 2: 2x2 Bayer matrix\n * ---- 3: 4x4 Bayer matrix\n * ---- 4: 8x8 Bayer matrix\n * - u_originalColors - switching between 3 colors palette and original image colors\n * - u_colorSteps - number of colors to use (applies to both color modes)\n *\n * Note: pixelization is applied to the shapes BEFORE dithering,\n * meaning pixels don't react to scaling and fit\n */\n\n// language=GLSL\nexport const imageDitheringFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\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\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform mediump float u_imageAspectRatio;\n\nuniform float u_type;\nuniform float u_pxSize;\nuniform bool u_originalColors;\nuniform float u_colorSteps;\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv, vec2 px) {\n float left = step(-px.x, uv.x);\n float right = step(uv.x, 1.);\n float bottom = step(-px.y, uv.y);\n float top = step(uv.y, 1. + px.y);\n\n return left * right * bottom * top;\n}\n\n${proceduralHash21}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n 0, 8, 2, 10,\n 12, 4, 14, 6,\n 3, 11, 1, 9,\n 15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n 0, 32, 8, 40, 2, 34, 10, 42,\n 48, 16, 56, 24, 50, 18, 58, 26,\n 12, 44, 4, 36, 14, 46, 6, 38,\n 60, 28, 52, 20, 62, 30, 54, 22,\n 3, 35, 11, 43, 1, 33, 9, 41,\n 51, 19, 59, 27, 49, 17, 57, 25,\n 15, 47, 7, 39, 13, 45, 5, 37,\n 63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(mod(uv, float(size)));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n\n #define USE_IMAGE_SIZING\n #define USE_PIXELIZATION\n ${sizingUV}\n\n vec2 dithering_uv = pxSizeUv;\n vec2 ditheringNoise_uv = u_resolution * uv;\n vec4 image = texture(u_image, imageUV);\n float frame = getUvFrame(imageUV, pxSize / u_resolution.xy);\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\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoise_uv), lum);\n } break;\n case 2:\n dithering = getBayerValue(dithering_uv, 2);\n break;\n case 3:\n dithering = getBayerValue(dithering_uv, 4);\n break;\n default:\n dithering = getBayerValue(dithering_uv, 8);\n break;\n }\n\n\n float steps = max(floor(u_colorSteps), 1.);\n float ditherAmount = 1.0 / (steps);\n
|
|
4
|
+
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingUV, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { proceduralHash21 } from '../shader-utils.js';\n\n/**\n * Dithering effect over user texture using 3-color palette\n * or colors sampled from original image\n *\n * Uniforms:\n * - u_colorBack, u_colorFront, u_colorHighlight (RGBA)\n * (u_colorHighlight to be the lightest parts of u_colorFront pixels)\n * - pxSize: px size set relative to canvas resolution\n * - u_type (float used as integer)\n * ---- 1: random dithering\n * ---- 2: 2x2 Bayer matrix\n * ---- 3: 4x4 Bayer matrix\n * ---- 4: 8x8 Bayer matrix\n * - u_originalColors - switching between 3 colors palette and original image colors\n * - u_colorSteps - number of colors to use (applies to both color modes)\n *\n * Note: pixelization is applied to the shapes BEFORE dithering,\n * meaning pixels don't react to scaling and fit\n */\n\n// language=GLSL\nexport const imageDitheringFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\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\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform mediump float u_imageAspectRatio;\n\nuniform float u_type;\nuniform float u_pxSize;\nuniform bool u_originalColors;\nuniform float u_colorSteps;\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv, vec2 px) {\n float left = step(-px.x, uv.x);\n float right = step(uv.x, 1.);\n float bottom = step(-px.y, uv.y);\n float top = step(uv.y, 1. + px.y);\n\n return left * right * bottom * top;\n}\n\n${proceduralHash21}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n 0, 8, 2, 10,\n 12, 4, 14, 6,\n 3, 11, 1, 9,\n 15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n 0, 32, 8, 40, 2, 34, 10, 42,\n 48, 16, 56, 24, 50, 18, 58, 26,\n 12, 44, 4, 36, 14, 46, 6, 38,\n 60, 28, 52, 20, 62, 30, 54, 22,\n 3, 35, 11, 43, 1, 33, 9, 41,\n 51, 19, 59, 27, 49, 17, 57, 25,\n 15, 47, 7, 39, 13, 45, 5, 37,\n 63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(mod(uv, float(size)));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n\n #define USE_IMAGE_SIZING\n #define USE_PIXELIZATION\n ${sizingUV}\n\n vec2 dithering_uv = pxSizeUv;\n vec2 ditheringNoise_uv = u_resolution * uv;\n vec4 image = texture(u_image, imageUV);\n float frame = getUvFrame(imageUV, pxSize / u_resolution.xy);\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\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoise_uv), lum);\n } break;\n case 2:\n dithering = getBayerValue(dithering_uv, 2);\n break;\n case 3:\n dithering = getBayerValue(dithering_uv, 4);\n break;\n default:\n dithering = getBayerValue(dithering_uv, 8);\n break;\n }\n\n\n float steps = max(floor(u_colorSteps), 1.);\n float ditherAmount = 1.0 / (steps);\n\n vec3 color = vec3(0.0);\n float opacity = 1.;\n\n dithering -= .5;\n float brightness = clamp(lum + dithering * ditherAmount, 0.0, 1.0);\n brightness = mix(0.0, brightness, frame);\n float quantLum = floor(brightness * steps + 0.5) / steps;\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 * steps + 0.5) / steps;\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\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}\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}\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"],
|
|
5
5
|
"mappings": ";;;;;AACA,SAAS,gBAAoE;AAC7E,SAAS,wBAAwB;AAuB1B,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuClD,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,IAwCd,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyFL,MAAM,iBAAiB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,12 +7,12 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
7
7
|
* - u_colorFront, u_colorBack (RGBA)
|
|
8
8
|
* - u_contrast - mixing front and back colors
|
|
9
9
|
* - u_roughness - pixel noise, related to canvas => not scalable
|
|
10
|
-
* - u_fiber,
|
|
11
|
-
* - u_crumples,
|
|
12
|
-
* - u_folds,
|
|
10
|
+
* - u_fiber, u_fiberSize - curly shaped noise
|
|
11
|
+
* - u_crumples, u_crumpleSize - cell-based pattern
|
|
12
|
+
* - u_folds, u_foldCount - lines pattern, 15 max
|
|
13
13
|
* - u_drops - metaballs-like pattern
|
|
14
14
|
* - u_seed - applied to folds, crumples and dots
|
|
15
|
-
* -
|
|
15
|
+
* - u_fade - big-scale noise mask applied to everything but roughness
|
|
16
16
|
*
|
|
17
17
|
* - u_noiseTexture (sampler2D): pre-computed randomizer source
|
|
18
18
|
*
|
|
@@ -26,28 +26,28 @@ export interface PaperTextureUniforms extends ShaderSizingUniforms {
|
|
|
26
26
|
u_contrast: number;
|
|
27
27
|
u_roughness: number;
|
|
28
28
|
u_fiber: number;
|
|
29
|
-
|
|
29
|
+
u_fiberSize: number;
|
|
30
30
|
u_crumples: number;
|
|
31
|
-
|
|
31
|
+
u_foldCount: number;
|
|
32
32
|
u_folds: number;
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
u_fade: number;
|
|
34
|
+
u_crumpleSize: number;
|
|
35
35
|
u_drops: number;
|
|
36
36
|
u_seed: number;
|
|
37
37
|
}
|
|
38
38
|
export interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {
|
|
39
|
-
image?: HTMLImageElement | string
|
|
39
|
+
image?: HTMLImageElement | string;
|
|
40
40
|
colorFront?: string;
|
|
41
41
|
colorBack?: string;
|
|
42
42
|
contrast?: number;
|
|
43
43
|
roughness?: number;
|
|
44
44
|
fiber?: number;
|
|
45
|
-
|
|
45
|
+
fiberSize?: number;
|
|
46
46
|
crumples?: number;
|
|
47
|
-
|
|
47
|
+
foldCount?: number;
|
|
48
48
|
folds?: number;
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
fade?: number;
|
|
50
|
+
crumpleSize?: number;
|
|
51
51
|
drops?: number;
|
|
52
52
|
seed?: number;
|
|
53
53
|
}
|
|
@@ -20,14 +20,14 @@ uniform float u_imageAspectRatio;
|
|
|
20
20
|
uniform float u_contrast;
|
|
21
21
|
uniform float u_roughness;
|
|
22
22
|
uniform float u_fiber;
|
|
23
|
-
uniform float
|
|
23
|
+
uniform float u_fiberSize;
|
|
24
24
|
uniform float u_crumples;
|
|
25
|
-
uniform float
|
|
25
|
+
uniform float u_crumpleSize;
|
|
26
26
|
uniform float u_folds;
|
|
27
|
-
uniform float
|
|
27
|
+
uniform float u_foldCount;
|
|
28
28
|
uniform float u_drops;
|
|
29
29
|
uniform float u_seed;
|
|
30
|
-
uniform float
|
|
30
|
+
uniform float u_fade;
|
|
31
31
|
|
|
32
32
|
uniform sampler2D u_noiseTexture;
|
|
33
33
|
|
|
@@ -125,13 +125,13 @@ vec2 folds(vec2 uv) {
|
|
|
125
125
|
vec3 pp = vec3(0.);
|
|
126
126
|
float l = 9.;
|
|
127
127
|
for (float i = 0.; i < 15.; i++) {
|
|
128
|
-
if (i >=
|
|
128
|
+
if (i >= u_foldCount) break;
|
|
129
129
|
vec2 rand = randomGB(vec2(i, i * u_seed));
|
|
130
130
|
float an = rand.x * TWO_PI;
|
|
131
131
|
vec2 p = vec2(cos(an), sin(an)) * rand.y;
|
|
132
132
|
float dist = distance(uv, p);
|
|
133
133
|
l = min(l, dist);
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
if (l == dist) {
|
|
136
136
|
pp.xy = (uv - p.xy);
|
|
137
137
|
pp.z = dist;
|
|
@@ -157,6 +157,10 @@ float drops(vec2 uv) {
|
|
|
157
157
|
return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
float lst(float edge0, float edge1, float x) {
|
|
161
|
+
return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
|
162
|
+
}
|
|
163
|
+
|
|
160
164
|
void main() {
|
|
161
165
|
|
|
162
166
|
vec2 imageUV = v_imageUV;
|
|
@@ -166,10 +170,10 @@ void main() {
|
|
|
166
170
|
vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;
|
|
167
171
|
float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));
|
|
168
172
|
|
|
169
|
-
vec2 crumplesUV = fract(patternUV * .
|
|
173
|
+
vec2 crumplesUV = fract(patternUV * .02 / u_crumpleSize - u_seed) * 32.;
|
|
170
174
|
float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));
|
|
171
175
|
|
|
172
|
-
vec2 fiberUV =
|
|
176
|
+
vec2 fiberUV = 2. / u_fiberSize * patternUV;
|
|
173
177
|
float fiber = fiberNoise(fiberUV, vec2(0.));
|
|
174
178
|
fiber = .5 * u_fiber * (fiber - 1.);
|
|
175
179
|
|
|
@@ -183,7 +187,17 @@ void main() {
|
|
|
183
187
|
vec2 w2 = folds(foldsUV);
|
|
184
188
|
|
|
185
189
|
float drops = u_drops * drops(patternUV * 2.);
|
|
186
|
-
|
|
190
|
+
|
|
191
|
+
float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed);
|
|
192
|
+
fade = clamp(8. * pow(fade, 3.), 0., 1.);
|
|
193
|
+
|
|
194
|
+
w = mix(w, vec2(0.), fade);
|
|
195
|
+
w2 = mix(w2, vec2(0.), fade);
|
|
196
|
+
crumples = mix(crumples, 0., fade);
|
|
197
|
+
drops = mix(drops, 0., fade);
|
|
198
|
+
fiber *= mix(1., .5, fade);
|
|
199
|
+
roughness *= mix(1., .5, fade);
|
|
200
|
+
|
|
187
201
|
normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);
|
|
188
202
|
normalImage.xy += u_folds * 2. * w;
|
|
189
203
|
|
|
@@ -193,13 +207,9 @@ void main() {
|
|
|
193
207
|
normal.xy += 3. * drops;
|
|
194
208
|
normalImage.xy += .2 * drops;
|
|
195
209
|
|
|
196
|
-
float blur = u_blur * smoothstep(0., 1., fbm(.17 * patternUV + 10. * u_seed));
|
|
197
|
-
normal *= (1. - 2. * blur);
|
|
198
|
-
fiber *= (1. - blur);
|
|
199
|
-
|
|
200
210
|
normal.xy += u_roughness * 1.5 * roughness;
|
|
201
211
|
normal.xy += fiber;
|
|
202
|
-
|
|
212
|
+
|
|
203
213
|
normalImage += u_roughness * .75 * roughness;
|
|
204
214
|
normalImage += .2 * fiber;
|
|
205
215
|
|
|
@@ -215,7 +225,7 @@ void main() {
|
|
|
215
225
|
float frame = getUvFrame(imageUV);
|
|
216
226
|
vec4 image = texture(u_image, imageUV);
|
|
217
227
|
image.rgb += .6 * pow(u_contrast, .4) * (res - .7);
|
|
218
|
-
|
|
228
|
+
|
|
219
229
|
frame *= image.a;
|
|
220
230
|
|
|
221
231
|
vec3 color = fgColor * res;
|
|
@@ -224,7 +234,7 @@ void main() {
|
|
|
224
234
|
color += bgColor * (1. - opacity);
|
|
225
235
|
opacity += bgOpacity * (1. - opacity);
|
|
226
236
|
opacity = mix(opacity, 1., frame);
|
|
227
|
-
|
|
237
|
+
|
|
228
238
|
color -= .007 * drops;
|
|
229
239
|
|
|
230
240
|
color.rgb = mix(color, image.rgb, frame);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/paper-texture.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * Mimicking paper texture with a combination of noises\n *\n * Uniforms:\n * - u_colorFront, u_colorBack (RGBA)\n * - u_contrast - mixing front and back colors\n * - u_roughness - pixel noise, related to canvas => not scalable\n * - u_fiber,
|
|
5
|
-
"mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,YAAY,0BAA0B;AAqB9D,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BhD,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2ClB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
4
|
+
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * Mimicking paper texture with a combination of noises\n *\n * Uniforms:\n * - u_colorFront, u_colorBack (RGBA)\n * - u_contrast - mixing front and back colors\n * - u_roughness - pixel noise, related to canvas => not scalable\n * - u_fiber, u_fiberSize - curly shaped noise\n * - u_crumples, u_crumpleSize - cell-based pattern\n * - u_folds, u_foldCount - lines pattern, 15 max\n * - u_drops - metaballs-like pattern\n * - u_seed - applied to folds, crumples and dots\n * - u_fade - big-scale noise mask applied to everything but roughness\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform 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\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\n${declarePI}\n${rotation2}\n${textureRandomizerR}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbm(vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < 3; i++) {\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat roughness(vec2 p) {\n p *= .1;\n float o = 0.;\n for (float i = 0.; ++i < 4.; p *= 2.1) {\n vec4 w = vec4(floor(p), ceil(p));\n vec2 f = fract(p);\n o += mix(\n mix(randomG(w.xy), randomG(w.xw), f.y),\n mix(randomG(w.zy), randomG(w.zw), f.y),\n f.x);\n o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));\n }\n return o / 3.;\n}\n\n${fiberNoise}\n\nvec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n}\nfloat crumpledNoise(vec2 t, float pw) {\n vec2 p = floor(t);\n float wsum = 0.;\n float cl = 0.;\n for (int y = -1; y < 2; y += 1) {\n for (int x = -1; x < 2; x += 1) {\n vec2 b = vec2(float(x), float(y));\n vec2 q = b + p;\n vec2 q2 = q - floor(q / 8.) * 8.;\n vec2 c = q + randomGB(q2);\n vec2 r = c - t;\n float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);\n cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;\n wsum += w;\n }\n }\n return pow(cl / wsum, .5) * 2.;\n}\nfloat crumplesShape(vec2 uv) {\n return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);\n}\n\n\nvec2 folds(vec2 uv) {\n vec3 pp = vec3(0.);\n float l = 9.;\n for (float i = 0.; i < 15.; i++) {\n if (i >= u_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. * pow(fade, 3.), 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"],
|
|
5
|
+
"mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,YAAY,0BAA0B;AAqB9D,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BhD,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2ClB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -12,6 +12,7 @@ export declare const pulsingBorderMeta: {
|
|
|
12
12
|
* - u_colorBack (RGBA)
|
|
13
13
|
* - u_colors (vec4[]), u_colorsCount (float used as integer)
|
|
14
14
|
* - u_roundness, u_thickness, u_softness: border parameters
|
|
15
|
+
* - u_aspectRatio
|
|
15
16
|
* - u_intensity: thickness of individual spots
|
|
16
17
|
* - u_bloom: normal / additive color blending
|
|
17
18
|
* - u_spotSize: angular size of spots
|
|
@@ -29,6 +30,11 @@ export interface PulsingBorderUniforms extends ShaderSizingUniforms {
|
|
|
29
30
|
u_colorsCount: number;
|
|
30
31
|
u_roundness: number;
|
|
31
32
|
u_thickness: number;
|
|
33
|
+
u_marginLeft: number;
|
|
34
|
+
u_marginRight: number;
|
|
35
|
+
u_marginTop: number;
|
|
36
|
+
u_marginBottom: number;
|
|
37
|
+
u_aspectRatio: (typeof PulsingBorderAspectRatios)[PulsingBorderAspectRatio];
|
|
32
38
|
u_softness: number;
|
|
33
39
|
u_intensity: number;
|
|
34
40
|
u_bloom: number;
|
|
@@ -44,6 +50,12 @@ export interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionPar
|
|
|
44
50
|
colors?: string[];
|
|
45
51
|
roundness?: number;
|
|
46
52
|
thickness?: number;
|
|
53
|
+
margin?: number;
|
|
54
|
+
marginLeft?: number;
|
|
55
|
+
marginRight?: number;
|
|
56
|
+
marginTop?: number;
|
|
57
|
+
marginBottom?: number;
|
|
58
|
+
aspectRatio?: PulsingBorderAspectRatio;
|
|
47
59
|
softness?: number;
|
|
48
60
|
intensity?: number;
|
|
49
61
|
bloom?: number;
|
|
@@ -53,3 +65,8 @@ export interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionPar
|
|
|
53
65
|
smoke?: number;
|
|
54
66
|
smokeSize?: number;
|
|
55
67
|
}
|
|
68
|
+
export declare const PulsingBorderAspectRatios: {
|
|
69
|
+
readonly auto: 0;
|
|
70
|
+
readonly square: 1;
|
|
71
|
+
};
|
|
72
|
+
export type PulsingBorderAspectRatio = keyof typeof PulsingBorderAspectRatios;
|
|
@@ -19,6 +19,11 @@ uniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];
|
|
|
19
19
|
uniform float u_colorsCount;
|
|
20
20
|
uniform float u_roundness;
|
|
21
21
|
uniform float u_thickness;
|
|
22
|
+
uniform float u_marginLeft;
|
|
23
|
+
uniform float u_marginRight;
|
|
24
|
+
uniform float u_marginTop;
|
|
25
|
+
uniform float u_marginBottom;
|
|
26
|
+
uniform float u_aspectRatio;
|
|
22
27
|
uniform float u_softness;
|
|
23
28
|
uniform float u_intensity;
|
|
24
29
|
uniform float u_bloom;
|
|
@@ -43,19 +48,23 @@ float beat(float time) {
|
|
|
43
48
|
return clamp(first + 0.6 * second, 0.0, 1.0);
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
float
|
|
47
|
-
|
|
48
|
-
float borderDistance = abs(distance);
|
|
49
|
-
float border = 1. - smoothstep(-u_softness * thickness - 2. * fwidth(borderDistance), .5 * u_softness * thickness, borderDistance - .5 * thickness);
|
|
50
|
-
border = pow(border, 2.);
|
|
51
|
-
|
|
52
|
-
return border;
|
|
51
|
+
float sst(float edge0, float edge1, float x) {
|
|
52
|
+
return smoothstep(edge0, edge1, x);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
float
|
|
55
|
+
float roundedBox(vec2 uv, vec2 halfSize, float distance, float cornerDistance, float thickness, float softness) {
|
|
56
56
|
float borderDistance = abs(distance);
|
|
57
|
-
float
|
|
58
|
-
border
|
|
57
|
+
float aa = 2. * fwidth(distance);
|
|
58
|
+
float border = 1. - sst(mix(thickness, -thickness, softness), thickness + aa, borderDistance);
|
|
59
|
+
float cornerFadeCircles = 0.;
|
|
60
|
+
cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv + halfSize) / thickness)));
|
|
61
|
+
cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(-halfSize.x, halfSize.y)) / thickness)));
|
|
62
|
+
cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(halfSize.x, -halfSize.y)) / thickness)));
|
|
63
|
+
cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - halfSize) / thickness)));
|
|
64
|
+
aa = fwidth(cornerDistance);
|
|
65
|
+
float cornerFade = sst(0., mix(aa, thickness, softness), cornerDistance);
|
|
66
|
+
cornerFade *= cornerFadeCircles;
|
|
67
|
+
border += cornerFade;
|
|
59
68
|
return border;
|
|
60
69
|
}
|
|
61
70
|
|
|
@@ -78,101 +87,86 @@ float valueNoise(vec2 st) {
|
|
|
78
87
|
return mix(x1, x2, u.y);
|
|
79
88
|
}
|
|
80
89
|
|
|
81
|
-
float linearstep(float edge0, float edge1, float x) {
|
|
82
|
-
return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
90
|
void main() {
|
|
86
|
-
|
|
87
|
-
const float firstFrameOffset = 4.;
|
|
91
|
+
const float firstFrameOffset = 109.;
|
|
88
92
|
float t = 1.2 * (u_time + firstFrameOffset);
|
|
89
93
|
|
|
90
94
|
vec2 borderUV = v_responsiveUV;
|
|
91
|
-
|
|
92
|
-
float angle = atan(borderUV.y, borderUV.x) / TWO_PI;
|
|
93
|
-
|
|
94
95
|
float pulse = u_pulse * beat(.18 * u_time);
|
|
95
96
|
|
|
96
|
-
float
|
|
97
|
-
borderUV.x *= borderRatio;
|
|
97
|
+
float canvasRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
|
|
98
98
|
vec2 halfSize = vec2(.5);
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
borderUV.x *= max(canvasRatio, 1.);
|
|
100
|
+
borderUV.y /= min(canvasRatio, 1.);
|
|
101
|
+
halfSize.x *= max(canvasRatio, 1.);
|
|
102
|
+
halfSize.y /= min(canvasRatio, 1.);
|
|
103
|
+
|
|
104
|
+
float mL = u_marginLeft;
|
|
105
|
+
float mR = u_marginRight;
|
|
106
|
+
float mT = u_marginTop;
|
|
107
|
+
float mB = u_marginBottom;
|
|
108
|
+
float mX = mL + mR;
|
|
109
|
+
float mY = mT + mB;
|
|
110
|
+
|
|
111
|
+
if (u_aspectRatio > 0.) {
|
|
112
|
+
float shapeRatio = canvasRatio * (1. - mX) / (1. - mY);
|
|
113
|
+
float freeX = shapeRatio > 1. ? (1. - mX) * (1. - 1. / shapeRatio) : 0.;
|
|
114
|
+
float freeY = shapeRatio < 1. ? (1. - mY) * (1. - shapeRatio) : 0.;
|
|
115
|
+
mL += freeX * 0.5;
|
|
116
|
+
mR += freeX * 0.5;
|
|
117
|
+
mT += freeY * 0.5;
|
|
118
|
+
mB += freeY * 0.5;
|
|
119
|
+
mX = mL + mR;
|
|
120
|
+
mY = mT + mB;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
float thickness = .5 * u_thickness * min(halfSize.x, halfSize.y);
|
|
124
|
+
|
|
125
|
+
halfSize.x *= (1. - mX);
|
|
126
|
+
halfSize.y *= (1. - mY);
|
|
127
|
+
|
|
128
|
+
vec2 centerShift = vec2(
|
|
129
|
+
(mL - mR) * max(canvasRatio, 1.) * 0.5,
|
|
130
|
+
(mB - mT) / min(canvasRatio, 1.) * 0.5
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
borderUV -= centerShift;
|
|
134
|
+
halfSize -= mix(thickness, 0., u_softness);
|
|
135
|
+
|
|
136
|
+
float radius = mix(0., min(halfSize.x, halfSize.y), u_roundness);
|
|
101
137
|
vec2 d = abs(borderUV) - halfSize + radius;
|
|
102
|
-
float outsideDistance = length(max(d,
|
|
103
|
-
float insideDistance = min(max(d.x, d.y),
|
|
138
|
+
float outsideDistance = length(max(d, .0001)) - radius;
|
|
139
|
+
float insideDistance = min(max(d.x, d.y), .0001);
|
|
140
|
+
float cornerDistance = abs(min(max(d.x, d.y) - .45 * radius, .0));
|
|
104
141
|
float distance = outsideDistance + insideDistance;
|
|
105
142
|
|
|
106
|
-
float
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);
|
|
110
|
-
vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);
|
|
111
|
-
vec2 v3 = borderUV - halfSize;
|
|
112
|
-
|
|
113
|
-
float cornerFade = 1. - abs(v0.x - v0.y);
|
|
114
|
-
cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));
|
|
115
|
-
cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));
|
|
116
|
-
cornerFade = max(cornerFade, 1. - abs(v3.x - v3.y));
|
|
117
|
-
cornerFade = .75 * pow(cornerFade, 20.);
|
|
118
|
-
|
|
119
|
-
float cornerFadeMask = 0.;
|
|
120
|
-
float maskR = (.35 * u_thickness - .25 * radius);
|
|
121
|
-
float maskHL = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, borderUV.x);
|
|
122
|
-
float maskHR = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, -borderUV.x);
|
|
123
|
-
float maskVT = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, -borderUV.y);
|
|
124
|
-
float maskVB = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, borderUV.y);
|
|
125
|
-
float maskOffset = .25 * (u_thickness + radius);
|
|
126
|
-
{
|
|
127
|
-
float m = maskHR;
|
|
128
|
-
m *= maskVT;
|
|
129
|
-
m *= (1. - clamp(length((v0 - maskOffset) / maskR), 0., 1.));
|
|
130
|
-
cornerFadeMask += m;
|
|
131
|
-
}
|
|
132
|
-
{
|
|
133
|
-
float m = maskHR;
|
|
134
|
-
m *= maskVB;
|
|
135
|
-
m *= (1. - clamp(length((v1 - vec2(1., -1.) * maskOffset) / maskR), 0., 1.));
|
|
136
|
-
cornerFadeMask += m;
|
|
137
|
-
}
|
|
138
|
-
{
|
|
139
|
-
float m = maskHL;
|
|
140
|
-
m *= maskVT;
|
|
141
|
-
m *= (1. - clamp(length((v2 - vec2(-1., 1.) * maskOffset) / maskR), 0., 1.));
|
|
142
|
-
cornerFadeMask += m;
|
|
143
|
-
}
|
|
144
|
-
{
|
|
145
|
-
float m = maskHL;
|
|
146
|
-
m *= maskVB;
|
|
147
|
-
m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));
|
|
148
|
-
cornerFadeMask += m;
|
|
149
|
-
}
|
|
150
|
-
cornerFade = clamp(cornerFade, 0., 1.);
|
|
151
|
-
cornerFade *= cornerFadeMask;
|
|
152
|
-
border += cornerFade;
|
|
143
|
+
float borderThickness = mix(thickness, 3. * thickness, u_softness);
|
|
144
|
+
float border = roundedBox(borderUV, halfSize, distance, cornerDistance, borderThickness, u_softness);
|
|
145
|
+
border = pow(border, 1. + u_softness);
|
|
153
146
|
|
|
154
|
-
vec2 smokeUV = .
|
|
147
|
+
vec2 smokeUV = .3 * u_smokeSize * v_patternUV;
|
|
155
148
|
float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);
|
|
156
149
|
smoke -= valueNoise(3.4 * smokeUV - .5 * t);
|
|
157
|
-
|
|
150
|
+
float smokeThickness = thickness + .2;
|
|
151
|
+
smokeThickness = min(.4, max(smokeThickness, .1));
|
|
152
|
+
smoke *= roundedBox(borderUV, halfSize, distance, cornerDistance, smokeThickness, 1.);
|
|
158
153
|
smoke = 30. * pow(smoke, 2.);
|
|
159
|
-
smoke
|
|
160
|
-
smoke *= u_smoke;
|
|
154
|
+
smoke *= mix(0., .5, pow(u_smoke, 2.));
|
|
161
155
|
smoke *= mix(1., pulse, u_pulse);
|
|
162
156
|
smoke = clamp(smoke, 0., 1.);
|
|
163
|
-
|
|
164
157
|
border += smoke;
|
|
165
|
-
|
|
166
|
-
border *= borderBounds;
|
|
158
|
+
|
|
167
159
|
border = clamp(border, 0., 1.);
|
|
168
160
|
|
|
169
161
|
vec3 blendColor = vec3(0.);
|
|
170
|
-
float blendAlpha = 0
|
|
162
|
+
float blendAlpha = 0.;
|
|
171
163
|
vec3 addColor = vec3(0.);
|
|
172
|
-
float addAlpha = 0
|
|
164
|
+
float addAlpha = 0.;
|
|
173
165
|
|
|
174
166
|
float bloom = 4. * u_bloom;
|
|
175
|
-
float intensity = 1. + 4. * u_intensity;
|
|
167
|
+
float intensity = 1. + (1. + 4. * u_softness) * u_intensity;
|
|
168
|
+
|
|
169
|
+
float angle = atan(borderUV.y, borderUV.x) / TWO_PI;
|
|
176
170
|
|
|
177
171
|
for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {
|
|
178
172
|
if (colorIdx >= int(u_colorsCount)) break;
|
|
@@ -202,7 +196,7 @@ void main() {
|
|
|
202
196
|
float atg1 = fract(angle + time);
|
|
203
197
|
float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;
|
|
204
198
|
spotSize = mix(spotSize, .1, p);
|
|
205
|
-
float sector =
|
|
199
|
+
float sector = sst(.5 - spotSize, .5, atg1) * sst(.5 + spotSize, .5, atg1);
|
|
206
200
|
|
|
207
201
|
sector *= mask;
|
|
208
202
|
sector *= border;
|
|
@@ -231,7 +225,12 @@ void main() {
|
|
|
231
225
|
|
|
232
226
|
fragColor = vec4(color, opacity);
|
|
233
227
|
}`;
|
|
228
|
+
const PulsingBorderAspectRatios = {
|
|
229
|
+
auto: 0,
|
|
230
|
+
square: 1
|
|
231
|
+
};
|
|
234
232
|
export {
|
|
233
|
+
PulsingBorderAspectRatios,
|
|
235
234
|
pulsingBorderFragmentShader,
|
|
236
235
|
pulsingBorderMeta
|
|
237
236
|
};
|