Skip to content

3D

View .mdllms.txt

3D and 2D share one depth buffer. The camera is calibrated so z = 0 maps 1:1 onto canvas pixels: a box at x: 960, y: 540, z: 0 sits in the centre of a 1920×1080 frame. y points down, so “up” is −y.

import { Composition, Layer3D, LayerAnimation, Lighting } from "framefields";
const W = 1920, H = 1080;
const comp = new Composition({ width: W, height: H, fps: 30, durationMs: 4000, backgroundColor: "#0b0b0c" });
comp.add(Lighting.studio({ target: [W / 2, H / 2, 0] })); // environment + key/rim/fill, soft shadow
comp.add(
Layer3D.text({
text: "framefields", fontFamily: "Archivo", fontWeight: 800, fontSize: 280,
extrusionDepth: 26, fill: "#f5e300", bevelColor: "#6b6300", roughness: 0.35,
x: W / 2, y: H / 2, z: 0,
}).animate(LayerAnimation.create().keys("rotateY", [[0, -20], [120, 6, "sine.inOut"]])),
);

Rigs: Lighting.studio, soft, sunset, dramatic. Options: target, distance, rotation, intensity, exposure (stops), toneMapping, shadows (default on), shadowSoftness, fog, bloom. A rig returns an array; comp.add takes it, or spread it into children.

import { CameraAnimation, Layer } from "framefields";
comp.add(
Layer.camera({ x: 960, y: 540, z: -1000, targetX: 960, targetY: 540, targetZ: 0 }).animate(
CameraAnimation.camera()
.orbit({ azimuth: { from: -30, to: 30 }, elevation: { from: 15, to: 15 }, radius: { to: 1200 }, start: 0, end: 300, ease: "sine.inOut" })
.rackFocus({ fromDistance: 2000, toDistance: 1200, fromFStop: 1.8, toFStop: 4, start: 20, end: 60 }),
),
);

CameraAnimation.camera() moves: orbit, dolly, truck, pedestal, pan, tilt, roll, rackFocus, handheld({ translationAmplitude, rotationAmplitude }). Camera mode is "lookAt" (default), "free" or "orbit".

import { Layer, Light } from "framefields";
comp.add([
Layer.environment("studio", { // presets: studio | soft | sunset | night | neutral
exposure: 0.3,
toneMapping: "neutral", // default; "agx" filmic, "aces" punchy, "none"
rotation: 30,
fog: { color: "#0b0b0c", start: 2000, end: 5000 },
bloom: true, // or { intensity, threshold, radius }
}),
Light.directional({ x: 400, y: -1200, z: -600, targetX: 960, targetY: 540, castShadow: true }),
Light.ambient("#ffffff", 0.3),
]);

Light.ambient, Light.directional, Light.point, Light.spot (also Layer.ambientLight, Layer.directionalLight, Layer.pointLight, Layer.spotLight).

Rule Why
Add Layer.environment(...) for roughness / metallic to mean anything Without it the scene uses classic Blinn-Phong (lint: pbr_without_environment)
One castShadow light, directional or spot Only the first casts (multiple_shadow_lights); point/ambient can’t (shadow_unsupported_light)
Tone mapping "neutral" keeps brand colors as authored "agx" rolls highlights off filmically
Bloom only takes light well past white Use emissiveIntensity ≳ 3 to make something glow
Set fog.color to the background Surfaces fade into it seamlessly
Layer3D.roundedBox({ x: 960, y: 540, z: 0, width: 300, height: 80, depth: 300, radius: 18, taper: 0.9, color: "#ff5a1f", roughness: 0.45 }); // keycap
Layer3D.sphere({ x: 700, y: 540, z: 0, radius: 90, color: "#e8e8e8", metallic: 1, roughness: 0.15 }); // chrome
Layer3D.cylinder({ x: 1200, y: 540, z: 0, radius: 12, height: 400, color: "#111", emissive: "#4da3ff", emissiveIntensity: 3 }); // neon tube
Builder Makes
Layer3D.roundedBox / sphere / cylinder solid smooth-shaded meshes; equal shapes share GPU buffers, so hundreds are cheap
Layer3D.cube({ size, faces }) a cube whose faces are 2D layers
Layer3D.carousel({ radius, items }) 2D items on a ring
Layer3D.prism, Layer3D.plane, Layer3D.grid prisms, flat cards, ground grids
Layer3D.text / Layer3D.extrudedText extruded, bevelled type from your registered fonts

Surface props on meshes: color, tint (animates as color), roughness, metallic, emissive, emissiveIntensity, castShadow. Flat layers cast shadows only with castShadow: true; meshes cast by default.

comp.add(Layer.glb("assets/models/character.glb", { x: 960, y: 640, z: 0, scale: 2.5, loop: true }));

Loaders: Layer.glb, gltf, obj, fbx, stl, ply, vox, threeDS, off (also on Layer3D). glTF brings base color, normal, metallic-roughness, occlusion and emissive maps, and skeletal animation (up to 128 bones). Animate playback with animationProgress, animationTime or animationSpeed.

z, rotateX/Y/Z, scaleX/Y/Z, roughness, metallic, emissive, emissiveIntensity, exposure, intensity, plus camera props (cameraX/Y/Z, targetX/Y/Z, cameraFov, focusDistance, fStop, orbitRadius, orbitAzimuth, orbitElevation).