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).
86 lines
3.0 KiB
HTML
86 lines
3.0 KiB
HTML
<!doctype html>
|
|
<html data-seconds="8">
|
|
<meta charset="utf-8" />
|
|
<title>Mori</title>
|
|
<style>html,body{margin:0;background:#000}canvas{display:block}</style>
|
|
<body>
|
|
<canvas></canvas>
|
|
<!--
|
|
Mori: a mountain as a mesh. A heightfield peak, ridged and broken, drawn as
|
|
its wireframe only — dense lines along one axis, sparser across — lit
|
|
brightest at the summit and falling away into the dark at its foot. In the
|
|
loop the terrain turns slowly one way and back.
|
|
-->
|
|
<script type="x-shader/x-fragment">
|
|
float terrain(vec2 p){
|
|
float r = length(p);
|
|
float peak = 1.6 * exp(-pow(r / .9, 1.45));
|
|
// Ridges running down from the summit, and a broken surface over everything.
|
|
float ridged = 0., a = .5, fr = .9;
|
|
vec2 q = p;
|
|
for (int k = 0; k < 4; k++) {
|
|
float n = 1. - abs(gn(q * fr + 3.7));
|
|
ridged += a * n * n;
|
|
q = mat2(.8, .6, -.6, .8) * q;
|
|
fr *= 2.; a *= .5;
|
|
}
|
|
float shoulder = .35 * exp(-dot(p - vec2(1.1, .5), p - vec2(1.1, .5)) / .5) + .25 * exp(-dot(p + vec2(.9, -.8), p + vec2(.9, -.8)) / .6);
|
|
float base = exp(-r * r / 4.5);
|
|
return peak * (.72 + .28 * ridged) + shoulder * (.6 + .4 * ridged) + .12 * ridged * base;
|
|
}
|
|
|
|
float scene(vec2 f){
|
|
vec2 uv = (f - vec2(.64 * R.x, .56 * R.y)) / R.y;
|
|
uv.y = -uv.y;
|
|
// The slow turn: one way and back, once a loop.
|
|
float yaw = .55 + .2 * sin(TAU * P);
|
|
vec3 target = vec3(0., .55, 0.);
|
|
float el = radians(25.);
|
|
vec3 eye = target + 9.5 * vec3(sin(yaw) * cos(el), sin(el), -cos(yaw) * cos(el));
|
|
vec3 fw = normalize(target - eye);
|
|
vec3 rt = normalize(cross(vec3(0, 1, 0), fw));
|
|
vec3 up = cross(fw, rt);
|
|
vec3 rd = normalize(fw * 1.75 + rt * uv.x + up * uv.y);
|
|
float L = 0.;
|
|
// March the heightfield.
|
|
float t = 2.;
|
|
float hit = -1.;
|
|
for (int i = 0; i < 220; i++) {
|
|
vec3 p = eye + rd * t;
|
|
float d = p.y - terrain(p.xz);
|
|
if (d < .001 * t) { hit = t; break; }
|
|
t += max(d * .45, .004);
|
|
if (t > 22.) break;
|
|
}
|
|
if (hit > 0.) {
|
|
// Refine the crossing.
|
|
float lo = hit - .02, hi = hit;
|
|
for (int i = 0; i < 8; i++) {
|
|
float mid = (lo + hi) * .5;
|
|
vec3 p = eye + rd * mid;
|
|
if (p.y - terrain(p.xz) < 0.) hi = mid; else lo = mid;
|
|
}
|
|
vec3 p = eye + rd * hi;
|
|
float h = terrain(p.xz);
|
|
// The mesh: dense lines across, sparser along, as thin as a pixel wherever they fall.
|
|
vec2 g = p.xz * vec2(16., 6.);
|
|
vec2 w = fwidth(g);
|
|
vec2 a = abs(fract(g - .5) - .5) / max(w, 1e-4);
|
|
float wire = max(1. - smoothstep(.2, 1.1, a.y), .55 * (1. - smoothstep(.2, 1.1, a.x)));
|
|
// Fade the mesh where its lines crowd past seeing, at a grazing angle or far away.
|
|
float crowd = 1. - smoothstep(.35, .9, max(w.x, w.y));
|
|
float r = length(p.xz);
|
|
float lit = (.1 + 1.25 * smoothstep(.05, 1.5, h)) * exp(-r * r / 5.);
|
|
L = wire * crowd * lit * 1.6;
|
|
// A faint skin, so the near slopes hide the far ones.
|
|
L += .025 * lit;
|
|
}
|
|
// The left of the frame is the words': keep it dark.
|
|
L *= mix(.08, 1., smoothstep(.22, .48, f.x / R.x));
|
|
return pow(tone(L * 1.1), .9);
|
|
}
|
|
</script>
|
|
<script src="./gl.js"></script>
|
|
</body>
|
|
</html>
|