Support React.js
- WebGL
- WebGPU
- TSL (TypeScript Shading Language)
Live Editor
function Canvas() { const gl = useGL({ frag: ` #version 300 es precision mediump float; uniform vec2 iResolution; uniform float iTime; uniform float ellipseRadius; uniform float ellipseXCoord; uniform float ellipseYCoord; uniform float ellipseStroke; out vec4 fragColor; #define PI 3.141592 mat2 rotate(float x, float y, float angle) { mat2 scale = mat2(1.0 / x, 0.0, 0.0, 1.0 / y); mat2 rotation = mat2(cos(angle), -sin(angle), sin(angle), cos(angle)); return scale * rotation; } float circle(vec2 p) { return length(p) - ellipseRadius; } float ellipse(vec2 p, float angle) { mat2 transform = rotate(ellipseXCoord, ellipseYCoord, angle); return circle(transform * p); } float onion(float d, vec2 p, float angle) { return min(d, abs(ellipse(p, angle)) - ellipseStroke); } void main() { vec2 uv = fract(gl_FragCoord.xy / iResolution); vec2 p = uv * 2.4 - 1.2; p.x *= iResolution.x / iResolution.y; float d = circle(p); d = onion(d, p, PI / 2.0 + iTime); d = onion(d, p, PI / 6.0 + iTime); d = onion(d, p, -PI / 6.0 + iTime); if (d < 0.0) { fragColor = vec4(96.0 / 255.0, 219.0 / 255.0, 251.0 / 255.0, 0.8); } } `, resize() { resize(gl) }, }) gl.uniform( useControls({ ellipseRadius: { min: 0, value: 0.2, max: 0.4 }, ellipseXCoord: { min: 0, value: 2.2, max: 4.4 }, ellipseYCoord: { min: 0, value: 5.4, max: 10.8 }, ellipseStroke: { min: 0, value: 0.01, max: 0.02 }, }) ) return <canvas ref={gl.ref} /> }
Result
Loading...
Live Editor
function Canvas() { const gl = useGL({ frag: ` @group(0) @binding(0) var<uniform> iResolution: vec2f; @group(0) @binding(2) var<uniform> iTime: f32; @group(0) @binding(3) var<uniform> ellipseRadius: f32; @group(0) @binding(4) var<uniform> ellipseXCoord: f32; @group(0) @binding(5) var<uniform> ellipseYCoord: f32; @group(0) @binding(6) var<uniform> ellipseStroke: f32; const PI: f32 = 3.141592; fn rotate(x: f32, y: f32, angle: f32) -> mat2x2<f32> { let scale = mat2x2<f32>(1.0 / x, 0.0, 0.0, 1.0 / y); let rotation = mat2x2<f32>(cos(angle), -sin(angle), sin(angle), cos(angle)); return scale * rotation; } fn circle(p: vec2<f32>) -> f32 { return length(p) - ellipseRadius; } fn ellipse(p: vec2<f32>, angle: f32) -> f32 { let transform = rotate(ellipseXCoord, ellipseYCoord, angle); return circle(transform * p); } fn onion(d: f32, p: vec2<f32>, angle: f32) -> f32 { return min(d, abs(ellipse(p, angle)) - ellipseStroke); } @fragment fn main(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> { let uv = fract(position.xy / iResolution); var p = uv * 2.4 - 1.2; p.x *= iResolution.x / iResolution.y; var d = circle(p); d = onion(d, p, PI / 2.0 + iTime); d = onion(d, p, PI / 6.0 + iTime); d = onion(d, p, -PI / 6.0 + iTime); if (d < 0.0) { return vec4<f32>(96.0 / 255.0, 219.0 / 255.0, 251.0 / 255.0, 0.8); } else { return vec4<f32>(0.0, 0.0, 0.0, 0.0); } } `, isWebGL: false, }) gl.uniform( useControls({ ellipseRadius: { min: 0, value: 0.2, max: 0.4 }, ellipseXCoord: { min: 0, value: 2.2, max: 4.4 }, ellipseYCoord: { min: 0, value: 5.4, max: 10.8 }, ellipseStroke: { min: 0, value: 0.01, max: 0.02 }, }) ) return <canvas ref={gl.ref} /> }
Result
Loading...
Live Editor
function Canvas() { const ellipseRadius = uniform(0.5, 'ellipseRadius') const ellipseXCoord = uniform(1.0, 'ellipseXCoord') const ellipseYCoord = uniform(1.0, 'ellipseYCoord') const ellipseStroke = uniform(0.1, 'ellipseStroke') const PI = float(3.141592) const rotate = Fn(([x, y, angle]) => { const scale = mat2(float(1).div(x), float(0), float(0), float(1).div(y)).toVar('scale') const rotation = mat2(cos(angle), sin(angle).negate(), sin(angle), cos(angle)).toVar('rotation') return scale.mul(rotation) }) rotate.setLayout({ name: 'rotate', type: 'mat2', inputs: [ { name: 'x', type: 'float' }, { name: 'y', type: 'float' }, { name: 'angle', type: 'float' }, ], }) const circle = Fn(([p]) => { return length(p).sub(ellipseRadius) }) circle.setLayout({ name: 'circle', type: 'float', inputs: [{ name: 'p', type: 'vec2' }], }) const ellipse = Fn(([p, angle]) => { const transform = rotate(ellipseXCoord, ellipseYCoord, angle).toVar('transform') return circle(transform.mul(p)) }) ellipse.setLayout({ name: 'ellipse', type: 'float', inputs: [ { name: 'p', type: 'vec2' }, { name: 'angle', type: 'float' }, ], }) const onion = Fn(([d, p, angle]) => { return min(d, abs(ellipse(p, angle)).sub(ellipseStroke)) }) onion.setLayout({ name: 'onion', type: 'float', inputs: [ { name: 'd', type: 'float' }, { name: 'p', type: 'vec2' }, { name: 'angle', type: 'float' }, ], }) const frag = Fn(() => { const uv = fract(position.xy.div(iResolution)).toVar('uv') const p = uv.mul(2.4).sub(1.2).toVar('p') p.x = p.x.mul(iResolution.x.div(iResolution.y)) const d = circle(p).toVar('d') d.assign(onion(d, p, PI.div(2).add(iTime))) d.assign(onion(d, p, PI.div(6).add(iTime))) d.assign(onion(d, p, PI.div(6).negate().add(iTime))) const color = vec4(0, 0, 0, 0).toVar('color') If(d.lessThan(float(0)), () => { color.assign(vec4(float(96).div(255), float(219).div(255), float(251).div(255), 0.8)) }) return color })() const gl = useGL({ frag }) gl.uniform( useControls({ ellipseRadius: { min: 0, value: 0.2, max: 0.4 }, ellipseXCoord: { min: 0, value: 2.2, max: 4.4 }, ellipseYCoord: { min: 0, value: 5.4, max: 10.8 }, ellipseStroke: { min: 0, value: 0.01, max: 0.02 }, }) ) return <canvas ref={gl.ref} /> }
Result
Loading...