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).
64 lines
2.4 KiB
HTML
64 lines
2.4 KiB
HTML
<!doctype html>
|
|
<html data-seconds="6">
|
|
<meta charset="utf-8" />
|
|
<title>Uta</title>
|
|
<style>html,body{margin:0;background:#000}canvas{display:block}</style>
|
|
<body>
|
|
<canvas></canvas>
|
|
<!--
|
|
Uta: a crescendo. A fan of fine lines leaves one point low on the left and
|
|
rises, curving ever more steeply, to the right, spreading as it climbs;
|
|
under it stand the strings, each reaching up to the lowest line. In the
|
|
loop the fan sways and a light runs up the strings, left to right.
|
|
-->
|
|
<script type="x-shader/x-fragment">
|
|
const int N = 46;
|
|
|
|
float scene(vec2 f){
|
|
float H = R.y;
|
|
vec2 o = vec2(.42 * R.x, .76 * H);
|
|
float span = R.x * .98 - o.x;
|
|
float u = (f.x - o.x) / span;
|
|
float L = 0.;
|
|
float lowest = 1e9;
|
|
if (u > -.02) {
|
|
float uc = max(u, 0.);
|
|
for (int i = 0; i < N; i++) {
|
|
float t = float(i) / float(N - 1);
|
|
float sway = .035 * sin(TAU * (P + t * .6));
|
|
float a = mix(.07, .8, pow(t, 1.1)) + sway;
|
|
float pw = mix(2.3, 1.35, t);
|
|
float yi = o.y - H * .64 * a * pow(uc, pw);
|
|
float dy = H * .64 * a * pw * pow(max(uc, 1e-4), pw - 1.) / span;
|
|
float d = abs(f.y - yi) / sqrt(1. + dy * dy);
|
|
lowest = min(lowest, yi);
|
|
// Dense at the root, so dimmer there; each line brightest as it climbs.
|
|
float bright = (.28 + .5 * pow(t, 1.5)) * smoothstep(.0, .25, uc) * (1. - smoothstep(1., 1.03, uc));
|
|
L += bright * (1. - smoothstep(.25, 1.05, d)) + exp(-d / 4.) * .02 * bright;
|
|
}
|
|
// The root, where every line leaves from.
|
|
L += exp(-length(f - o) / (H * .012)) * .5;
|
|
}
|
|
// The strings, each standing up to the lowest line, a light running up them in turn.
|
|
float pitch = H * .011;
|
|
float sx = f.x - (o.x + span * .22);
|
|
if (sx > 0. && f.x < R.x * .985) {
|
|
float n = floor(sx / pitch + .5);
|
|
float dx = abs(sx - n * pitch);
|
|
float uu = (n * pitch + span * .22) / span;
|
|
float sway = .035 * sin(TAU * P);
|
|
float top = o.y - H * .64 * (.07 + sway) * pow(uu, 2.3) + 6.;
|
|
float bottom = o.y + H * .06;
|
|
float on = smoothstep(top, top + 10., f.y) * (1. - smoothstep(bottom - 30., bottom, f.y));
|
|
float run = exp(-pow(fract(uu * 1.5 - P * 2.) - .5, 2.) * 40.);
|
|
L += (1. - smoothstep(.3, .9, dx)) * on * (.22 + .5 * run) * smoothstep(.0, .2, uu);
|
|
}
|
|
// 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.2), .9);
|
|
}
|
|
</script>
|
|
<script src="./gl.js"></script>
|
|
</body>
|
|
</html>
|