fp64 sine sweep
sin(x) for x = a large base + a small on-screen sweep. Past ~2²⁴ one f32 ulp of the argument grows wider than the sweep window, so the plain-f32 wave (left) collapses into an aliased staircase; the emulated-f64 side (right) carries the base in extended precision and the injected df64_sin — argument reduction + tabled angle-addition + a short Taylor — resolves the smooth curve. Drag BASE from 10⁴ (both smooth) to 10⁸ (only f64 survives); flip the fp64 toggle to shatter both. Correct on backends where the df64 multiply survives fast-math (Apple/Metal collapses it — see AUTHORING §7).
One source, compiled every way
The DSL source below, compiled to WebGPU (WGSL), WebGL2 (GLSL ES 3.00 — two stages), and a reflection JSON the host binds from. Nothing but the DSL tab is hand-written.
// ═══ @xgis/shader-dsl example — fp64 sine sweep (df64 sin at large argument) ═══//// sin(x) where the argument x is a LARGE base plus a small on-screen sweep. As the// base grows past ~2²⁴, one f32 ulp of x widens past the sweep window: the plain-f32// argument `base + sx·span` quantizes to a few discrete steps, so its sine renders// as a STAIRCASE — the wave the eye expects has dissolved into aliased blocks. The// df64 side carries the base in extended precision, adds the sweep exactly, and the// injected df64_sin (3-stage reduction + tabled angle-addition + short Taylor)// resolves the smooth curve. Drag the BASE slider from 10⁴ (both smooth) up to 10⁸// (the f32 wave shatters, the f64 wave holds); flip the fp64 toggle to shatter both.//// This is the transcendental twin of fp64-cancellation: same graph-paper split, a// different f32 failure mode (argument-resolution loss, not term cancellation).//// The `_fp64` guard uniform is auto-injected by the lowering; the render harnesses// bind it to 1.0f by probing the program for the Fp64Guard block.
import { fn, module, uniformStruct, vec3, vec4, f32, toF64, sin, fract, abs, min, mix, step, smoothstep, toF32, f32T, f64T, vec2fT, Let,} from '../src/index.ts'import { VsOut, vs } from './_fullscreen.ts'import type { ShaderExample } from './_shared.ts'
// Sweep window (radians of argument spanned across one half's width). ~4 cycles// when the base is small enough to resolve them.const SPAN = 8 * Math.PI
const Uni = uniformStruct( 'Uniforms', { group: 0, binding: 0, as: 'u' }, { resolution: vec2fT, base: f64T, // large argument base (seconds-like), swept 10^4..10^8 fp64: f32T, // toggle: 1 = split-screen f32 | f64 (canonical), 0 = all-f32 },)
const fsSweep = fn( 'fs_sweep', { vo: VsOut }, (p) => { // Position within this half: sx ∈ [0, 1] over each half's width. const halfUv = Let(p.vo.uv.x.mul(2.0)) const sx = Let(halfUv.sub(p.vo.uv.x.lt(0.5).select(0.0, 1.0))) const isF32 = Let(p.vo.uv.x.lt(0.5).or(Uni.field.fp64.lt(0.5)))
// The swept argument = base + sx·SPAN. f64: add in extended precision, then // df64_sin. f32: narrow the base first (its ulp swallows the sweep at large base). const arg64 = Let(Uni.field.base.add(toF64(sx.mul(SPAN)))) const y64 = Let(toF32(sin(arg64))) const y32 = Let(sin(toF32(Uni.field.base).add(sx.mul(SPAN)))) const v = Let(isF32.select(y32, y64)) // sine value ∈ [−1, 1]
// Plot: py ∈ [−1, 1] over the height; the curve is v. const py = Let(p.vo.uv.y.sub(0.5).mul(2.0)) const px = Let(f32(2).div(Uni.field.resolution.y)) // plot-units per pixel
// Graph-paper: parchment + a pale grid (10 columns per half, 0.25-unit rows). const gxf = Let(fract(sx.mul(10.0))) const gyf = Let(fract(py.add(1.0).mul(4.0))) const dgx = Let(min(gxf, f32(1).sub(gxf))) const dgy = Let(min(gyf, f32(1).sub(gyf))) const aaCx = Let(f32(30).div(Uni.field.resolution.x)) const aaCy = Let(f32(20).div(Uni.field.resolution.y)) const grid = Let( f32(1) .sub(smoothstep(f32(0), aaCx, dgx)) .add(f32(1).sub(smoothstep(f32(0), aaCy, dgy))), ) const paper = vec3(0.96, 0.94, 0.88) const rgb0 = Let(mix(paper, vec3(0.72, 0.78, 0.86), min(grid, f32(1)).mul(0.45)))
// Fill under the curve — its boundary reads the verdict at a glance (a smooth // sine on f64, a stepped barcode on f32 once the base is large). const fill = Let(step(py, v)) const rgb1 = Let(mix(rgb0, vec3(0.62, 0.74, 0.9), fill.mul(0.4))) // Ink the curve. const ink = Let(f32(1).sub(smoothstep(px.mul(1.2), px.mul(3.0), abs(v.sub(py))))) const rgb2 = Let(mix(rgb1, vec3(0.13, 0.16, 0.3), ink.mul(0.85))) // Axes: the midline y = 0 and the half divider. const axis = Let( min( smoothstep(f32(0), px.mul(1.5), abs(py)), smoothstep(f32(0), px.mul(1.5), abs(sx.sub(0.5)).mul(2.0)), ), ) const rgb = Let(mix(vec3(0.35, 0.33, 0.3), rgb2, axis)) return vec4(rgb, f32(1)) }, { stage: 'fragment', retAttr: '@location(0)' },)
// `_fp64` guard lands at (group 0, binding 1) automatically.const fp64SineSweepModule = module({ funcs: [vs, fsSweep], uses: [Uni, VsOut],})
export const fp64SineSweep: ShaderExample = { id: 'fp64-sine-sweep', title: 'fp64 sine sweep', blurb: 'sin(x) for x = a large base + a small on-screen sweep. Past ~2²⁴ one f32 ulp of the argument grows wider than the sweep window, so the plain-f32 wave (left) collapses into an aliased staircase; the emulated-f64 side (right) carries the base in extended precision and the injected df64_sin — argument reduction + tabled angle-addition + a short Taylor — resolves the smooth curve. Drag BASE from 10⁴ (both smooth) to 10⁸ (only f64 survives); flip the fp64 toggle to shatter both. Correct on backends where the df64 multiply survives fast-math (Apple/Metal collapses it — see AUTHORING §7).', category: 'generic', file: 'fp64-sine-sweep.ts', module: fp64SineSweepModule, renderable: true, splitLabels: ['f32 sin', 'f64 sin (emulated)'], controls: { resolution: { kind: 'resolution' }, base: { kind: 'logmag1d', magField: 'mag', base: 1, offset: 0.123 }, mag: { kind: 'slider', label: 'Argument base 10^x', min: 4, max: 8, step: 0.02, value: 6, wheel: true, }, fp64: { kind: 'toggle', label: 'fp64 emulation', value: true }, },}struct Uniforms { resolution: vec2<f32>, base: vec2<f32>, fp64: f32,}
struct VsOut { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32>,}
@group(0) @binding(0) var<uniform> u: Uniforms;@group(0) @binding(1) var _fp64: texture_2d<f32>;
@vertexfn vs(@builtin(vertex_index) vi: u32) -> VsOut { let _cse0 = ((f32((vi & 1u)) * 4.0) - 1.0); let _cse1 = ((f32((vi >> 1u)) * 4.0) - 1.0); return VsOut(vec4<f32>(_cse0, _cse1, 0.0, 1.0), vec2<f32>(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5)));}
@fragmentfn fs_sweep(vo: VsOut) -> @location(0) vec4<f32> { let _cse0 = (vo.uv.x < 0.5); let _v0 = (vo.uv.x * 2.0); let _v1 = (_v0 - select(1.0, 0.0, _cse0)); let _v2 = (_cse0 || (u.fp64 < 0.5)); let _v3 = df64_add(u.base, vec2<f32>((_v1 * 25.132741228718345), 0.0)); let _v4 = df64_narrow(df64_sin(df64_add(_v3, vec2<f32>(0.0, 0.0)))); let _v5 = sin((df64_narrow(u.base) + (_v1 * 25.132741228718345))); let _v6 = select(_v4, _v5, _v2); let _v7 = ((vo.uv.y - 0.5) * 2.0); let _v8 = (2.0 / u.resolution.y); let _v9 = fract((_v1 * 10.0)); let _v10 = fract(((_v7 + 1.0) * 4.0)); let _v11 = min(_v9, (1.0 - _v9)); let _v12 = min(_v10, (1.0 - _v10)); let _v13 = (30.0 / u.resolution.x); let _v14 = (20.0 / u.resolution.y); let _v15 = ((1.0 - smoothstep(0.0, _v13, _v11)) + (1.0 - smoothstep(0.0, _v14, _v12))); let _v16 = mix(vec3<f32>(0.96, 0.94, 0.88), vec3<f32>(0.72, 0.78, 0.86), (min(_v15, 1.0) * 0.45)); let _v17 = step(_v7, _v6); let _v18 = mix(_v16, vec3<f32>(0.62, 0.74, 0.9), (_v17 * 0.4)); let _v19 = (1.0 - smoothstep((_v8 * 1.2), (_v8 * 3.0), abs((_v6 - _v7)))); let _v20 = mix(_v18, vec3<f32>(0.13, 0.16, 0.3), (_v19 * 0.85)); let _lc0 = (_v8 * 1.5); let _v21 = min(smoothstep(0.0, _lc0, abs(_v7)), smoothstep(0.0, _lc0, (abs((_v1 - 0.5)) * 2.0))); let _v22 = mix(vec3<f32>(0.35, 0.33, 0.3), _v20, _v21); return vec4<f32>(_v22, 1.0);}
fn df64_twoSum(a: f32, b: f32) -> vec2<f32> { let _cse0 = textureLoad(_fp64, vec2<i32>(0, 0), 0).x; let _v0 = (a + b); let _v1 = (((_v0 * _cse0) - a) * _cse0); let _v2 = (((((a - ((_v0 - _v1) * _cse0)) * _cse0) * _cse0) * _cse0) + (b - _v1)); return vec2<f32>(_v0, _v2);}
fn df64_quickTwoSum(a: f32, b: f32) -> vec2<f32> { let _cse0 = textureLoad(_fp64, vec2<i32>(0, 0), 0).x; let _v0 = ((a + b) * _cse0); let _v1 = (b - ((_v0 - a) * _cse0)); return vec2<f32>(_v0, _v1);}
fn df64_split(a: f32) -> vec2<f32> { let _cse0 = textureLoad(_fp64, vec2<i32>(0, 0), 0).x; let _v0 = (a * (_cse0 * 4097.0)); let _v1 = ((_v0 * _cse0) - (_v0 - a)); let _v2 = ((a * _cse0) - _v1); return vec2<f32>(_v1, _v2);}
fn df64_twoProd(a: f32, b: f32) -> vec2<f32> { let _v0 = (a * b); let _v1 = df64_split(a); let _v2 = df64_split(b); let _v3 = (((((_v1.x * _v2.x) - _v0) + (_v1.x * _v2.y)) + (_v1.y * _v2.x)) + (_v1.y * _v2.y)); return vec2<f32>(_v0, _v3);}
fn df64_add(a: vec2<f32>, b: vec2<f32>) -> vec2<f32> { var _v0: vec2<f32> = df64_twoSum(a.x, b.x); let _v1 = df64_twoSum(a.y, b.y); _v0.y = (_v0.y + _v1.x); _v0 = df64_quickTwoSum(_v0.x, _v0.y); _v0.y = (_v0.y + _v1.y); _v0 = df64_quickTwoSum(_v0.x, _v0.y); return _v0;}
fn df64_sub(a: vec2<f32>, b: vec2<f32>) -> vec2<f32> { return df64_add(a, (-b));}
fn df64_mul(a: vec2<f32>, b: vec2<f32>) -> vec2<f32> { var _v0: vec2<f32> = df64_twoProd(a.x, b.x); _v0.y = (_v0.y + (a.x * b.y)); _v0 = df64_quickTwoSum(_v0.x, _v0.y); _v0.y = (_v0.y + (a.y * b.x)); return df64_quickTwoSum(_v0.x, _v0.y);}
fn df64_div(a: vec2<f32>, b: vec2<f32>) -> vec2<f32> { let _v0 = (textureLoad(_fp64, vec2<i32>(0, 0), 0).x / b.x); let _v1 = (a * _v0); let _v2 = df64_sub(a, df64_mul(b, _v1)).x; let _v3 = df64_twoProd(_v0, _v2); return df64_add(_v1, _v3);}
fn df64_narrow(a: vec2<f32>) -> f32 { return (a.x + a.y);}
fn df64_nint(a: vec2<f32>) -> vec2<f32> { let _v0 = floor((a.x + 0.5)); let _v1 = select(_v0, (_v0 - 1.0), ((abs((_v0 - a.x)) == 0.5) && (a.y < 0.0))); return select(vec2<f32>(_v1, 0.0), df64_quickTwoSum(_v0, floor((a.y + 0.5))), (_v0 == a.x));}
fn df64_sin_taylor(a: vec2<f32>) -> vec2<f32> { let _v0 = (-df64_mul(a, a)); let _v1 = df64_mul(a, _v0); let _v2 = df64_add(a, df64_mul(_v1, vec2<f32>(0.1666666716337204, -4.967053879312289e-9))); let _v3 = df64_mul(_v1, _v0); return df64_add(_v2, df64_mul(_v3, vec2<f32>(0.008333333767950535, -4.34617203337595e-10)));}
fn df64_cos_taylor(a: vec2<f32>) -> vec2<f32> { let _v0 = (-df64_mul(a, a)); let _v1 = df64_add(vec2<f32>(1.0, 0.0), df64_mul(_v0, vec2<f32>(0.5, 0.0))); let _v2 = df64_mul(_v0, _v0); let _v3 = df64_add(_v1, df64_mul(_v2, vec2<f32>(0.0416666679084301, -1.2417634698280722e-9))); let _v4 = df64_mul(_v2, _v0); return df64_add(_v3, df64_mul(_v4, vec2<f32>(0.0013888889225199819, -3.3631094437103215e-11)));}
fn df64_sin(a: vec2<f32>) -> vec2<f32> { let _cse0 = vec2<f32>(6.2831854820251465, -1.7484555314695172e-7); let _cse1 = vec2<f32>(0.7071067690849304, 1.2101617485882343e-8); let _v0 = df64_nint(df64_div(a, _cse0)); let _v1 = df64_sub(a, df64_mul(_cse0, _v0)); let _v2 = floor(((_v1.x / 1.5707963705062866) + 0.5)); let _v3 = df64_sub(_v1, df64_mul(vec2<f32>(1.5707963705062866, -4.371138828673793e-8), vec2<f32>(_v2, 0.0))); let _v4 = floor(((_v3.x / 0.19634954631328583) + 0.5)); let _v5 = df64_sub(_v3, df64_mul(vec2<f32>(0.19634954631328583, -5.463923535842241e-9), vec2<f32>(_v4, 0.0))); let _v6 = df64_sin_taylor(_v5); let _v7 = df64_cos_taylor(_v5); let _v8 = abs(_v4); let _v9 = select(select(select(select(vec2<f32>(1.0, 0.0), _cse1, (_v8 == 4.0)), vec2<f32>(0.8314695954322815, 1.687026340846387e-8), (_v8 == 3.0)), vec2<f32>(0.9238795042037964, 2.830748968563057e-8), (_v8 == 2.0)), vec2<f32>(0.9807852506637573, 2.9739473106360492e-8), (_v8 == 1.0)); let _v10 = select(select(select(select(vec2<f32>(0.0, 0.0), _cse1, (_v8 == 4.0)), vec2<f32>(0.5555702447891235, -1.1769521357507529e-8), (_v8 == 3.0)), vec2<f32>(0.3826834261417389, 6.2233507236442165e-9), (_v8 == 2.0)), vec2<f32>(0.19509032368659973, -1.6704715388726754e-9), (_v8 == 1.0)); let _v11 = select((-_v10), _v10, (_v4 >= 0.0)); let _v12 = df64_add(df64_mul(_v9, _v6), df64_mul(_v11, _v7)); let _v13 = df64_sub(df64_mul(_v9, _v7), df64_mul(_v11, _v6)); return select(select(select((-_v12), (-_v13), (_v2 == -1.0)), _v13, (_v2 == 1.0)), _v12, (_v2 == 0.0));}#version 300 esprecision highp float;precision highp int;
struct VsOut { vec4 pos; vec2 uv;};out vec2 uv;
VsOut vs_impl(uint vi) { float _cse0 = ((float((vi & 1u)) * 4.0) - 1.0); float _cse1 = ((float((vi >> 1u)) * 4.0) - 1.0); return VsOut(vec4(_cse0, _cse1, 0.0, 1.0), vec2(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5)));}
void main() { VsOut _out = vs_impl(uint(gl_VertexID)); gl_Position = _out.pos; uv = _out.uv;}#version 300 esprecision highp float;precision highp int;
struct VsOut { vec4 pos; vec2 uv;};layout(std140) uniform Uniforms { vec2 resolution; vec2 base; float fp64;} u;
uniform sampler2D _fp64;vec2 df64_twoSum(float a, float b);vec2 df64_quickTwoSum(float a, float b);vec2 df64_split(float a);vec2 df64_twoProd(float a, float b);vec2 df64_add(vec2 a, vec2 b);vec2 df64_sub(vec2 a, vec2 b);vec2 df64_mul(vec2 a, vec2 b);vec2 df64_div(vec2 a, vec2 b);float df64_narrow(vec2 a);vec2 df64_nint(vec2 a);vec2 df64_sin_taylor(vec2 a);vec2 df64_cos_taylor(vec2 a);vec2 df64_sin(vec2 a);vec2 df64_twoSum(float a, float b) { float _cse0 = texelFetch(_fp64, ivec2(0, 0), 0).x; float _v0 = (a + b); float _v1 = (((_v0 * _cse0) - a) * _cse0); float _v2 = (((((a - ((_v0 - _v1) * _cse0)) * _cse0) * _cse0) * _cse0) + (b - _v1)); return vec2(_v0, _v2);}
vec2 df64_quickTwoSum(float a, float b) { float _cse0 = texelFetch(_fp64, ivec2(0, 0), 0).x; float _v0 = ((a + b) * _cse0); float _v1 = (b - ((_v0 - a) * _cse0)); return vec2(_v0, _v1);}
vec2 df64_split(float a) { float _cse0 = texelFetch(_fp64, ivec2(0, 0), 0).x; float _v0 = (a * (_cse0 * 4097.0)); float _v1 = ((_v0 * _cse0) - (_v0 - a)); float _v2 = ((a * _cse0) - _v1); return vec2(_v1, _v2);}
vec2 df64_twoProd(float a, float b) { float _v0 = (a * b); vec2 _v1 = df64_split(a); vec2 _v2 = df64_split(b); float _v3 = (((((_v1.x * _v2.x) - _v0) + (_v1.x * _v2.y)) + (_v1.y * _v2.x)) + (_v1.y * _v2.y)); return vec2(_v0, _v3);}
vec2 df64_add(vec2 a, vec2 b) { vec2 _v0 = df64_twoSum(a.x, b.x); vec2 _v1 = df64_twoSum(a.y, b.y); _v0.y = (_v0.y + _v1.x); _v0 = df64_quickTwoSum(_v0.x, _v0.y); _v0.y = (_v0.y + _v1.y); _v0 = df64_quickTwoSum(_v0.x, _v0.y); return _v0;}
vec2 df64_sub(vec2 a, vec2 b) { return df64_add(a, (-b));}
vec2 df64_mul(vec2 a, vec2 b) { vec2 _v0 = df64_twoProd(a.x, b.x); _v0.y = (_v0.y + (a.x * b.y)); _v0 = df64_quickTwoSum(_v0.x, _v0.y); _v0.y = (_v0.y + (a.y * b.x)); return df64_quickTwoSum(_v0.x, _v0.y);}
vec2 df64_div(vec2 a, vec2 b) { float _v0 = (texelFetch(_fp64, ivec2(0, 0), 0).x / b.x); vec2 _v1 = (a * _v0); float _v2 = df64_sub(a, df64_mul(b, _v1)).x; vec2 _v3 = df64_twoProd(_v0, _v2); return df64_add(_v1, _v3);}
float df64_narrow(vec2 a) { return (a.x + a.y);}
vec2 df64_nint(vec2 a) { float _v0 = floor((a.x + 0.5)); float _v1 = (((abs((_v0 - a.x)) == 0.5) && (a.y < 0.0)) ? (_v0 - 1.0) : _v0); return ((_v0 == a.x) ? df64_quickTwoSum(_v0, floor((a.y + 0.5))) : vec2(_v1, 0.0));}
vec2 df64_sin_taylor(vec2 a) { vec2 _v0 = (-df64_mul(a, a)); vec2 _v1 = df64_mul(a, _v0); vec2 _v2 = df64_add(a, df64_mul(_v1, vec2(0.1666666716337204, -4.967053879312289e-9))); vec2 _v3 = df64_mul(_v1, _v0); return df64_add(_v2, df64_mul(_v3, vec2(0.008333333767950535, -4.34617203337595e-10)));}
vec2 df64_cos_taylor(vec2 a) { vec2 _v0 = (-df64_mul(a, a)); vec2 _v1 = df64_add(vec2(1.0, 0.0), df64_mul(_v0, vec2(0.5, 0.0))); vec2 _v2 = df64_mul(_v0, _v0); vec2 _v3 = df64_add(_v1, df64_mul(_v2, vec2(0.0416666679084301, -1.2417634698280722e-9))); vec2 _v4 = df64_mul(_v2, _v0); return df64_add(_v3, df64_mul(_v4, vec2(0.0013888889225199819, -3.3631094437103215e-11)));}
vec2 df64_sin(vec2 a) { vec2 _cse0 = vec2(6.2831854820251465, -1.7484555314695172e-7); vec2 _cse1 = vec2(0.7071067690849304, 1.2101617485882343e-8); vec2 _v0 = df64_nint(df64_div(a, _cse0)); vec2 _v1 = df64_sub(a, df64_mul(_cse0, _v0)); float _v2 = floor(((_v1.x / 1.5707963705062866) + 0.5)); vec2 _v3 = df64_sub(_v1, df64_mul(vec2(1.5707963705062866, -4.371138828673793e-8), vec2(_v2, 0.0))); float _v4 = floor(((_v3.x / 0.19634954631328583) + 0.5)); vec2 _v5 = df64_sub(_v3, df64_mul(vec2(0.19634954631328583, -5.463923535842241e-9), vec2(_v4, 0.0))); vec2 _v6 = df64_sin_taylor(_v5); vec2 _v7 = df64_cos_taylor(_v5); float _v8 = abs(_v4); vec2 _v9 = ((_v8 == 1.0) ? vec2(0.9807852506637573, 2.9739473106360492e-8) : ((_v8 == 2.0) ? vec2(0.9238795042037964, 2.830748968563057e-8) : ((_v8 == 3.0) ? vec2(0.8314695954322815, 1.687026340846387e-8) : ((_v8 == 4.0) ? _cse1 : vec2(1.0, 0.0))))); vec2 _v10 = ((_v8 == 1.0) ? vec2(0.19509032368659973, -1.6704715388726754e-9) : ((_v8 == 2.0) ? vec2(0.3826834261417389, 6.2233507236442165e-9) : ((_v8 == 3.0) ? vec2(0.5555702447891235, -1.1769521357507529e-8) : ((_v8 == 4.0) ? _cse1 : vec2(0.0, 0.0))))); vec2 _v11 = ((_v4 >= 0.0) ? _v10 : (-_v10)); vec2 _v12 = df64_add(df64_mul(_v9, _v6), df64_mul(_v11, _v7)); vec2 _v13 = df64_sub(df64_mul(_v9, _v7), df64_mul(_v11, _v6)); return ((_v2 == 0.0) ? _v12 : ((_v2 == 1.0) ? _v13 : ((_v2 == -1.0) ? (-_v13) : (-_v12))));}in vec2 uv;layout(location = 0) out vec4 _ret;
vec4 fs_sweep_impl(VsOut vo) { bool _cse0 = (vo.uv.x < 0.5); float _v0 = (vo.uv.x * 2.0); float _v1 = (_v0 - (_cse0 ? 0.0 : 1.0)); bool _v2 = (_cse0 || (u.fp64 < 0.5)); vec2 _v3 = df64_add(u.base, vec2((_v1 * 25.132741228718345), 0.0)); float _v4 = df64_narrow(df64_sin(df64_add(_v3, vec2(0.0, 0.0)))); float _v5 = sin((df64_narrow(u.base) + (_v1 * 25.132741228718345))); float _v6 = (_v2 ? _v5 : _v4); float _v7 = ((vo.uv.y - 0.5) * 2.0); float _v8 = (2.0 / u.resolution.y); float _v9 = fract((_v1 * 10.0)); float _v10 = fract(((_v7 + 1.0) * 4.0)); float _v11 = min(_v9, (1.0 - _v9)); float _v12 = min(_v10, (1.0 - _v10)); float _v13 = (30.0 / u.resolution.x); float _v14 = (20.0 / u.resolution.y); float _v15 = ((1.0 - smoothstep(0.0, _v13, _v11)) + (1.0 - smoothstep(0.0, _v14, _v12))); vec3 _v16 = mix(vec3(0.96, 0.94, 0.88), vec3(0.72, 0.78, 0.86), (min(_v15, 1.0) * 0.45)); float _v17 = step(_v7, _v6); vec3 _v18 = mix(_v16, vec3(0.62, 0.74, 0.9), (_v17 * 0.4)); float _v19 = (1.0 - smoothstep((_v8 * 1.2), (_v8 * 3.0), abs((_v6 - _v7)))); vec3 _v20 = mix(_v18, vec3(0.13, 0.16, 0.3), (_v19 * 0.85)); float _lc0 = (_v8 * 1.5); float _v21 = min(smoothstep(0.0, _lc0, abs(_v7)), smoothstep(0.0, _lc0, (abs((_v1 - 0.5)) * 2.0))); vec3 _v22 = mix(vec3(0.35, 0.33, 0.3), _v20, _v21); return vec4(_v22, 1.0);}
void main() { VsOut vo; vo.pos = gl_FragCoord; vo.uv = uv; _ret = fs_sweep_impl(vo);}{ "bindGroups": [ { "group": 0, "entries": [ { "group": 0, "binding": 0, "name": "u", "space": "uniform", "resourceKind": "uniform-buffer", "structName": "Uniforms" } ] } ], "uniforms": [ { "name": "Uniforms", "size": 32, "align": 16, "fields": [ { "name": "resolution", "type": "vec2<f32>", "offset": 0, "align": 8, "size": 8 }, { "name": "base", "type": "f64", "offset": 8, "align": 8, "size": 8 }, { "name": "fp64", "type": "f32", "offset": 16, "align": 4, "size": 4 } ] } ], "storage": [], "entries": [ { "name": "vs", "stage": "vertex", "inputs": [ "u32" ], "output": "struct:VsOut" }, { "name": "fs_sweep", "stage": "fragment", "inputs": [ "struct:VsOut" ], "output": "vec4<f32>" } ], "overrides": []}
Run it locally:
npx tsx examples/print.ts fp64-sine-sweep
— prints the WGSL, GLSL, reflection. Source:
GitHub.
New to the IR? See Concepts; the full authoring + emit surface is in the API reference.