@paper-design/shaders-react 0.0.4 → 0.0.5
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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -79
- package/dist/index.js.map +4 -4
- package/dist/shader-mount.d.ts +1 -0
- package/dist/shader-mount.d.ts.map +1 -0
- package/dist/shaders/grain-clouds.d.ts +1 -0
- package/dist/shaders/grain-clouds.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,80 +1,2 @@
|
|
|
1
|
-
import{useEffect as
|
|
2
|
-
attribute vec4 a_position;
|
|
3
|
-
void main() {
|
|
4
|
-
gl_Position = a_position;
|
|
5
|
-
}
|
|
6
|
-
`;function x(e,t,r){let i=e.createShader(t);return i?(e.shaderSource(i,r),e.compileShader(i),e.getShaderParameter(i,e.COMPILE_STATUS)?i:(console.error("An error occurred compiling the shaders: "+e.getShaderInfoLog(i)),e.deleteShader(i),null)):null}function R(e,t,r){let i=x(e,e.VERTEX_SHADER,t),o=x(e,e.FRAGMENT_SHADER,r);if(!i||!o)return null;let s=e.createProgram();return s?(e.attachShader(s,i),e.attachShader(s,o),e.linkProgram(s),e.getProgramParameter(s,e.LINK_STATUS)?(e.detachShader(s,i),e.detachShader(s,o),e.deleteShader(i),e.deleteShader(o),s):(console.error("Unable to initialize the shader program: "+e.getProgramInfoLog(s)),e.deleteProgram(s),e.deleteShader(i),e.deleteShader(o),null)):null}function y(e){let t,r,i;if(e.startsWith("#"))[t,r,i]=C(e);else if(e.startsWith("rgb"))[t,r,i]=F(e);else if(e.startsWith("hsl"))[t,r,i]=E(U(e));else return console.error("Unsupported color format"),[0,0,0];return[t,r,i]}function C(e){let t=parseInt(e.slice(1),16),r=(t>>16&255)/255,i=(t>>8&255)/255,o=(t&255)/255;return[r,i,o]}function F(e){let t=e.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i);return t?[parseInt(t[1]??"0")/255,parseInt(t[2]??"0")/255,parseInt(t[3]??"0")/255]:[0,0,0]}function U(e){let t=e.match(/^hsl\s*\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$/i);return t?[parseInt(t[1]??"0"),parseInt(t[2]??"0"),parseInt(t[3]??"0")]:[0,0,0]}function E(e){let[t,r,i]=e,o=t/360,s=r/100,a=i/100,n,m,c;if(r===0)n=m=c=a;else{let d=(h,g,l)=>(l<0&&(l+=1),l>1&&(l-=1),l<.16666666666666666?h+(g-h)*6*l:l<.5?g:l<.6666666666666666?h+(g-h)*(.6666666666666666-l)*6:h),u=a<.5?a*(1+s):a+s-a*s,f=2*a-u;n=d(f,u,o+1/3),m=d(f,u,o),c=d(f,u,o-1/3)}return[n,m,c]}var S=`
|
|
7
|
-
precision highp float;
|
|
8
|
-
uniform vec2 u_resolution;
|
|
9
|
-
uniform float u_time;
|
|
10
|
-
uniform vec3 u_color1;
|
|
11
|
-
uniform vec3 u_color2;
|
|
12
|
-
uniform float u_noiseScale;
|
|
13
|
-
uniform float u_noiseSpeed;
|
|
14
|
-
uniform float u_grainAmount;
|
|
15
|
-
|
|
16
|
-
// Simplex 2D noise
|
|
17
|
-
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
|
|
18
|
-
|
|
19
|
-
float snoise(vec2 v) {
|
|
20
|
-
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
|
|
21
|
-
-0.577350269189626, 0.024390243902439);
|
|
22
|
-
vec2 i = floor(v + dot(v, C.yy));
|
|
23
|
-
vec2 x0 = v - i + dot(i, C.xx);
|
|
24
|
-
vec2 i1;
|
|
25
|
-
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
|
26
|
-
vec4 x12 = x0.xyxy + C.xxzz;
|
|
27
|
-
x12.xy -= i1;
|
|
28
|
-
i = mod(i, 289.0);
|
|
29
|
-
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0))
|
|
30
|
-
+ i.x + vec3(0.0, i1.x, 1.0));
|
|
31
|
-
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
|
|
32
|
-
dot(x12.zw,x12.zw)), 0.0);
|
|
33
|
-
m = m*m ;
|
|
34
|
-
m = m*m ;
|
|
35
|
-
vec3 x = 2.0 * fract(p * C.www) - 1.0;
|
|
36
|
-
vec3 h = abs(x) - 0.5;
|
|
37
|
-
vec3 ox = floor(x + 0.5);
|
|
38
|
-
vec3 a0 = x - ox;
|
|
39
|
-
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
|
|
40
|
-
vec3 g;
|
|
41
|
-
g.x = a0.x * x0.x + h.x * x0.y;
|
|
42
|
-
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
|
|
43
|
-
return 130.0 * dot(m, g);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
void main() {
|
|
47
|
-
vec2 st = gl_FragCoord.xy / u_resolution.xy;
|
|
48
|
-
|
|
49
|
-
// Calculate the aspect ratio of the shader
|
|
50
|
-
float shaderAspect = u_resolution.x / u_resolution.y;
|
|
51
|
-
|
|
52
|
-
// Define the aspect ratio of your content (e.g., 1.0 for square)
|
|
53
|
-
float contentAspect = 1.0;
|
|
54
|
-
|
|
55
|
-
// Adjust st to maintain content aspect ratio
|
|
56
|
-
if (shaderAspect > contentAspect) {
|
|
57
|
-
float scale = shaderAspect / contentAspect;
|
|
58
|
-
st.x = (st.x - 0.5) * scale + 0.5;
|
|
59
|
-
} else {
|
|
60
|
-
float scale = contentAspect / shaderAspect;
|
|
61
|
-
st.y = (st.y - 0.5) * scale + 0.5;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Create blobby texture
|
|
65
|
-
float n = snoise(st * u_noiseScale + u_time * u_noiseSpeed);
|
|
66
|
-
n += 0.5 * snoise(st * u_noiseScale * 2.0 - u_time * u_noiseSpeed * 0.5);
|
|
67
|
-
n += 0.25 * snoise(st * u_noiseScale * 4.0 + u_time * u_noiseSpeed * 0.25);
|
|
68
|
-
n = n * 0.5 + 0.5;
|
|
69
|
-
|
|
70
|
-
// Color interpolation
|
|
71
|
-
vec3 color = mix(u_color1, u_color2, n);
|
|
72
|
-
|
|
73
|
-
// Add grain
|
|
74
|
-
float grain = fract(sin(dot(st * 1000.0, vec2(12.9898, 78.233))) * 43758.5453);
|
|
75
|
-
color += (grain - 0.5) * u_grainAmount;
|
|
76
|
-
|
|
77
|
-
gl_FragColor = vec4(color, 1.0);
|
|
78
|
-
}
|
|
79
|
-
`;import{jsx as w}from"react/jsx-runtime";var v=({ref:e,fragmentShader:t,style:r,uniforms:i={},webGlContextAttributes:o,animated:s=!0})=>{let a=e??b(null),n=b(null);return p(()=>(a.current&&(n.current=new A(a.current,t,i,o,s)),()=>{n.current&&n.current.dispose()}),[t,o]),p(()=>{n.current&&n.current.setUniforms(i)},[i]),p(()=>{n.current&&(s?n.current.startAnimating():n.current.stopAnimating())},[s]),w("canvas",{ref:a,style:r})};import{jsx as P}from"react/jsx-runtime";var L=e=>P(v,{...e,fragmentShader:S});export{L as GrainClouds,v as ShaderMount,y as getShaderColorFromString};
|
|
1
|
+
import{useEffect as a,useRef as f}from"react";import{ShaderMount as d}from"@paper-design/shaders";import{jsx as m}from"react/jsx-runtime";var s=({ref:e,fragmentShader:u,style:l,uniforms:t={},webGlContextAttributes:i,animated:n=!0})=>{let o=e??f(null),r=f(null);return a(()=>(o.current&&(r.current=new d(o.current,u,t,i,n)),()=>{r.current&&r.current.dispose()}),[u,i]),a(()=>{r.current&&r.current.setUniforms(t)},[t]),a(()=>{r.current&&(n?r.current.startAnimating():r.current.stopAnimating())},[n]),m("canvas",{ref:o,style:l})};import{grainCloudsFragmentShader as p}from"@paper-design/shaders";import{jsx as S}from"react/jsx-runtime";var c=e=>S(s,{...e,fragmentShader:p});import{getShaderColorFromString as E}from"@paper-design/shaders";export{c as GrainClouds,s as ShaderMount,E as getShaderColorFromString};
|
|
80
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/shader-mount.tsx", "
|
|
4
|
-
"sourcesContent": ["import React, { useEffect, useRef } from 'react';\nimport { ShaderMount as ShaderMountVanilla } from '@paper-design/shaders';\n\nexport interface ShaderMountProps {\n ref?: React.RefObject<HTMLCanvasElement>;\n fragmentShader: string;\n style?: React.CSSProperties;\n uniforms?: Record<string, number | number[]>;\n webGlContextAttributes?: WebGLContextAttributes;\n animated?: boolean;\n}\n\nexport const ShaderMount: React.FC<ShaderMountProps> = ({\n ref,\n fragmentShader,\n style,\n uniforms = {},\n webGlContextAttributes,\n animated = true,\n}) => {\n const canvasRef = ref ?? useRef<HTMLCanvasElement>(null);\n const shaderMountRef = useRef<ShaderMountVanilla | null>(null);\n\n useEffect(() => {\n if (canvasRef.current) {\n shaderMountRef.current = new ShaderMountVanilla(\n canvasRef.current,\n fragmentShader,\n uniforms,\n webGlContextAttributes,\n animated\n );\n }\n\n return () => {\n if (shaderMountRef.current) {\n shaderMountRef.current.dispose();\n }\n };\n }, [fragmentShader, webGlContextAttributes]);\n\n useEffect(() => {\n if (shaderMountRef.current) {\n shaderMountRef.current.setUniforms(uniforms);\n }\n }, [uniforms]);\n\n useEffect(() => {\n if (shaderMountRef.current) {\n if (animated) {\n shaderMountRef.current.startAnimating();\n } else {\n shaderMountRef.current.stopAnimating();\n }\n }\n }, [animated]);\n\n return <canvas ref={canvasRef} style={style} />;\n};\n", "export class ShaderMount {\n private canvas: HTMLCanvasElement;\n private gl: WebGLRenderingContext;\n private program: WebGLProgram | null = null;\n private uniformLocations: Record<string, WebGLUniformLocation | null> = {};\n /** The fragment shader that we are using */\n private fragmentShader: string;\n /** Stores the RAF for the render loop */\n private rafId: number | null = null;\n /** Time of the last rendered frame */\n private lastFrameTime = 0;\n /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */\n private totalAnimationTime = 0;\n /** Whether we RAF the render or not */\n private isAnimated: boolean;\n /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */\n private providedUniforms: Record<string, number | number[]>;\n /** Just a sanity check to make sure frames don't run after we're disposed */\n private hasBeenDisposed = false;\n /** If the resolution of the canvas has changed since the last render */\n private resolutionChanged = true;\n\n constructor(\n canvas: HTMLCanvasElement,\n fragmentShader: string,\n uniforms: Record<string, number | number[]> = {},\n webGlContextAttributes?: WebGLContextAttributes,\n animated = true\n ) {\n this.canvas = canvas;\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n this.isAnimated = animated;\n\n const gl = canvas.getContext('webgl', webGlContextAttributes);\n if (!gl) {\n throw new Error('WebGL not supported');\n }\n this.gl = gl;\n\n this.initWebGL();\n this.setupResizeObserver();\n if (this.isAnimated) {\n this.startAnimating();\n } else {\n this.render(performance.now());\n }\n }\n\n private initWebGL = () => {\n const program = createProgram(\n this.gl,\n vertexShaderSource,\n this.fragmentShader\n );\n if (!program) return;\n this.program = program;\n\n this.setupPositionAttribute();\n this.setupUniforms();\n };\n\n private setupPositionAttribute = () => {\n const positionAttributeLocation = this.gl.getAttribLocation(\n this.program!,\n 'a_position'\n );\n const positionBuffer = this.gl.createBuffer();\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);\n const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];\n this.gl.bufferData(\n this.gl.ARRAY_BUFFER,\n new Float32Array(positions),\n this.gl.STATIC_DRAW\n );\n this.gl.enableVertexAttribArray(positionAttributeLocation);\n this.gl.vertexAttribPointer(\n positionAttributeLocation,\n 2,\n this.gl.FLOAT,\n false,\n 0,\n 0\n );\n };\n\n private setupUniforms = () => {\n this.uniformLocations = {\n u_time: this.gl.getUniformLocation(this.program!, 'u_time'),\n u_resolution: this.gl.getUniformLocation(this.program!, 'u_resolution'),\n ...Object.fromEntries(\n Object.keys(this.providedUniforms).map((key) => [\n key,\n this.gl.getUniformLocation(this.program!, key),\n ])\n ),\n };\n };\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(() => this.handleResize());\n this.resizeObserver.observe(this.canvas);\n this.handleResize();\n };\n\n private handleResize = () => {\n const newWidth = this.canvas.clientWidth;\n const newHeight = this.canvas.clientHeight;\n if (this.canvas.width !== newWidth || this.canvas.height !== newHeight) {\n this.canvas.width = newWidth;\n this.canvas.height = newHeight;\n this.resolutionChanged = true;\n this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);\n this.render(performance.now());\n }\n };\n\n private render = (currentTime: number) => {\n if (this.hasBeenDisposed) return;\n\n const dt = currentTime - this.lastFrameTime;\n this.lastFrameTime = currentTime;\n\n if (this.isAnimated) {\n this.totalAnimationTime += dt;\n }\n\n this.gl.useProgram(this.program);\n\n // Update the time uniform\n this.gl.uniform1f(\n this.uniformLocations.u_time!,\n this.totalAnimationTime * 0.001\n );\n // If the resolution has changed, we need to update the uniform\n if (this.resolutionChanged) {\n this.gl.uniform2f(\n this.uniformLocations.u_resolution!,\n this.gl.canvas.width,\n this.gl.canvas.height\n );\n this.resolutionChanged = false;\n }\n\n this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n // Loop if we're animating\n\n if (this.isAnimated) {\n this.requestRender();\n } else {\n this.rafId = null;\n }\n };\n\n private requestRender = () => {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n }\n this.rafId = requestAnimationFrame(this.render);\n };\n\n private updateProvidedUniforms = () => {\n this.gl.useProgram(this.program);\n Object.entries(this.providedUniforms).forEach(([key, value]) => {\n const location = this.uniformLocations[key];\n if (location) {\n if (Array.isArray(value)) {\n switch (value.length) {\n case 2:\n this.gl.uniform2fv(location, value);\n break;\n case 3:\n this.gl.uniform3fv(location, value);\n break;\n case 4:\n this.gl.uniform4fv(location, value);\n break;\n default:\n if (value.length === 9) {\n this.gl.uniformMatrix3fv(location, false, value);\n } else if (value.length === 16) {\n this.gl.uniformMatrix4fv(location, false, value);\n } else {\n console.warn(\n `Unsupported uniform array length: ${value.length}`\n );\n }\n }\n } else if (typeof value === 'number') {\n this.gl.uniform1f(location, value);\n } else if (typeof value === 'boolean') {\n this.gl.uniform1i(location, value ? 1 : 0);\n } else {\n console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);\n }\n }\n });\n };\n\n /** Start the animation loop, can be called during instantiation or later by an outside source */\n public startAnimating = () => {\n this.isAnimated = true;\n this.lastFrameTime = performance.now();\n this.rafId = requestAnimationFrame(this.render);\n };\n\n /** Stop the animation loop */\n public stopAnimating = () => {\n this.isAnimated = false;\n if (this.rafId) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n };\n\n /** Update the uniforms that are provided by the outside shader */\n public setUniforms = (newUniforms: Record<string, number | number[]>) => {\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\n // If we need to allow users to add uniforms after the shader has been created, we can do that here\n // But right now we're expecting the uniform list to be predictable and static\n // this.setupUniforms();\n\n this.updateProvidedUniforms();\n this.render(performance.now());\n };\n\n /** Dispose of the shader mount, cleaning up all of the WebGL resources */\n public dispose = () => {\n this.hasBeenDisposed = true;\n this.stopAnimating();\n if (this.gl && this.program) {\n this.gl.deleteProgram(this.program);\n this.program = null;\n\n // Reset the WebGL context\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);\n this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);\n this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);\n\n // Clear any errors\n this.gl.getError();\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n this.uniformLocations = {};\n };\n}\n\n/** Vertex shader for the shader mount */\nconst vertexShaderSource = `\n attribute vec4 a_position;\n void main() {\n gl_Position = a_position;\n }\n`;\n\nfunction createShader(\n gl: WebGLRenderingContext,\n type: number,\n source: string\n): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error(\n 'An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)\n );\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\nfunction createProgram(\n gl: WebGLRenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);\n const fragmentShader = createShader(\n gl,\n gl.FRAGMENT_SHADER,\n fragmentShaderSource\n );\n\n if (!vertexShader || !fragmentShader) return null;\n\n const program = gl.createProgram();\n if (!program) return null;\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.error(\n 'Unable to initialize the shader program: ' +\n gl.getProgramInfoLog(program)\n );\n gl.deleteProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return null;\n }\n\n // Clean up shaders after successful linking\n gl.detachShader(program, vertexShader);\n gl.detachShader(program, fragmentShader);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n return program;\n}\n\n/** Convert color string from HSL, RGB, or hex to 0-to-1-range-RGB array */\nexport function getShaderColorFromString(\n colorString: string\n): [number, number, number] {\n let r: number, g: number, b: number;\n if (colorString.startsWith('#')) {\n [r, g, b] = hexToRgb(colorString);\n } else if (colorString.startsWith('rgb')) {\n [r, g, b] = parseRgb(colorString);\n } else if (colorString.startsWith('hsl')) {\n [r, g, b] = hslToRgb(parseHsl(colorString));\n } else {\n console.error('Unsupported color format');\n return [0, 0, 0];\n }\n return [r, g, b];\n}\n\n/** Convert hex to RGB (0 to 1 range) */\nfunction hexToRgb(hex: string): [number, number, number] {\n const bigint = parseInt(hex.slice(1), 16);\n const r = ((bigint >> 16) & 255) / 255;\n const g = ((bigint >> 8) & 255) / 255;\n const b = (bigint & 255) / 255;\n return [r, g, b];\n}\n\n/** Parse RGB string to RGB (0 to 1 range) */\nfunction parseRgb(rgb: string): [number, number, number] {\n const match = rgb.match(/^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i);\n if (!match) return [0, 0, 0];\n return [\n parseInt(match[1] ?? '0') / 255,\n parseInt(match[2] ?? '0') / 255,\n parseInt(match[3] ?? '0') / 255,\n ];\n}\n\n/** Parse HSL string */\nfunction parseHsl(hsl: string): [number, number, number] {\n const match = hsl.match(/^hsl\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*\\)$/i);\n if (!match) return [0, 0, 0];\n return [\n parseInt(match[1] ?? '0'),\n parseInt(match[2] ?? '0'),\n parseInt(match[3] ?? '0'),\n ];\n}\n\n/** Convert HSL to RGB (0 to 1 range) */\nfunction hslToRgb(hsl: [number, number, number]): [number, number, number] {\n const [h, s, l] = hsl;\n const hDecimal = h / 360;\n const sDecimal = s / 100;\n const lDecimal = l / 100;\n let r, g, b;\n\n if (s === 0) {\n r = g = b = lDecimal; // achromatic\n } else {\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n const q =\n lDecimal < 0.5\n ? lDecimal * (1 + sDecimal)\n : lDecimal + sDecimal - lDecimal * sDecimal;\n const p = 2 * lDecimal - q;\n r = hue2rgb(p, q, hDecimal + 1 / 3);\n g = hue2rgb(p, q, hDecimal);\n b = hue2rgb(p, q, hDecimal - 1 / 3);\n }\n\n return [r, g, b];\n}\n", "/**\n * Renders a grainy texture over top of blobby animated clouds\n * This is an example shader that we're using to bootstrap the project\n * Generated by Claude 3.5 Sonnet\n *\n * Parameters include:\n * color1: The first color of the clouds\n * color2: The second color of the clouds\n * noiseScale: The scale of the noise\n * noiseSpeed: The speed of the noise\n * grainAmount: The amount of grain on the texture\n */\n\nexport type GrainCloudsUniforms = {\n color1: [number, number, number];\n color2: [number, number, number];\n noiseScale: number;\n noiseSpeed: number;\n grainAmount: number;\n};\n\nexport const grainCloudsFragmentShader = `\n precision highp float;\n uniform vec2 u_resolution;\n uniform float u_time;\n uniform vec3 u_color1;\n uniform vec3 u_color2;\n uniform float u_noiseScale;\n uniform float u_noiseSpeed;\n uniform float u_grainAmount;\n\n // Simplex 2D noise\n vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n\n float snoise(vec2 v) {\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0));\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),\n dot(x12.zw,x12.zw)), 0.0);\n m = m*m ;\n m = m*m ;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n }\n\n void main() {\n vec2 st = gl_FragCoord.xy / u_resolution.xy;\n\n // Calculate the aspect ratio of the shader\n float shaderAspect = u_resolution.x / u_resolution.y;\n\n // Define the aspect ratio of your content (e.g., 1.0 for square)\n float contentAspect = 1.0;\n\n // Adjust st to maintain content aspect ratio\n if (shaderAspect > contentAspect) {\n float scale = shaderAspect / contentAspect;\n st.x = (st.x - 0.5) * scale + 0.5;\n } else {\n float scale = contentAspect / shaderAspect;\n st.y = (st.y - 0.5) * scale + 0.5;\n }\n\n // Create blobby texture\n float n = snoise(st * u_noiseScale + u_time * u_noiseSpeed);\n n += 0.5 * snoise(st * u_noiseScale * 2.0 - u_time * u_noiseSpeed * 0.5);\n n += 0.25 * snoise(st * u_noiseScale * 4.0 + u_time * u_noiseSpeed * 0.25);\n n = n * 0.5 + 0.5;\n\n // Color interpolation\n vec3 color = mix(u_color1, u_color2, n);\n\n // Add grain\n float grain = fract(sin(dot(st * 1000.0, vec2(12.9898, 78.233))) * 43758.5453);\n color += (grain - 0.5) * u_grainAmount;\n\n gl_FragColor = vec4(color, 1.0);\n }\n`;\n", "import { ShaderMount, type ShaderMountProps } from '../shader-mount';\nimport {\n grainCloudsFragmentShader,\n type GrainCloudsUniforms,\n} from '@paper-design/shaders';\n\ntype GrainCloudsProps = Omit<ShaderMountProps, 'fragmentShader'> & {\n uniforms: GrainCloudsUniforms;\n};\n\nexport const GrainClouds = (props: GrainCloudsProps) => {\n return <ShaderMount {...props} fragmentShader={grainCloudsFragmentShader} />;\n};\n"],
|
|
5
|
-
"mappings": "AAAA,OAAgB,aAAAA,EAAW,UAAAC,MAAc,
|
|
6
|
-
"names": ["useEffect", "useRef", "
|
|
3
|
+
"sources": ["../src/shader-mount.tsx", "../src/shaders/grain-clouds.tsx", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import React, { useEffect, useRef } from 'react';\nimport { ShaderMount as ShaderMountVanilla } from '@paper-design/shaders';\n\nexport interface ShaderMountProps {\n ref?: React.RefObject<HTMLCanvasElement>;\n fragmentShader: string;\n style?: React.CSSProperties;\n uniforms?: Record<string, number | number[]>;\n webGlContextAttributes?: WebGLContextAttributes;\n animated?: boolean;\n}\n\nexport const ShaderMount: React.FC<ShaderMountProps> = ({\n ref,\n fragmentShader,\n style,\n uniforms = {},\n webGlContextAttributes,\n animated = true,\n}) => {\n const canvasRef = ref ?? useRef<HTMLCanvasElement>(null);\n const shaderMountRef = useRef<ShaderMountVanilla | null>(null);\n\n useEffect(() => {\n if (canvasRef.current) {\n shaderMountRef.current = new ShaderMountVanilla(\n canvasRef.current,\n fragmentShader,\n uniforms,\n webGlContextAttributes,\n animated\n );\n }\n\n return () => {\n if (shaderMountRef.current) {\n shaderMountRef.current.dispose();\n }\n };\n }, [fragmentShader, webGlContextAttributes]);\n\n useEffect(() => {\n if (shaderMountRef.current) {\n shaderMountRef.current.setUniforms(uniforms);\n }\n }, [uniforms]);\n\n useEffect(() => {\n if (shaderMountRef.current) {\n if (animated) {\n shaderMountRef.current.startAnimating();\n } else {\n shaderMountRef.current.stopAnimating();\n }\n }\n }, [animated]);\n\n return <canvas ref={canvasRef} style={style} />;\n};\n", "import { ShaderMount, type ShaderMountProps } from '../shader-mount';\nimport {\n grainCloudsFragmentShader,\n type GrainCloudsUniforms,\n} from '@paper-design/shaders';\n\ntype GrainCloudsProps = Omit<ShaderMountProps, 'fragmentShader'> & {\n uniforms: GrainCloudsUniforms;\n};\n\nexport const GrainClouds = (props: GrainCloudsProps) => {\n return <ShaderMount {...props} fragmentShader={grainCloudsFragmentShader} />;\n};\n", "// ----- ShaderMount ----- //\nexport { ShaderMount } from './shader-mount';\n\n// ----- Fragment shaders ----- //\nexport { GrainClouds } from './shaders/grain-clouds';\nexport { type GrainCloudsUniforms } from '@paper-design/shaders';\n\n// ----- Uniform conversion utils ----- //\nexport { getShaderColorFromString } from '@paper-design/shaders';\n"],
|
|
5
|
+
"mappings": "AAAA,OAAgB,aAAAA,EAAW,UAAAC,MAAc,QACzC,OAAS,eAAeC,MAA0B,wBAwDzC,cAAAC,MAAA,oBA7CF,IAAMC,EAA0C,CAAC,CACtD,IAAAC,EACA,eAAAC,EACA,MAAAC,EACA,SAAAC,EAAW,CAAC,EACZ,uBAAAC,EACA,SAAAC,EAAW,EACb,IAAM,CACJ,IAAMC,EAAYN,GAAOJ,EAA0B,IAAI,EACjDW,EAAiBX,EAAkC,IAAI,EAE7D,OAAAD,EAAU,KACJW,EAAU,UACZC,EAAe,QAAU,IAAIV,EAC3BS,EAAU,QACVL,EACAE,EACAC,EACAC,CACF,GAGK,IAAM,CACPE,EAAe,SACjBA,EAAe,QAAQ,QAAQ,CAEnC,GACC,CAACN,EAAgBG,CAAsB,CAAC,EAE3CT,EAAU,IAAM,CACVY,EAAe,SACjBA,EAAe,QAAQ,YAAYJ,CAAQ,CAE/C,EAAG,CAACA,CAAQ,CAAC,EAEbR,EAAU,IAAM,CACVY,EAAe,UACbF,EACFE,EAAe,QAAQ,eAAe,EAEtCA,EAAe,QAAQ,cAAc,EAG3C,EAAG,CAACF,CAAQ,CAAC,EAENP,EAAC,UAAO,IAAKQ,EAAW,MAAOJ,EAAO,CAC/C,ECzDA,OACE,6BAAAM,MAEK,wBAOE,cAAAC,MAAA,oBADF,IAAMC,EAAeC,GACnBF,EAACG,EAAA,CAAa,GAAGD,EAAO,eAAgBH,EAA2B,ECH5E,OAAS,4BAAAK,MAAgC",
|
|
6
|
+
"names": ["useEffect", "useRef", "ShaderMountVanilla", "jsx", "ShaderMount", "ref", "fragmentShader", "style", "uniforms", "webGlContextAttributes", "animated", "canvasRef", "shaderMountRef", "grainCloudsFragmentShader", "jsx", "GrainClouds", "props", "ShaderMount", "getShaderColorFromString"]
|
|
7
7
|
}
|
package/dist/shader-mount.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shader-mount.d.ts","sourceRoot":"","sources":["../src/shader-mount.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC7C,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA8ClD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grain-clouds.d.ts","sourceRoot":"","sources":["../../src/shaders/grain-clouds.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAE/B,KAAK,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,GAAG;IACjE,QAAQ,EAAE,mBAAmB,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,WAAW,UAAW,gBAAgB,4CAElD,CAAC"}
|