Reported from a live session on a Retina MacBook Pro: SDF object edges read as rough / low-resolution. Visible as stair-stepping along the box and sphere silhouettes, with the shapes otherwise smoothly shaded.
Not investigated as a fix — this is a starting point for whoever picks it up, so the session does not begin by guessing.
Two causes, stacking
1. The silhouette has no partial coverage. src/inputs/SDFGenerator.js:572 decides the hit with a hard threshold:
Coverage is therefore 1 or 0 per pixel. A ray that passes a hair outside the surface contributes nothing, and its neighbour contributes fully — which is a hard, stepped edge by construction, at any resolution.
2. The whole pipeline renders at DPR 1. src/main.js:236 sets renderer.setPixelRatio(1) deliberately: DPR 2 quadruples fill cost across 35+ shader passes for no visible gain on moving video. That reasoning holds for video and does not hold for a hard-edged synthetic silhouette, which is exactly where half linear resolution shows. On a Retina panel the SDF is rendered at half resolution and upscaled.
So the edge is both hard and magnified 2×.
What is likely the cheap fix
The raymarcher already tracks the quantity antialiasing needs. SDFGenerator.js:509–514:
float minD = 1e9; // closest the ray ever came to the surface
...
minD = min(minD, d);
minD is currently used only for the glow halo (line 532). It is the ray's closest approach to the surface, which is the analytic ingredient for coverage: instead of a binary hit, derive alpha by comparing minD against the pixel's world-space footprint at that depth, and smoothstep it. That is a handful of lines in the fragment shader, costs no extra marching, and — unlike a resolution increase — is paid once in the SDF pass rather than across all 35+.
Worth checking whether the same treatment helps the reflection hit test at line 677 (if (rdd < 0.002)), which has the same binary shape.
Things that will NOT fix it, and why
antialias: true on the renderer (src/main.js:230 currently false). MSAA antialiases geometry edges. This silhouette is produced inside a fragment shader on a full-screen quad, so there is no geometry edge to sample — the setting would cost fill rate and change nothing.
- Raising
setPixelRatio globally. It would help the look and is the expensive answer: 4× fill across the entire chain, which the comment at that line rejects for good measured reasons. If supersampling turns out to be needed, it belongs on the SDF render target alone, not on the pipeline.
Files
src/inputs/SDFGenerator.js — hit test (572), minD (509–514), reflection hit (677)
src/main.js:236 — pixel ratio, and the reasoning to argue with before changing it
Verification note
Judge this on a still frame, at rest, on a Retina display. A moving SDF hides aliasing, and the environment the fix is developed in may not be the one that shows the bug — see .claude/skills/verify/SKILL.md.
Reported from a live session on a Retina MacBook Pro: SDF object edges read as rough / low-resolution. Visible as stair-stepping along the box and sphere silhouettes, with the shapes otherwise smoothly shaded.
Not investigated as a fix — this is a starting point for whoever picks it up, so the session does not begin by guessing.
Two causes, stacking
1. The silhouette has no partial coverage.
src/inputs/SDFGenerator.js:572decides the hit with a hard threshold:Coverage is therefore 1 or 0 per pixel. A ray that passes a hair outside the surface contributes nothing, and its neighbour contributes fully — which is a hard, stepped edge by construction, at any resolution.
2. The whole pipeline renders at DPR 1.
src/main.js:236setsrenderer.setPixelRatio(1)deliberately: DPR 2 quadruples fill cost across 35+ shader passes for no visible gain on moving video. That reasoning holds for video and does not hold for a hard-edged synthetic silhouette, which is exactly where half linear resolution shows. On a Retina panel the SDF is rendered at half resolution and upscaled.So the edge is both hard and magnified 2×.
What is likely the cheap fix
The raymarcher already tracks the quantity antialiasing needs.
SDFGenerator.js:509–514:minDis currently used only for the glow halo (line 532). It is the ray's closest approach to the surface, which is the analytic ingredient for coverage: instead of a binary hit, derive alpha by comparingminDagainst the pixel's world-space footprint at that depth, andsmoothstepit. That is a handful of lines in the fragment shader, costs no extra marching, and — unlike a resolution increase — is paid once in the SDF pass rather than across all 35+.Worth checking whether the same treatment helps the reflection hit test at line 677 (
if (rdd < 0.002)), which has the same binary shape.Things that will NOT fix it, and why
antialias: trueon the renderer (src/main.js:230currentlyfalse). MSAA antialiases geometry edges. This silhouette is produced inside a fragment shader on a full-screen quad, so there is no geometry edge to sample — the setting would cost fill rate and change nothing.setPixelRatioglobally. It would help the look and is the expensive answer: 4× fill across the entire chain, which the comment at that line rejects for good measured reasons. If supersampling turns out to be needed, it belongs on the SDF render target alone, not on the pipeline.Files
src/inputs/SDFGenerator.js— hit test (572),minD(509–514), reflection hit (677)src/main.js:236— pixel ratio, and the reasoning to argue with before changing itVerification note
Judge this on a still frame, at rest, on a Retina display. A moving SDF hides aliasing, and the environment the fix is developed in may not be the one that shows the bug — see
.claude/skills/verify/SKILL.md.