Skip to content

Commit 334dc0d

Browse files
arnogclaude
andcommitted
fix: use proper types in fractals library and clamp GPU preamble output to [0,1]
Replace `any` types in fractals.ts with `Expression` from global-types, using `isNumber()` type guard and `.re`/`.im` properties. Wrap smooth escape-time return values in GLSL and WGSL fractal preambles with `clamp(..., 0.0, 1.0)` to guarantee output stays in [0, 1]. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent f765fc9 commit 334dc0d

2 files changed

Lines changed: 15 additions & 21 deletions

File tree

src/compute-engine/compilation/gpu-target.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ float _fractal_mandelbrot(vec2 c, int maxIter) {
652652
for (int i = 0; i < maxIter; i++) {
653653
z = vec2(z.x*z.x - z.y*z.y + c.x, 2.0*z.x*z.y + c.y);
654654
if (dot(z, z) > 4.0)
655-
return (float(i) - log2(log2(dot(z, z))) + 4.0) / float(maxIter);
655+
return clamp((float(i) - log2(log2(dot(z, z))) + 4.0) / float(maxIter), 0.0, 1.0);
656656
}
657657
return 1.0;
658658
}
@@ -661,7 +661,7 @@ float _fractal_julia(vec2 z, vec2 c, int maxIter) {
661661
for (int i = 0; i < maxIter; i++) {
662662
z = vec2(z.x*z.x - z.y*z.y + c.x, 2.0*z.x*z.y + c.y);
663663
if (dot(z, z) > 4.0)
664-
return (float(i) - log2(log2(dot(z, z))) + 4.0) / float(maxIter);
664+
return clamp((float(i) - log2(log2(dot(z, z))) + 4.0) / float(maxIter), 0.0, 1.0);
665665
}
666666
return 1.0;
667667
}
@@ -676,7 +676,7 @@ fn _fractal_mandelbrot(c: vec2f, maxIter: i32) -> f32 {
676676
for (var i: i32 = 0; i < maxIter; i++) {
677677
z = vec2f(z.x*z.x - z.y*z.y + c.x, 2.0*z.x*z.y + c.y);
678678
if (dot(z, z) > 4.0) {
679-
return (f32(i) - log2(log2(dot(z, z))) + 4.0) / f32(maxIter);
679+
return clamp((f32(i) - log2(log2(dot(z, z))) + 4.0) / f32(maxIter), 0.0, 1.0);
680680
}
681681
}
682682
return 1.0;
@@ -687,7 +687,7 @@ fn _fractal_julia(z_in: vec2f, c: vec2f, maxIter: i32) -> f32 {
687687
for (var i: i32 = 0; i < maxIter; i++) {
688688
z = vec2f(z.x*z.x - z.y*z.y + c.x, 2.0*z.x*z.y + c.y);
689689
if (dot(z, z) > 4.0) {
690-
return (f32(i) - log2(log2(dot(z, z))) + 4.0) / f32(maxIter);
690+
return clamp((f32(i) - log2(log2(dot(z, z))) + 4.0) / f32(maxIter), 0.0, 1.0);
691691
}
692692
}
693693
return 1.0;

src/compute-engine/library/fractals.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import type { SymbolDefinitions } from '../global-types';
2-
3-
/** Smooth escape-time value for the Mandelbrot set (z0 = 0) in [0, 1]. */
4-
function mandelbrotEscape(cx: number, cy: number, maxN: number): number {
5-
return juliaEscape(0, 0, cx, cy, maxN);
6-
}
1+
import type { SymbolDefinitions, Expression } from '../global-types';
2+
import { isNumber } from '../boxed-expression/type-guards';
73

84
/** Smooth escape-time value for any z0 → z^2 + c iteration in [0, 1]. */
95
function juliaEscape(
@@ -26,23 +22,21 @@ function juliaEscape(
2622
return 1.0;
2723
}
2824

29-
/** Extract real and imaginary parts from a boxed numeric value. */
25+
/** Extract finite real and imaginary parts from a boxed numeric value. */
3026
function getComplexParts(
31-
op: any
27+
op: Expression
3228
): { cx: number; cy: number } | undefined {
33-
const n = op.numericValue;
34-
if (n === null || n === undefined) return undefined;
35-
const cx = typeof n === 'number' ? n : n.re;
36-
const cy = typeof n === 'number' ? 0 : n.im;
29+
if (!isNumber(op)) return undefined;
30+
const cx = op.re;
31+
const cy = op.im;
3732
if (!isFinite(cx) || !isFinite(cy)) return undefined;
3833
return { cx, cy };
3934
}
4035

4136
/** Extract a finite positive integer from a boxed numeric value. */
42-
function getMaxIter(op: any): number | undefined {
43-
const n = op.numericValue;
44-
if (n === null || n === undefined) return undefined;
45-
const v = typeof n === 'number' ? n : n.re;
37+
function getMaxIter(op: Expression): number | undefined {
38+
if (!isNumber(op)) return undefined;
39+
const v = op.re;
4640
if (!isFinite(v) || v <= 0) return undefined;
4741
return Math.round(v);
4842
}
@@ -58,7 +52,7 @@ export const FRACTALS_LIBRARY: SymbolDefinitions[] = [
5852
const cp = getComplexParts(c);
5953
const n = getMaxIter(maxIter);
6054
if (cp === undefined || n === undefined) return undefined;
61-
return ce.number(mandelbrotEscape(cp.cx, cp.cy, n));
55+
return ce.number(juliaEscape(0, 0, cp.cx, cp.cy, n));
6256
},
6357
},
6458

0 commit comments

Comments
 (0)