Solandra can render GLSL fragment shaders to images and draw them in a sketch. You can also render a sketch to an image and pass it to a shader.
These APIs are intended for adding textures and image effects to sketches.
These APIs require a browser with
OffscreenCanvassupport.
renderShader({ w, h, shader }) compiles a GLSL fragment shader, renders it offscreen at the given pixel size and returns an ImageBitmap. Your shader gets a u_resolution uniform, and should set gl_FragColor in main. Draw the result with s.drawImage:
import { renderShader } from "solandra"
const image = renderShader({
w: 800,
h: 800,
shader: `
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
float d = distance(pos, vec2(0.5));
gl_FragColor = vec4(pos.x, 0.4 + 0.4 * cos(d * 40.0), pos.y, 1.0);
}
`,
})
const sketch = (s: SCanvas) => {
s.drawImage({ image }) // fills the canvas by default
}drawImage accepts optional at, w and h values in canvas units:
s.drawImage({ image, at: [0.1, 0.1], w: 0.35, h: 0.35 })Add built-in GLSL helpers with includes:
"rand" — a hash-based rand(vec2) pseudo-random function"palette" — Inigo Quilez's cosine palette(t, a, b, c, d) function (the same idea as the palette API)const image = renderShader({
w: 800,
h: 800,
includes: ["rand", "palette"],
shader: `
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
vec3 color = palette(
pos.x + 0.15 * rand(pos),
vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.0, 0.33, 0.67)
);
gl_FragColor = vec4(color, 1.0);
}
`,
})
s.drawImage({ image })render({ w, h, sketch, seed, time }) renders a sketch offscreen as an ImageBitmap. Pass images to renderShader through its images option; each becomes a sampler2D uniform:
import { render, renderShader } from "solandra"
// 1. draw something with ordinary Solandra
const source = render({
w: 800,
h: 800,
sketch: (s) => {
s.background(215, 70, 25)
s.setFillColor(45, 90, 65)
s.fill(new Star({ at: s.meta.center, r: 0.35, n: 5 }))
},
})
// 2. distort it with a shader
const warped = renderShader({
w: 800,
h: 800,
images: { source },
shader: `
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
pos.x += 0.08 * sin(pos.y * 20.0);
pos.y = 1.0 - pos.y; // textures are y-flipped
gl_FragColor = texture2D(source, pos);
}
`,
})
// 3. use it in a final sketch
const sketch = (s: SCanvas) => {
s.drawImage({ image: warped })
}Shader output is an image, so you can clip it, draw shapes over it or apply blend modes:
const texture = renderShader({
w: 800,
h: 800,
includes: ["rand"],
shader: `
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
float n = rand(floor(pos * 60.0) / 60.0);
gl_FragColor = vec4(vec3(0.1 + 0.15 * n), 1.0);
}
`,
})
s.drawImage({ image: texture })
s.withBlendMode("lighten", () => {
s.times(16, (n) => {
s.setFillColor(180 + n * 8, 80, 50, 0.6)
s.fill(
new RegularPolygon({
at: s.randomPoint(),
n: 6,
r: 0.04 + s.random() * 0.1,
})
)
})
})See the shader examples for simplex noise and rendering in multiple stages.
Solandra was made by James Porter.
Check out the GitHub page or install with npm i solandra