mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
Nine concepts to the owner's mockup, grey on true black, the subject right
of centre and the left 40% kept dark for a card's words: Enso a brushed
ensÅ shedding particles over water and mist, Kai three panes of glass
threaded by falling light, Zen a sphere in raked sand, Iro mountains and
cloud spilling out of a frame, Koma film frames running into depth, Oto a
mirrored waveform, Koe twisting ribbons, Uta a fan rising over strings,
Mori a wireframe peak.
Each is one fragment shader over film/models/gl.js, a pure function of the
loop's phase, so the frame after the last is the first. film.mjs steps it
on the GPU, refuses a seam, and cuts public/models/<name>.{webp,webm,mp4}:
1200x1500 for every model and a 1500x1500 Enso, 30 fps, each loop under
700 KB. Frames stay in film/models/frames (ignored).
80 lines
3.1 KiB
HTML
80 lines
3.1 KiB
HTML
<!doctype html>
|
|
<html data-seconds="6">
|
|
<meta charset="utf-8" />
|
|
<title>Oto</title>
|
|
<style>html,body{margin:0;background:#000}canvas{display:block}</style>
|
|
<body>
|
|
<canvas></canvas>
|
|
<!--
|
|
Oto: a sound drawn as its waveform, thin bars mirrored about one line,
|
|
tallest and brightest at the centre and falling away to either side, with
|
|
a fine spray of points over the loudest. In the loop the bars rise and fall
|
|
to a few slow beats, every one of them back where it began.
|
|
-->
|
|
<script type="x-shader/x-fragment">
|
|
// A bar's loudness, -1..1 of its reach, at the loop's phase: a few beats that each turn a whole number of times.
|
|
float level(float n){
|
|
float a = 0.;
|
|
a += .55 * sin(TAU * (P * 1. + h11(n * .37 + 1.) ));
|
|
a += .3 * sin(TAU * (P * 2. + h11(n * .71 + 5.) ));
|
|
a += .2 * sin(TAU * (P * 3. + n * .11));
|
|
return .42 + .58 * abs(a) / 1.05;
|
|
}
|
|
|
|
float scene(vec2 f){
|
|
vec2 c = vec2(.645 * R.x, .5 * R.y);
|
|
float pitch = R.y * .0064;
|
|
float x = f.x - c.x;
|
|
float y = abs(f.y - c.y);
|
|
float reach = R.y * .26;
|
|
float L = 0.;
|
|
float i0 = floor(x / pitch + .5);
|
|
for (int k = -2; k <= 2; k++) {
|
|
float n = i0 + float(k);
|
|
float side = R.y * .27;
|
|
float u = n * pitch / side;
|
|
if (abs(u) > 1.25) continue;
|
|
// Tallest at the centre, a little uneven, falling to nothing at the ends.
|
|
float env = exp(-pow(u / .5, 2.)) * .9 + .1 * exp(-pow(u / 1., 2.));
|
|
env *= .8 + .2 * h11(n * 1.9);
|
|
float hgt = reach * env * level(n) + 2.;
|
|
float dx = abs(x - n * pitch);
|
|
float w = .9 + .5 * env;
|
|
float core = 1. - smoothstep(w - .5, w + .5, dx);
|
|
// Brightest at the waist, dimming toward the tips, the tips themselves catching light.
|
|
float along = y / max(hgt, 1.);
|
|
float inBar = 1. - smoothstep(hgt - .8, hgt + .8, y);
|
|
float lit = (.4 + .95 * env) * mix(1.25, .4, along);
|
|
L += core * inBar * lit;
|
|
// A point of light just past each tip.
|
|
float tip = length(vec2(dx, y - hgt - 5.)) ;
|
|
L += exp(-tip * tip / 2.5) * .5 * env;
|
|
// The glow of the loud ones.
|
|
L += exp(-dx / 7.) * inBar * .06 * env;
|
|
L += exp(-length(vec2(dx, y)) / (R.y * .03)) * .05 * env;
|
|
}
|
|
// The axis the sound is mirrored about.
|
|
L += (1. - smoothstep(.3, 1.2, abs(f.y - c.y))) * .25 * smoothstep(-R.y * .34, -R.y * .2, x) * (1. - smoothstep(R.y * .2, R.y * .34, x));
|
|
// A spray of points over the loudest, rising and fading, mirrored.
|
|
vec2 g = vec2(x, y) / (R.y * .012);
|
|
vec2 id = floor(g);
|
|
for (int j = -1; j <= 1; j++) for (int k = -1; k <= 1; k++) {
|
|
vec2 cid = id + vec2(k, j);
|
|
vec2 h = h22(cid + 3.);
|
|
if (h.x > .3) continue;
|
|
float life = fract(P * (1. + floor(h.y * 2.)) + h.y * 5.);
|
|
vec2 pt = (cid + h22(cid)) * R.y * .012 + vec2(0., life * R.y * .03);
|
|
float u = pt.x / (R.y * .27);
|
|
float near = exp(-pow(u / .35, 2.)) * smoothstep(reach * .55, reach * .9, pt.y) * (1. - smoothstep(reach * .95, reach * 1.2, pt.y));
|
|
float d = length(vec2(x, y) - pt);
|
|
L += near * sin(PI * life) * exp(-d * d / 1.8) * .9;
|
|
}
|
|
// The left of the frame is the words': keep it dark.
|
|
L *= mix(.1, 1., smoothstep(.22, .45, f.x / R.x));
|
|
return pow(tone(L * 1.15), .9);
|
|
}
|
|
</script>
|
|
<script src="./gl.js"></script>
|
|
</body>
|
|
</html>
|