Skip to content

@frapx/glsl-raymarch

glsl-* — GLSL snippet Not a runtime — plain GLSL strings you concatenate into your own fragment.

The skeleton of a raymarched 3D scene: you write float frapx_map(vec3 p), the signed distance to your scene, and this package marches rays against it. Lighting, materials and color grading stay in your shader. Pair it with @frapx/glsl-sdf for the distance functions.

Terminal window
pnpm add @frapx/fx-canvas @frapx/glsl-raymarch @frapx/glsl-sdf
import { createShaderBackground, glsl } from "@frapx/fx-canvas";
import { raymarch, raymarchCamera, raymarchCameraUniforms } from "@frapx/glsl-raymarch";
import { sdf3d } from "@frapx/glsl-sdf";
createShaderBackground({
target: ".hero",
uniforms: { camPos: [0, 1.5, 5], camTarget: [0, 0, 0], fov: Math.PI / 4 },
fragment: glsl`
precision highp float;
uniform vec2 u_resolution;
${sdf3d}
${raymarchCamera}
${raymarchCameraUniforms}
${raymarch}
float frapx_map(vec3 p) {
return min(frapx_sdSphere(p, 1.0), p.y + 1.0);
}
void main() {
vec3 rd = frapx_cameraRay(gl_FragCoord.xy, u_resolution);
vec3 color = vec3(0.05);
float t = frapx_raymarch(u_camPos, rd, 0.0, 30.0);
if (t > 0.0) {
vec3 p = u_camPos + rd * t;
vec3 n = frapx_normal(p, 0.0005 * t);
vec3 light = normalize(vec3(0.6, 1.0, 0.4));
float diffuse = max(dot(n, light), 0.0);
diffuse *= frapx_softShadow(p + n * 0.01, light, 0.01, 10.0, 16.0);
color = vec3(0.8) * (0.15 * frapx_ao(p, n, 0.2) + diffuse);
}
gl_FragColor = vec4(pow(color, vec3(0.4545)), 1.0);
}
`
});
Export Contents
raymarch frapx_map forward declaration, frapx_raymarch, frapx_normal, frapx_softShadow, frapx_ao, loop-limit macros
raymarchCamera frapx_lookAt, frapx_cameraRay — independent of frapx_map
raymarchCameraUniforms u_camPos, u_camTarget, u_fov and a frapx_cameraRay(fragCoord, resolution) that reads them. Include after raymarchCamera

frapx_map may be defined before or after ${raymarch}. frapx_raymarch returns the hit distance, or -1.0 on a miss. The groups never define the same signature twice and share no names with @frapx/glsl-sdf. Everything works in both GLSL ES 1.00 and 3.00.

  • World up is +y. fov is the vertical field of view in radians.
  • Set camPos, camTarget and fov before the first frame — unset uniforms are zero, which puts the eye on the target.
  • Step limits are macros (FRAPX_RAYMARCH_STEPS 128, FRAPX_SHADOW_STEPS 64, FRAPX_AO_SAMPLES 5, FRAPX_RAYMARCH_PRECISION 0.0005), because GLSL ES 1.00 loops need constant bounds. #define them before the snippet, for example to march further when exporting final frames.
  • If frapx_map returns a bound rather than an exact distance (after twist or bend), scale it down, such as return d * 0.5;.

Full function list: README on GitHub.

The helpers are adapted from Inigo Quilez’s Shadertoy shaders, each published under the MIT License. The package ships LICENSES/iq-raymarch-MIT.txt, which lists the source shader for each function and includes the license text. raymarch and raymarchCamera start with the raymarchLicense attribution comment, also exported on its own.