Restore missing required asset/flow packages from the pinned nigig revision; retain upstream script isolation, X11 hover, and widget-core fixes. Validated makepad-widgets data feature with Rust 1.97.1.
99 lines
4 KiB
Text
99 lines
4 KiB
Text
// FRACTAL DESCENT — a kaleidoscopic-IFS fractal orbited in the dark, its
|
|
// fold angle WANDERING with the beat count so the shape never repeats.
|
|
// Pattern taught: an iterated fold (abs + rotate + scale-out) inside a
|
|
// scene_sdf subclass — five iterations, own constants; the marcher, AO and
|
|
// palette all come free from the base shader. `p0` binds extra fold angle.
|
|
//
|
|
// THE LAW THIS DOCUMENT LEARNED THE HARD WAY: a shader that is a function
|
|
// of `beat` must be a BOUNDED one. `beat` is the host's SONG clock, not a
|
|
// stopwatch that starts when the effect loads — cue this into a deck an
|
|
// hour into a set and the first frame is at beat 6000. The original fold
|
|
// angle was `0.52 + beat * 0.010`, an unbounded creep: lovely for the ten
|
|
// seconds a gallery grab ever sees, and by beat ~120 the IFS attractor has
|
|
// escaped the marcher and the deck shows BLACK. So the wander here is two
|
|
// slow sines with an irrational-ish frequency ratio (quasi-periodic — it
|
|
// still never repeats) clamped into the band where the attractor is a
|
|
// picture, and the FOLD dial is centred on 0.5 so no knob can leave it.
|
|
{
|
|
name: "Fractal Descent"
|
|
engine: "raymarch"
|
|
|
|
steps: 84
|
|
max_dist: 30.0
|
|
cam: "orbit"
|
|
cam_speed: 0.14
|
|
cam_dist: 3.6
|
|
cam_height: 1.0
|
|
cam_fov: 62.0
|
|
shadow: 1
|
|
|
|
beat_pulse: "0.6 * (0.2 + 1.6*p2)"
|
|
beat_rate: 1.0
|
|
fog: 0.05
|
|
glow: "1.45 * (0.25 + 1.5*p1)"
|
|
// FOLD is knob-shaped: 0.5 is neutral, the binding breathes around it
|
|
// over the bar, and the scene reads it as an OFFSET from centre.
|
|
p0: "0.5 + 0.16 * sin(bar * tau)"
|
|
|
|
// PERFORMANCE DIALS — FOLD is this doc's own p0 lever (the scene hook
|
|
// reads self.user.x; touching it holds the fold open); GLOW and PUMP
|
|
// route p1/p2. Mid-knob = the stock look, exact.
|
|
p1: 0.5 p2: 0.5
|
|
dials: [
|
|
{name: "FOLD", bind: "p0", default: 0.5},
|
|
{name: "GLOW", bind: "p1", default: 0.5},
|
|
{name: "PUMP", bind: "p2", default: 0.5}
|
|
]
|
|
|
|
color_bg: #x05040f
|
|
color_a: #x8f4dff
|
|
color_b: #x0fd0c8
|
|
color_c: #xf0eaff
|
|
|
|
stages: [
|
|
{kind: "bloom", threshold: 0.5, strength: 1.35, levels: 3}
|
|
]
|
|
|
|
shader: draw.DrawVjFxRaymarch {
|
|
scene_sdf: fn(p: vec3) -> vec2 {
|
|
// Kaleidoscopic IFS: fold into the positive octant, then TWO
|
|
// rotations (xz and yz — the second is what lifts the fractal
|
|
// out of a flat extrusion), scale outward. Own constants.
|
|
let mut z = p * 0.72
|
|
let k = 1.84
|
|
let off = vec3(1.18, 0.62, 1.34)
|
|
// The fold angle WANDERS but never escapes: two slow sines of
|
|
// the beat count (periods ~153 and ~370 beats, ratio not a
|
|
// simple fraction, so the pair never quite comes back around)
|
|
// plus the FOLD dial as a signed offset from mid-knob. The
|
|
// clamp is the guarantee — outside roughly 0.2..0.9 the
|
|
// attractor either collapses or runs off past `max_dist`, and
|
|
// the picture goes black.
|
|
let b = self.time_beat.y
|
|
let wander = 0.14 * sin(b * 0.041) + 0.08 * sin(b * 0.017 + 2.3)
|
|
let fold = (self.user.x - 0.5) * 0.24
|
|
let ang = clamp(0.54 + wander + fold, 0.20, 0.90)
|
|
let mut s = 0.72
|
|
let mut trap = 10.0
|
|
let mut i = 0.0
|
|
loop {
|
|
if i > 5.5 {
|
|
break
|
|
}
|
|
z = abs(z)
|
|
let r = self.rot2(vec2(z.x, z.z), ang)
|
|
z = vec3(r.x, z.y, r.y)
|
|
let r2 = self.rot2(vec2(z.y, z.z), 0.61 - ang * 0.35)
|
|
z = vec3(z.x, r2.x, r2.y)
|
|
z = z * k - off * (k - 1.0)
|
|
s = s * k
|
|
// Orbit trap: nearest approach to the origin, in world
|
|
// scale — the palette rides the fractal's onion layers.
|
|
trap = min(trap, length(z) / s)
|
|
i = i + 1.0
|
|
}
|
|
let d = self.sd_box(z, vec3(0.90, 0.90, 0.90)) / s
|
|
return vec2(d * 0.82, fract(trap * 2.6))
|
|
}
|
|
}
|
|
}
|