makepad/apps/vj/resources/effects/93_midnight_metropolis.splash
Admin f44616b2a7 makepad-vj effects: the effect renderstack, with the shaders inside the documents
The VJ's EFFECT surface is a small renderer of its own. An effect is a
`.splash` DOCUMENT — engine choice, stages, fields, parameters and now the
SHADERS THEMSELVES live in the document rather than in Rust. That is the
shape this commit introduces (dev has never seen an intermediate one): a
document is the whole effect, and the Rust side is the engine families that
documents draw with.

The engine families: particles and emitters, GPU sim swarms and fluid, static
meshes (firefly synchrony, harmonograph loom, domino liturgy), tiles, flock,
clouds, city, pipes, stock charts, an SDF raymarcher with a subclassable
`scene_sdf`, and a mountain-jet endless range with a beat-pulsed fighter.

Three things make them a system rather than a demo reel:

  - SIM FIELDS — a float simulation-texture primitive, so an engine can carry
    GPU state across frames (wind, particles, fluid) instead of being a pure
    function of the clock.
  - CONTENT COUPLING — `content:` in a document and `input0` on every engine's
    tex0, so an effect can consume the program video: drapes, backdrops,
    mirrors, billboards, chrome, frescoes, canopy, glass, silk, wall, swarm,
    pen and mosaic families all take the picture playing behind them.
  - MUSIC BINDING — shaders read the beat, so the whole library moves with the
    track rather than on its own clock.

Roughly a hundred seeded preset documents ship with it, each with a lazily
rendered animated thumbnail (rendered 4x and box-downscaled, 16-tap SSAA);
the thumbnail pass went from four minutes to eleven seconds. CONTRACT.md is
the document contract and its verify recipe; IDEAS.md is the campaign tracker.
2026-08-23 01:35:44 +02:00

76 lines
2.9 KiB
Text

// MIDNIGHT METROPOLIS — a realistic night city flown over by a slow
// banking camera. The whole city is one static mesh; every lit window is
// pixel math on the facade uv (baked in window units), and each beat a
// fraction of the windows re-roll their state: hash(tower, window,
// floor(beat)) — the city itself flickers in tempo. Rooftop beacons blink
// on tall towers, and the tiltshift stage turns the blocks into a
// miniature. Pattern taught: the city engine's camera is engine-authored
// (a Lissajous drift with view-space banking) — cam_* keys don't steer it,
// `alt`/`fly`/`bank` do.
//
// SCALE: `blocks` is the DEPTH dial. The drift radius, the look-ahead, the
// ground and the sky all scale with the city's half-extent, so raising the
// block count at a FIXED `block` pitch keeps the near field exactly as it
// framed and adds rows RECEDING TO THE HORIZON — 18 blocks is ~1060 towers,
// four times the old nine-block cluster, and the fog is thinned to match so
// the far rows read as a dim glittering skyline instead of being eaten.
{
name: "Midnight Metropolis"
engine: "city"
seed: 12
style: "night"
blocks: 18
block: 6.0
street: 0.32
towers: 1100
max_h: 11.0
win: 0.30
density: 0.52
flicker: 0.14
alt: 12.5
fly: 1.1
bank: 1.2
beat_pulse: 0.35
p0: "0.05 + 0.10*energy" // the city wakes up with the music
p2: 0.6 // beacon gain
// PERFORMANCE DIALS — the city engine's own p-levers: DENS lights
// extra windows (touching it holds the energy binding), RUSH scrubs
// the window re-roll front forward, BEACON gains the rooftop blinks.
dials: [
{name: "DENS", bind: "p0", default: 0.1},
{name: "RUSH", bind: "p1", default: 0.0},
{name: "BEACON", bind: "p2", default: 0.6}
]
color_bg: #x060a18
color_a: #x36405c
color_b: #x141a30
color_c: #xffe6b0
fog: 0.015
glow: 1.15
stages: [
{kind: "bloom", threshold: 0.55, strength: 1.0, levels: 2},
{kind: "tiltshift", focus: 0.62, width: 0.30, levels: 2}
]
// THE LOOK LIVES HERE. This block is not a reference to the
// engine's shader — it IS the pixel math this effect runs.
// Rewrite it and the effect looks different; everything else
// (geometry, motion, the content coupling, the beat) keeps
// working, because the block SUBCLASSES the engine shader.
// Inputs: t = height 0..1, attr = (class, id, hash, height/phase).
// Signals: self.time_beat (time, beat, phase, pulse),
// self.sig (bar, bpm, energy, dt), self.user (p0..p3),
// self.col_a/b/c/bg, self.fog (density, glow, content, -).
shader: draw.DrawVjFxCity {
fx_color: fn(t: float, attr: vec4, normal: vec3, wpos: vec3) -> vec4 {
let v = 0.8 + 0.4 * attr.z
return self.col_a.mix(self.col_b, clamp(t * 0.8 + attr.z * 0.3, 0.0, 1.0)) * v
}
}
}