makepad/apps/vj/resources/effects/267_bass_warp_drape.splash
Admin cb49b032df vjfx: 104 presets, engine hooks + hold stage, the videomesh engine, the audio picture, livecodable effects, and mp4 thumbnail sheets
Squashed from work; the fine-grained history is under tag archive/work-2026-08-26:
- vjfx: 104 new presets — the transition lane fills out and the screen family goes wide
- vjfx: three lanes land — engine hooks + hold stage, the videomesh engine, and the audio picture
- vj: the thumbnail pipeline becomes one honest machine, and effects go livecodable
- vj: thumbnails become mp4 — hardware-coded sheets at measured-4K cells, and the bake stops racing the GPU
- store: the ceremony dies — batch publish, one transaction, and the engine stops re-reading its own log
- store: the ceremony dies — batch publish, one transaction, and the engine stops re-reading its own log
- vj: the console grows real transports, and the deck stops lying about reverse
- vj: reverse earns a memory, and the effects stop aging
- fab: a 3D creation shell and the viewer built on it
2026-08-26 08:49:48 +02:00

101 lines
4.2 KiB
Text

// BASS WARP DRAPE — the CONTENT preset of this set: the channel's live
// video, hung on the sound. The low end pumps a radial push-and-pull, the
// mids ripple the surface horizontally, and the last seconds of spectrum
// hang down the right edge as a strip you can read the track from.
//
// This is the one to copy when an author wants audio to SHAPE the clip
// rather than replace it. `content` is the pre-gated strength: it is 0
// whenever the runtime's animated stand-in is bound instead of real deck
// video, so the look reads the fallback and lifts it instead of pretending.
{
name: "Bass Warp Drape"
engine: "screen"
seed: 29
input0: "test"
content: 1.0
speed: 1.0
beat_pulse: 0.7
beat_rate: 1.0
bar_beats: 4
glow: 1.0
p0: 0.5 p1: 0.5 p2: 0.5
dials: [
{name: "PUMP", bind: "p0", default: 0.5},
{name: "RIPPLE", bind: "p1", default: 0.5},
{name: "STRIP", bind: "p2", default: 0.5}
]
color_bg: #x04040a
color_a: #x39e6ff
color_b: #xff4f6e
color_c: #xfff0cc
stages: [
{kind: "bloom", threshold: 0.65, strength: 0.9, levels: 3}
]
shader: draw.DrawVjFxScreen {
fx_color: fn(uv: vec2, content: vec4, cmix: float) -> vec4 {
let aspect = 16.0 / 9.0
let p = vec2((uv.x - 0.5) * aspect, uv.y - 0.5)
let r = length(p)
// PUMP: the low end squeezes the frame in and out about centre.
let bass = self.audio_env.x
let pump = (0.02 + 0.18 * clamp(self.user.x, 0.0, 1.0))
* (bass - 0.25 + 0.35 * self.time_beat.w)
// RIPPLE: mids as travelling horizontal waves, their phase from
// the waveform so the ripple is the actual signal, not a sine.
let rip = (0.004 + 0.030 * clamp(self.user.y, 0.0, 1.0))
* self.audio_wave(clamp(uv.y * 0.5 + 0.5, 0.0, 1.0))
* (0.35 + self.audio_env.y)
let dir = p / max(r, 0.0006)
let warped = clamp(
vec2(uv.x - dir.x * pump * 0.6 + rip, uv.y - dir.y * pump),
vec2(0.0, 0.0),
vec2(1.0, 1.0)
)
// Highs split the channels a hair — a cheap sparkle that only
// shows when there is actually top end in the room.
let sp = 0.006 * self.audio_env.z
let cr = self.tex0.sample_as_bgra(clamp(warped + vec2(sp, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0)))
let cg = self.tex0.sample_as_bgra(warped)
let cb = self.tex0.sample_as_bgra(clamp(warped - vec2(sp, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0)))
let mut rgb = vec3(cr.x, cg.y, cb.z)
// Without real content the stand-in is all there is: lift it so
// the gallery tile still reads (the dead-air law).
let lift = 1.0 + (1.0 - clamp(cmix, 0.0, 1.0)) * 0.30
rgb = rgb * lift
// A spectrum wash over the picture: warm where the band that
// owns this screen height is loud.
let f = clamp(1.0 - uv.y, 0.0, 1.0)
let band = self.audio_fft(f, 0.0)
rgb = rgb + self.col_a.xyz * (band * 0.16)
// THE STRIP: the last seconds of spectrum standing on the right
// edge — x inside the strip is time, y is frequency.
let sw = 0.03 + 0.16 * clamp(self.user.z, 0.0, 1.0)
if uv.x > 1.0 - sw {
let age = clamp((1.0 - uv.x) / max(sw, 0.001), 0.0, 1.0)
let v = self.audio_fft(clamp(1.0 - uv.y, 0.0, 1.0), age)
let idle = 0.05 + 0.04 * sin(uv.y * 30.0 - self.time_beat.x * 1.6)
let m = max(v, idle)
let tint = self.col_a.xyz.mix(self.col_b.xyz, m)
rgb = rgb.mix(self.col_bg.xyz, 0.55)
rgb = rgb + tint * (m * 1.4)
}
// The seam: a hot line where the strip meets the picture.
rgb = rgb + self.col_c.xyz
* (exp(0.0 - abs(uv.x - (1.0 - sw)) * 420.0) * (0.25 + 0.6 * self.audio_env.w))
// A beat vignette that grips the frame on the downbeat.
let vig = 1.0 - (0.18 + 0.22 * self.time_beat.w) * smoothstep(0.3, 0.95, r)
return vec4(rgb * vig * self.fog.y, 1.0)
}
}
}