Skip to content
Русский

Attractor depth: the camera, depth_fade, depth_hue, spin

The 3-D families — thomas and lorenz — are seen through the shared camera that plexus, waterfall and the space curves use (ADR-0260). yaw turns it round the figure, pitch raises it, distance moves it in and out and fov is its field of view; focus and aperture are its lens. Each roster entry is first brought to unit radius by its own measured framing, so distance is in figure radii and means the same on every entry: at 1.5, the bottom of its range, a test holds every 3-D entry clear of the camera’s near plane. Lorenz Knot’s bass hit reaches about 1.43, below what that test covers. A particle nearer the camera than the near plane is dropped. The engine-wide zoom divides the field of view (the angle, not its tangent), and pan_x / pan_y slide the picture; on these two families pan_x is measured in frame heights, so a value written for a flat family drifts 16/9 as far on a 16:9 target. The default pitch is 0.25, so an unbound 3-D preset is seen slightly from above.

The camera turns the figure in place. It orbits the figure’s centre, so a yaw sweep or a spin no longer slides the figure round the frame: over a full turn a Lorenz figure’s projected centroid moves about 0.12 NDC at a camera matched to the old perspective = 0.25, where that setting swung it 0.20.

perspective is retired, and binding it is a load error that names distance and fov. An old preset moves onto the camera by an exact mapping, with E the entry’s depth half-extent in figure radii and p the old value: distance = E / p, tan(fov / 2) = p / (scale * E * zoom) with the camera’s zoom left at 1, and pitch = 0. A preset that sat at perspective = 0 takes a long distance and a matching narrow fov — the shipped fragment_sumi layer uses distance = 20, fov = 0.13 — which is as near to orthographic as the camera goes.

focus and aperture act on the camera’s real lens. focus places the focal plane in the figure’s depth, 0 at its nearest point and 1 at its farthest; aperture is the blur of the far side in pixels, and a sprite off the focal plane draws wider and dimmer, so its light stays the same. A sprite’s size is stated at the figure’s centre, so moving focus never resizes one; nearer sprites draw larger and farther ones smaller, as nearer material should.

fog darkens a sprite with its depth, on the scale focus uses: at 1 the figure’s farthest point is black and its nearest keeps all its light, and 0 is off. It takes light and never size, at the particle’s own depth, so the trace behind a particle keeps the light it had where it was. Its scale is the figure brought to unit radius, so it reads the same on every roster entry. depth_fade is the older cue on the same idea, measured on the entry’s depth half-extent; the two multiply. solid is not an attractor parameter: a sprite has no line to paint over another.

The camera, depth_fade and depth_hue are exact no-ops on every flat family, the same way a b c d already carry family-specific meanings. On de_jong, clifford and the five IFS figures they are exactly the identity: those maps have no third coordinate, so they keep their in-plane path and every depth cue collapses to a no-op. Binding them there is not an error and produces no warning — it produces nothing at all. (Verified by capture: at any setting, zero pixels differ — asserted in core/tests/attractor.rs.)

depth_fade is a no-op on a flat family too, and the arithmetic is why it once was not (design-backlog 0067). The haze is 1 − depth_fade · (1 − depth01(dn)), and a flat family’s dn ≡ 0 would put the multiplier at 1 − depth_fade/2, so depth_fade = 0.9 would dim a flat figure 45 % everywhere with no depth gradient (measured on attractor_dissolve: 20.1 % of pixels moved, max channel delta 97, while depth_hue moved zero). The fade term is now multiplied by the family’s has-depth flag, so all three cues are the identity together. If an old draft leaned on the dimming as an undocumented brightness trim on a flat family, it silently brightened back — exposure is the parameter that means “dimmer” and says so.

spin is the exception and reaches every family. The flat ones rotate in-plane through the same angle, so an audio-driven spin is a real look on De Jong today, and a fern that rocks a couple of degrees either side of upright reads as wind. That asymmetry is deliberate; do not read it as an oversight.

ParamWhat it doesRange that means something
distanceHow far the camera sits from the figure’s centre, in figure radii. Nearer exaggerates the perspective: near material grows and far material shrinks, position and sprite size together.1.5 .. 8; the shipped 3-D presets run from 1.5 (Plexus Cyanotype at its nearest; Lorenz Knot reaches 1.52 on a bass hit) to 5. The range documents and does not clamp
fovThe vertical field of view, in radians. A narrow fov at a long distance flattens the figure toward orthographic.0.2 .. 2
depth_fadeAttenuates brightness with distance — the substitute for occlusion, which this scene does not do. 1 takes the far end to black.0 (off) .. 1
depth_hueShifts the palette coordinate by ±depth_hue/2 across the depth range, so distance moves colour as well as contrast — on a ramp that travels in hue at roughly constant lightness. On a dark-to-light ramp (which is what the 3-D presets have shipped) it duplicates depth_fade instead, and under ink_amount = 1 it is structurally dead, like saturation. design-backlog 00620 (off) .. 2 * min(hue_center, 1 - hue_center), past which the offset wraps on the LUT’s repeat sampler and far material lands on the near colour
spinRate multiplier on the display rotation. 1 is unchanged, 0 holds the figure still, negative reverses it.any

Four things you cannot discover by binding them:

  • The near-to-far magnification is set by distance alone. A figure of radius 1 seen from distance D magnifies its near side over its far side by (D + 1) / (D - 1): 3 gives 2:1, 2 gives 3:1, and 1.5 gives 5:1. fov and zoom change how large the whole figure is, not that ratio, so to keep a figure’s size while deepening it, shorten distance and widen fov together.
  • spin turns the figure, yaw places the camera, and they add. The spin phase is subtracted from yaw, so a positive spin turns the figure the same way it always has, and a fixed yaw offsets where the turn starts.
  • spin is a multiplier on 0.18 rad/s (spin = 1 is one revolution per 34.9 seconds), and its usable ceiling is set by fade, not by taste — spin and fade are one look. A frame of trail drawn while the figure turns is a frame of rotational smear: push the pair too far and the accumulation stops being a trace of the trajectory and becomes concentric arcs, which destroys exactly the volume the camera is there to show. Measured: at fade = 0.932 (~15 frames of trail) the rendered ladder 1 / 2 / 3 / 5 / 8 reads crisp, crisp, softening, smeared, scribble — usable peak about 1.9; at fade = 0.955 (~22 frames, what the retired Thomas ran) the ceiling is correspondingly lower, about 1.3. The arithmetic agrees: holding the smear under ~5° needs rate < 0.087 / (frames / 60) rad/s, so the ceiling falls as fade rises. (This bullet used to say 2–4 is where the rotation becomes legible — true for a trail-free scene, wrong for every attractor preset that ships; design-backlog 0063.) The phase is integrated, so a spin bound to audio accelerates the figure rather than snapping it to a new angle — but the integration fixes the discontinuity, not the range: a wide binding like 1 + bass * 5 swings the figure through most of a revolution between transients and reads as tumbling, not drive. The 3-D presets have modulated narrowly (the since-retired Lorenz 1.0–1.8, Thomas 1.0–1.3).
  • The illusion has a density limit and haze does not remove it. Nothing occludes anything here — two strands crossing simply sum — so as [particles] density rises the figure reads more and more as X-ray whatever these are set to. If depth stops reading, lower density before shortening distance, and try a pitch that separates the strands.

Built from f4f807a at version 0.178.0. This site tracks main and is not versioned per release.