palette-field@0.1.0

Palette field

Flow without geometry: one fBM field warps another, and the result indexes a cosine palette. OKLab mixing sinks the edges into black.

Controls

1.6
1.00
#a28baa
#ad95a6

Imports

What this entry shader composes; every module resolves from npm.

import { fbmSimplex2d } from "@vgpu/wgsl-std/noise/simplex";

import { cosinePalette } from "@vshaders/color/palette";

import { mixOklab } from "@vshaders/color/oklab";

import { linearToSrgb3 } from "@vgpu/wgsl-std/color";

Source

The full entry shader, palette-field.wgsl. Copy it and it is yours.

// effect 003 · palette-field — domain-warped fBM driving a cosine palette.
// Flow without geometry: one noise field warps another, and the result
// indexes a palette. OKLab sinks the edges into the page ink.
// Works in linear light; encodes to sRGB once at the end.

import { fbmSimplex2d } from "@vgpu/wgsl-std/noise/simplex";
import { cosinePalette } from "@vshaders/color/palette";
import { mixOklab } from "@vshaders/color/oklab";
import { linearToSrgb3 } from "@vgpu/wgsl-std/color";

// Tunable members follow resolution/time. Defaults live in lib/effects.ts and
// must be set by the runner: an unset uniform member reads as zero. Members are
// ordered so each vec3f lands on a 16-byte boundary with an f32 in its pad.
struct Uniforms {
  resolution: vec2f,
  time: f32,
  // Noise frequency: how many field features fit across the card.
  scale: f32,
  // Cosine palette mean color, linear light.
  bias: vec3f,
  // Multiplies time in every animation term.
  speed: f32,
  // Cosine palette per-channel swing around the bias, linear light.
  amplitude: vec3f,
}

@group(0) @binding(0) var<uniform> uniforms: Uniforms;

@fragment
fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
  let res = max(uniforms.resolution, vec2f(1.0));
  let uv = position.xy / res;
  let aspect = res.x / res.y;
  let p = (uv - vec2f(0.5)) * vec2f(aspect, 1.0);
  let t = uniforms.time * 0.06 * uniforms.speed;

  let drift = fbmSimplex2d(p * uniforms.scale + vec2f(0.0, t), 4, 2.0, 0.5);
  let warped = fbmSimplex2d(p * uniforms.scale + vec2f(drift * 0.9, -t * 0.7), 4, 2.0, 0.5);

  let base = cosinePalette(
    warped * 0.55 + t * 0.35,
    uniforms.bias,
    uniforms.amplitude,
    vec3f(1.0),
    vec3f(0.00, 0.15, 0.42)
  );

  // Sink toward the page ink at the card's edges.
  let vignette = smoothstep(1.05, 0.35, length(p));
  let ink = vec3f(0.006, 0.007, 0.012);
  let color = mixOklab(ink, max(base, vec3f(0.0)), 0.22 + 0.78 * vignette);
  return vec4f(linearToSrgb3(clamp(color, vec3f(0.0), vec3f(1.0))), 1.0);
}