fp64 Newton fractal
Newton’s method for z³ = 1, colour = which cube root a pixel falls into — a full complex DIVISION per step, running through df64_div on the f64 side. The basin boundary has the Wada property (all three colours touch at every boundary point), so the interleaving persists to any depth: the f32 left half collapses flat past a ~1e-7 span while the emulated-double right half keeps dividing cleanly. Drag to pan, wheel to zoom, flip the fp64 toggle to compare.
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 Newton fractal (z³ = 1) ═══//// The fp64 family's DIVISION showcase: Newton's method z ← z − (z³−1)/(3z²)// runs a full complex division every iteration, and the f64 side does it with// df64_div (the long-division EFT) — the one emulated op an add/mul-only demo// never touches. The camera sits on a basin boundary of the three cube roots;// the boundary is the Julia set of the Newton map and has the Wada property// (every boundary point touches ALL THREE basins), so any zoom depth shows the// three colours interleaved — CPU-verified to 50+ distinct (root, steps) cells// per 48² window down to a 1e-11 span. The plain-f32 left half collapses once// the span drops under one ulp of the center (~1e-7).//// 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, vec3, vec4, f32, f64, pow, mix, toF32, toF64, f32T, vec2fT, vec2f64T, If, Loop, Var, Let, u32, uniformStruct,} from '../src/index.ts'import { VsOut, vs } from './_fullscreen.ts'import type { ShaderExample } from './_shared.ts'
// A boundary point between the basins of 1 and e^{2πi/3} (CPU bisection to// ~1e-19, so the window straddles the boundary at every reachable zoom).const CENTER_X = 0.17616732990860245const CENTER_Y = 0.7111381151066305const ITER = 48// Cube roots of unity (exactly representable enough for f32 CLASSIFICATION —// the roots are attracting, so classification is precision-insensitive).const R_IM = 0.8660254037844386 // √3/2
const U = uniformStruct( 'Uniforms', { group: 0, binding: 0, as: 'u' }, { center: vec2f64T, // one DF64Vec2 slot — host packs [hi.x, hi.y, lo.x, lo.y] resolution: vec2fT, zoom_exp: f32T, // view span = 10^-zoom_exp complex units fp64: f32T, // toggle: 1 = split-screen f32 | f64 (canonical), 0 = all-f32 },)
const fsNewton = fn( 'fs_newton', { vo: VsOut }, (p) => { const span = Let(pow(f32(10.0), U.field.zoom_exp.neg())) const half = Let(p.vo.uv.x.mul(2.0)) const sx = Let(half.sub(p.vo.uv.x.lt(0.5).select(0.0, 1.0))) const dx = Let(sx.sub(0.5).mul(span)) const dy = Let( p.vo.uv.y.sub(0.5).mul(span).mul(U.field.resolution.y.div(U.field.resolution.x).mul(2.0)), )
// Iterate to convergence; hand the FINAL z (narrowed) + step count out. const fx = Var(f32(0)) // final Re z const fy = Var(f32(0)) // final Im z const it = Var(f32(0)) // steps until the update went sub-epsilon If(p.vo.uv.x.lt(0.5).or(U.field.fp64.lt(0.5)), () => { // f32 twin — z₀ from the narrowed center: at deep zoom every pixel // starts at the SAME quantized point and the basins collapse flat. const zx = Var(toF32(U.field.center.x).add(dx)) const zy = Var(toF32(U.field.center.y).add(dy)) Loop( u32(0), (j) => j.lt(u32(ITER)), () => { const z2x = Let(zx.mul(zx).sub(zy.mul(zy))) const z2y = Let(zx.mul(zy).mul(2.0)) const nx = Let(z2x.mul(zx).sub(z2y.mul(zy)).sub(1.0)) // Re(z³−1) const ny = Let(z2x.mul(zy).add(z2y.mul(zx))) // Im(z³−1) const gx = Let(z2x.mul(3.0)) // Re(3z²) const gy = Let(z2y.mul(3.0)) const inv = Let(f32(1.0).div(gx.mul(gx).add(gy.mul(gy)))) const qx = Let(nx.mul(gx).add(ny.mul(gy)).mul(inv)) const qy = Let(ny.mul(gx).sub(nx.mul(gy)).mul(inv)) zx.assign(zx.sub(qx)) zy.assign(zy.sub(qy)) If(qx.mul(qx).add(qy.mul(qy)).gt(1e-14), () => { it.assign(it.add(1.0)) }) }, ) fx.assign(zx) fy.assign(zy) }).else(() => { // f64 — the SAME Newton step; the quotient runs through df64_div. const zx = Var(U.field.center.x.add(toF64(dx))) const zy = Var(U.field.center.y.add(toF64(dy))) Loop( u32(0), (j) => j.lt(u32(ITER)), () => { const z2x = Let(zx.mul(zx).sub(zy.mul(zy))) const z2y = Let(zx.mul(zy).mul(2.0)) const nx = Let(z2x.mul(zx).sub(z2y.mul(zy)).sub(1.0)) const ny = Let(z2x.mul(zy).add(z2y.mul(zx))) const gx = Let(z2x.mul(3.0)) const gy = Let(z2y.mul(3.0)) const inv = Let(f64(1.0).div(gx.mul(gx).add(gy.mul(gy)))) const qx = Let(nx.mul(gx).add(ny.mul(gy)).mul(inv)) const qy = Let(ny.mul(gx).sub(nx.mul(gy)).mul(inv)) zx.assign(zx.sub(qx)) zy.assign(zy.sub(qy)) If(toF32(qx.mul(qx).add(qy.mul(qy))).gt(1e-14), () => { it.assign(it.add(1.0)) }) }, ) fx.assign(toF32(zx)) fy.assign(toF32(zy)) })
// Classify the landing root (attracting fixed points — f32 suffices) and // shade by convergence speed: boundary-hugging pixels stay near-black. const d0 = Let(fx.sub(1.0).mul(fx.sub(1.0)).add(fy.mul(fy))) const d1 = Let( fx .add(0.5) .mul(fx.add(0.5)) .add(fy.sub(R_IM).mul(fy.sub(R_IM))), ) const d2 = Let( fx .add(0.5) .mul(fx.add(0.5)) .add(fy.add(R_IM).mul(fy.add(R_IM))), ) const c0 = vec3(0.91, 0.34, 0.22) // root 1 — vermilion const c1 = vec3(0.2, 0.66, 0.88) // root e^{2πi/3} — sky const c2 = vec3(0.98, 0.78, 0.22) // root e^{−2πi/3} — gold const base = Let(d0.le(d1).and(d0.le(d2)).select(c0, d1.le(d2).select(c1, c2))) const speed = Let(f32(1).sub(it.div(ITER))) const rgb = base.mul(mix(f32(0.25), f32(1.0), speed)) return vec4(rgb, f32(1)) }, { stage: 'fragment', retAttr: '@location(0)' },)
// `_fp64` guard lands at (group 0, binding 1) automatically.const fp64NewtonModule = module({ funcs: [vs, fsNewton], uses: [U, VsOut],})
export const fp64Newton: ShaderExample = { id: 'fp64-newton', title: 'fp64 Newton fractal', blurb: 'Newton’s method for z³ = 1, colour = which cube root a pixel falls into — a full complex DIVISION per step, running through df64_div on the f64 side. The basin boundary has the Wada property (all three colours touch at every boundary point), so the interleaving persists to any depth: the f32 left half collapses flat past a ~1e-7 span while the emulated-double right half keeps dividing cleanly. Drag to pan, wheel to zoom, flip the fp64 toggle to compare.', category: 'generic', file: 'fp64-newton.ts', module: fp64NewtonModule, renderable: true, splitLabels: ['f32', 'f64 (emulated)'], controls: { center: { kind: 'pan2d', value: [CENTER_X, CENTER_Y], zoomExpField: 'zoom_exp', unitsPerWidth: 2, }, resolution: { kind: 'resolution' }, zoom_exp: { kind: 'slider', label: 'Zoom 10^-x', min: 1, max: 13, step: 0.05, value: 4, wheel: true, }, fp64: { kind: 'toggle', label: 'fp64 emulation', value: true }, },}struct Uniforms { center: DF64Vec2, resolution: vec2<f32>, zoom_exp: f32, fp64: f32,}
struct VsOut { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32>,}
struct DF64Vec2 { hi: vec2<f32>, lo: 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_newton(vo: VsOut) -> @location(0) vec4<f32> { let _licm0 = vec2<f32>(2.0, 0.0); let _licm1 = vec2<f32>(0.0, 0.0); let _cse0 = (vo.uv.x < 0.5); let _cse1 = vec2<f32>(u.center.hi.x, u.center.lo.x); let _cse2 = vec2<f32>(u.center.hi.y, u.center.lo.y); let _cse3 = df64_add(vec2<f32>(1.0, 0.0), _licm1); let _cse4 = vec2<f32>(3.0, 0.0); let _v0 = pow(10.0, (-u.zoom_exp)); let _v1 = (vo.uv.x * 2.0); let _v2 = (_v1 - select(1.0, 0.0, _cse0)); let _v3 = ((_v2 - 0.5) * _v0); let _v4 = (((vo.uv.y - 0.5) * _v0) * ((u.resolution.y / u.resolution.x) * 2.0)); var _v5: f32 = 0.0; var _v6: f32 = 0.0; var _v7: f32 = 0.0; if ((_cse0 || (u.fp64 < 0.5))) { var _v8: f32 = (df64_narrow(_cse1) + _v3); var _v9: f32 = (df64_narrow(_cse2) + _v4); for (var _v10: u32 = 0u; (_v10 < 48u); _v10 = (_v10 + 1u)) { let _v11 = ((_v8 * _v8) - (_v9 * _v9)); let _v12 = ((_v8 * _v9) * 2.0); let _v13 = (((_v11 * _v8) - (_v12 * _v9)) - 1.0); let _v14 = ((_v11 * _v9) + (_v12 * _v8)); let _v15 = (_v11 * 3.0); let _v16 = (_v12 * 3.0); let _v17 = (1.0 / ((_v15 * _v15) + (_v16 * _v16))); let _v18 = (((_v13 * _v15) + (_v14 * _v16)) * _v17); let _v19 = (((_v14 * _v15) - (_v13 * _v16)) * _v17); _v8 = (_v8 - _v18); _v9 = (_v9 - _v19); if ((((_v18 * _v18) + (_v19 * _v19)) > 1e-14)) { _v7 = (_v7 + 1.0); } } _v5 = _v8; _v6 = _v9; } else { var _v20: vec2<f32> = df64_add(_cse1, vec2<f32>(_v3, 0.0)); var _v21: vec2<f32> = df64_add(_cse2, vec2<f32>(_v4, 0.0)); for (var _v22: u32 = 0u; (_v22 < 48u); _v22 = (_v22 + 1u)) { let _v23 = df64_sub(df64_mul(_v20, _v20), df64_mul(_v21, _v21)); let _v24 = df64_mul(df64_mul(_v20, _v21), _licm0); let _v25 = df64_sub(df64_sub(df64_mul(_v23, _v20), df64_mul(_v24, _v21)), _cse3); let _v26 = df64_add(df64_mul(_v23, _v21), df64_mul(_v24, _v20)); let _v27 = df64_mul(_v23, _cse4); let _v28 = df64_mul(_v24, _cse4); let _v29 = df64_div(_cse3, df64_add(df64_mul(_v27, _v27), df64_mul(_v28, _v28))); let _v30 = df64_mul(df64_add(df64_mul(_v25, _v27), df64_mul(_v26, _v28)), _v29); let _v31 = df64_mul(df64_sub(df64_mul(_v26, _v27), df64_mul(_v25, _v28)), _v29); _v20 = df64_sub(df64_add(_v20, _licm1), df64_add(_v30, _licm1)); _v21 = df64_sub(df64_add(_v21, _licm1), df64_add(_v31, _licm1)); if ((df64_narrow(df64_add(df64_mul(_v30, _v30), df64_mul(_v31, _v31))) > 1e-14)) { _v7 = (_v7 + 1.0); } } _v5 = df64_narrow(_v20); _v6 = df64_narrow(_v21); } let _lc0 = (_v5 - 1.0); let _v32 = ((_lc0 * _lc0) + (_v6 * _v6)); let _lc1 = (_v5 + 0.5); let _lc2 = (_v6 - 0.8660254037844386); let _v33 = ((_lc1 * _lc1) + (_lc2 * _lc2)); let _lc3 = (_v5 + 0.5); let _lc4 = (_v6 + 0.8660254037844386); let _v34 = ((_lc3 * _lc3) + (_lc4 * _lc4)); let _v35 = select(select(vec3<f32>(0.98, 0.78, 0.22), vec3<f32>(0.2, 0.66, 0.88), (_v33 <= _v34)), vec3<f32>(0.91, 0.34, 0.22), ((_v32 <= _v33) && (_v32 <= _v34))); let _v36 = (1.0 - (_v7 / 48.0)); return vec4<f32>((_v35 * mix(0.25, 1.0, _v36)), 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);}#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;};
struct DF64Vec2 { vec2 hi; vec2 lo;};layout(std140) uniform Uniforms { DF64Vec2 center; vec2 resolution; float zoom_exp; 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_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);}in vec2 uv;layout(location = 0) out vec4 _ret;
vec4 fs_newton_impl(VsOut vo) { vec2 _licm0 = vec2(2.0, 0.0); vec2 _licm1 = vec2(0.0, 0.0); bool _cse0 = (vo.uv.x < 0.5); vec2 _cse1 = vec2(u.center.hi.x, u.center.lo.x); vec2 _cse2 = vec2(u.center.hi.y, u.center.lo.y); vec2 _cse3 = df64_add(vec2(1.0, 0.0), _licm1); vec2 _cse4 = vec2(3.0, 0.0); float _v0 = pow(10.0, (-u.zoom_exp)); float _v1 = (vo.uv.x * 2.0); float _v2 = (_v1 - (_cse0 ? 0.0 : 1.0)); float _v3 = ((_v2 - 0.5) * _v0); float _v4 = (((vo.uv.y - 0.5) * _v0) * ((u.resolution.y / u.resolution.x) * 2.0)); float _v5 = 0.0; float _v6 = 0.0; float _v7 = 0.0; if ((_cse0 || (u.fp64 < 0.5))) { float _v8 = (df64_narrow(_cse1) + _v3); float _v9 = (df64_narrow(_cse2) + _v4); for (uint _v10 = 0u; (_v10 < 48u); _v10 = (_v10 + 1u)) { float _v11 = ((_v8 * _v8) - (_v9 * _v9)); float _v12 = ((_v8 * _v9) * 2.0); float _v13 = (((_v11 * _v8) - (_v12 * _v9)) - 1.0); float _v14 = ((_v11 * _v9) + (_v12 * _v8)); float _v15 = (_v11 * 3.0); float _v16 = (_v12 * 3.0); float _v17 = (1.0 / ((_v15 * _v15) + (_v16 * _v16))); float _v18 = (((_v13 * _v15) + (_v14 * _v16)) * _v17); float _v19 = (((_v14 * _v15) - (_v13 * _v16)) * _v17); _v8 = (_v8 - _v18); _v9 = (_v9 - _v19); if ((((_v18 * _v18) + (_v19 * _v19)) > 1e-14)) { _v7 = (_v7 + 1.0); } } _v5 = _v8; _v6 = _v9; } else { vec2 _v20 = df64_add(_cse1, vec2(_v3, 0.0)); vec2 _v21 = df64_add(_cse2, vec2(_v4, 0.0)); for (uint _v22 = 0u; (_v22 < 48u); _v22 = (_v22 + 1u)) { vec2 _v23 = df64_sub(df64_mul(_v20, _v20), df64_mul(_v21, _v21)); vec2 _v24 = df64_mul(df64_mul(_v20, _v21), _licm0); vec2 _v25 = df64_sub(df64_sub(df64_mul(_v23, _v20), df64_mul(_v24, _v21)), _cse3); vec2 _v26 = df64_add(df64_mul(_v23, _v21), df64_mul(_v24, _v20)); vec2 _v27 = df64_mul(_v23, _cse4); vec2 _v28 = df64_mul(_v24, _cse4); vec2 _v29 = df64_div(_cse3, df64_add(df64_mul(_v27, _v27), df64_mul(_v28, _v28))); vec2 _v30 = df64_mul(df64_add(df64_mul(_v25, _v27), df64_mul(_v26, _v28)), _v29); vec2 _v31 = df64_mul(df64_sub(df64_mul(_v26, _v27), df64_mul(_v25, _v28)), _v29); _v20 = df64_sub(df64_add(_v20, _licm1), df64_add(_v30, _licm1)); _v21 = df64_sub(df64_add(_v21, _licm1), df64_add(_v31, _licm1)); if ((df64_narrow(df64_add(df64_mul(_v30, _v30), df64_mul(_v31, _v31))) > 1e-14)) { _v7 = (_v7 + 1.0); } } _v5 = df64_narrow(_v20); _v6 = df64_narrow(_v21); } float _lc0 = (_v5 - 1.0); float _v32 = ((_lc0 * _lc0) + (_v6 * _v6)); float _lc1 = (_v5 + 0.5); float _lc2 = (_v6 - 0.8660254037844386); float _v33 = ((_lc1 * _lc1) + (_lc2 * _lc2)); float _lc3 = (_v5 + 0.5); float _lc4 = (_v6 + 0.8660254037844386); float _v34 = ((_lc3 * _lc3) + (_lc4 * _lc4)); vec3 _v35 = (((_v32 <= _v33) && (_v32 <= _v34)) ? vec3(0.91, 0.34, 0.22) : ((_v33 <= _v34) ? vec3(0.2, 0.66, 0.88) : vec3(0.98, 0.78, 0.22))); float _v36 = (1.0 - (_v7 / 48.0)); return vec4((_v35 * mix(0.25, 1.0, _v36)), 1.0);}
void main() { VsOut vo; vo.pos = gl_FragCoord; vo.uv = uv; _ret = fs_newton_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": "center", "type": "vec2<f64>", "offset": 0, "align": 16, "size": 16 }, { "name": "resolution", "type": "vec2<f32>", "offset": 16, "align": 8, "size": 8 }, { "name": "zoom_exp", "type": "f32", "offset": 24, "align": 4, "size": 4 }, { "name": "fp64", "type": "f32", "offset": 28, "align": 4, "size": 4 } ] } ], "storage": [], "entries": [ { "name": "vs", "stage": "vertex", "inputs": [ "u32" ], "output": "struct:VsOut" }, { "name": "fs_newton", "stage": "fragment", "inputs": [ "struct:VsOut" ], "output": "vec4<f32>" } ], "overrides": []}
Run it locally:
npx tsx examples/print.ts fp64-newton
— prints the WGSL, GLSL, reflection. Source:
GitHub.
New to the IR? See Concepts; the full authoring + emit surface is in the API reference.