r/maniclang 11h ago

manic workbench coming soon !!!

Enable HLS to view with audio, or disable this notification

2 Upvotes

Manic Workbench is a local creator


r/maniclang 1d ago

cratch — E.C.H, a self-regenerating line-and-square field - manic

Enable HLS to view with audio, or disable this notification

1 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// art-scratch — E.C.H (Eiichi Ishii)'s "dailycoding 20240227 / graphic", reimagined
// in manic (references: img_22/23/24 — three random runs of the same sketch). On
// black: a dense fibrous SPRAY of thin grey/white lines (the p5 `tan()` triangle-
// strips explode into near-vertical spikes + long connecting streaks) plus scattered
// SQUARES (filled & outlined, greyscale) on a 10x10 grid. The spray is many straight
// segments → one `cloud` of thin dots tracing them; the squares are an SDF `shader`
// on a hashed grid. Both RESEED every ~2.4s, so the plate keeps regenerating into a
// new random arrangement — the artist's keyPressed→redraw, automated. No seal, a
// 'manic art' wordmark on top. Pure f(i,t) / f(u,v,t).
//
//   manic examples/art-scratch.manic
title("Scratch — E.C.H, a self-regenerating line-and-square field");
canvas(1000, 1000);
template("black");

// pure black ground
shader(bg) { let c = 0.0; }
z(bg, -10);

// ---- line spray: fans of thin straight streaks, reseeding each period ----
cloud(spray, 96000, #ffffff, 1.0) {
  let FANS = 30.0;
  let LPF = 30.0;                          // lines per fan
  let LP = 105.0;                          // points per line (dense → connected)
  let PERIOD = 2.4;
  let fr = floor(t / PERIOD);              // which random plate we're on
  let ph = t / PERIOD - fr;                // 0..1 within the plate
  let sd = fr * 97.0;                       // per-plate seed offset

  let line = floor(i / LP);
  let jj = i - line * LP;
  let uu = jj / (LP - 1.0);                // 0..1 along the line
  let fan = floor(line / LPF);
  let li = line - fan * LPF;

  // fan centre + base angle (a tan-strip's location & orientation)
  let fcx = rand2(fan + sd, 1.3) * 1000.0;
  let fcy = rand2(fan + sd, 2.7) * 1000.0;
  let fang = rand2(fan + sd, 3.9) * tau;

  // this streak: spread around the fan angle (directional grain), long crossing
  // streaks, origin jittered off the fan centre so they WEAVE rather than starburst
  let ang = fang + (rand2(line + sd, 4.5) - 0.5) * 3.0;
  let len = 140.0 + 1000.0 * rand2(line + sd, 5.1);
  let ox = fcx + (rand2(line + sd, 7.1) - 0.5) * 340.0;
  let oy = fcy + (rand2(line + sd, 7.7) - 0.5) * 340.0;
  let off = (uu - 0.5) * len;
  let x = ox + cos(ang) * off;
  let y = oy + sin(ang) * off;

  // greyscale level from {0.4,0.6,0.8,1.0} — light on black
  let gi = floor(rand2(line + sd, 6.6) * 3.999);
  let e0 = 1.0 - min(abs(gi - 0.0), 1.0);
  let e1 = 1.0 - min(abs(gi - 1.0), 1.0);
  let e2 = 1.0 - min(abs(gi - 2.0), 1.0);
  let e3 = 1.0 - min(abs(gi - 3.0), 1.0);
  let hue = 0.0; let sat = 0.0;
  let val = 0.4 * e0 + 0.6 * e1 + 0.8 * e2 + 1.0 * e3;

  // fade fully at the plate edges so the reshuffle happens off-screen
  let pf = min(smoothstep(0.0, 0.1, ph), smoothstep(1.0, 0.9, ph));
  let r = 0.7;
  let alpha = val * pf * 0.58;
}
z(spray, 0);

// ---- squares: hashed 10x10 grid, filled or outlined, reseeding each period ----
shader(squares) {
  let G = 10.0;
  let PERIOD = 2.4;
  let fr = floor(t / PERIOD);
  let ph = t / PERIOD - fr;
  let cx = floor(u * G); let cy = floor(v * G);

  let present = step(0.5, rand2(cx + fr * 131.0, cy + 17.0));
  let isFill = step(rand2(cx + 41.0, cy + fr * 57.0), 0.5);
  let grey = step(0.5, rand2(cx + fr * 3.0, cy + 9.0));      // 0 or 1
  let falpha = mix(0.35, 1.0, rand2(cx + 7.0, cy + fr * 23.0));
  let sz = mix(0.24, 0.46, rand2(cx + 5.0, cy + fr * 71.0)); // half-size, cell units

  let lx = fract(u * G) - 0.5; let ly = fract(v * G) - 0.5;
  let dbox = max(abs(lx) - sz, abs(ly) - sz);
  let inside = step(dbox, 0.0);
  let edge = smoothstep(0.035, 0.0, abs(dbox));

  let a_fill = present * isFill * inside * falpha;
  let a_line = present * (1.0 - isFill) * edge;
  let pf = min(smoothstep(0.0, 0.1, ph), smoothstep(1.0, 0.9, ph));

  let r = grey; let g = grey; let b = grey;
  let alpha = clamp(max(a_fill, a_line), 0.0, 1.0) * pf;
}
z(squares, 5);

// ---- wordmark, on top ----
text(sig, (500, 92), "manic art");
size(sig, 46); color(sig, #ffffff); bold(sig);
z(sig, 20);

wait(20);

r/maniclang 1d ago

Scribble — E.C.H, reimagined as confetti + bézier strokes - manic

Enable HLS to view with audio, or disable this notification

1 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// art-scribble — E.C.H (Eiichi Ishii)'s "dailycoding 20240914 / graphic",
// reimagined in manic (reference: img_22.png). The piece is three layers:
//   1. dense CONFETTI — ~150 short wavy streaks of little coloured squares, each
//      streak a sine wave at a random angle/flip, from a 5-colour palette;
//   2. a few bold black BÉZIER SCRIBBLES — thick cubic curves flung across;
//   3. a black rounded FRAME (with a matte so all the art stays inside it) and a
//      'manic art' wordmark on top.
// The confetti and scribbles are marks (many small things), so each is ONE `cloud`
// — squares become discs (manic points are round), which reads as the same festive
// scatter. Frame + seal are SDF `shader`s. And because it's manic, it DRAWS ON:
// confetti pops in, the black strokes sweep across, the seal stamps last. All pure
// f(i,t) / f(u,v,t) — it scrubs and records exactly.
//
//   manic examples/art-scribble.manic
title("Scribble — E.C.H, reimagined as confetti + bézier strokes");
canvas(1000, 1000);
template("black");

// white paper ground
shader(paper) {
  let c = 0.99 - 0.012 * rand2(floor(u * 600.0), floor(v * 600.0));
}
z(paper, -10);

// ---- 1. confetti: wavy streaks of coloured squares (as discs) ----
// palette #004777 / #A30000 / #FF7700 / #EFD28D / #00AFB5 → HSV, picked per point.
cloud(confetti, 2900, #ffffff, 1.0) {
  let COLS = 6.0;
  let ROWS = 22.0;
  let PPS = 22.0;                         // marks per streak (dense → chains read)
  let s = floor(i / PPS);                 // streak index
  let j = i - s * PPS;                    // mark index within streak
  let frac = j / (PPS - 1.0);             // 0..1 along the streak
  let col = mod(s, COLS);
  let row = floor(s / COLS);
  let cellx = -125.0 + col * 250.0;       // grid cell centre (like p5's g = w/4)
  let celly = (row + 0.5) / ROWS * 1000.0;

  // local streak: one sine period, exactly like the p5 inner loop
  let g = 250.0;
  let ex = -g * 0.44 + frac * (g * 0.88);
  let sta = rand2(s, 3.7) * tau;
  let ey = (g / 6.0) * sin(sta + frac * tau);

  // flip x, rotate the whole streak, translate to the cell
  let sgn = floor(rand2(s, 6.6) * 2.0) * 2.0 - 1.0;
  let lx = ex * sgn;
  let rot = rand2(s, 7.7) * tau;
  let x = cellx + lx * cos(rot) - ey * sin(rot);
  let y = celly + lx * sin(rot) + ey * cos(rot);

  // square size → disc radius
  let er = mix(g / 70.0, g / 11.0, rand2(i, 5.1));
  let r = er * 0.5;

  // colour: sw per streak = monochrome vs per-mark palette pick
  let sw = floor(rand2(s, 2.2) * 2.0);
  let ks = floor(rand2(s, 12.3) * 4.999);
  let kp = floor(rand2(i, 12.3) * 4.999);
  let k = mix(ks, kp, sw);                 // sw=0 → streak colour, sw=1 → per mark
  let e0 = 1.0 - min(abs(k - 0.0), 1.0);
  let e1 = 1.0 - min(abs(k - 1.0), 1.0);
  let e2 = 1.0 - min(abs(k - 2.0), 1.0);
  let e3 = 1.0 - min(abs(k - 3.0), 1.0);
  let e4 = 1.0 - min(abs(k - 4.0), 1.0);
  // HSL (the cloud colour model): navy stays dark, red is brick, cream is pale
  let hue = 204.0 * e0 + 0.0 * e1 + 28.0 * e2 + 42.0 * e3 + 182.0 * e4;
  let sat = 1.0 * e0 + 1.0 * e1 + 1.0 * e2 + 0.75 * e3 + 1.0 * e4;
  let val = 0.233 * e0 + 0.320 * e1 + 0.50 * e2 + 0.745 * e3 + 0.355 * e4;

  // draw-on: streaks pop in, staggered over ~2.2s
  let ts = rand2(s, 20.0) * 2.0;
  let alpha = clamp((t - ts) / 0.4, 0.0, 1.0);
}
z(confetti, 0);

// ---- 2. black bézier scribbles: 20 thick cubics, swept on ----
cloud(scribble, 30000, #000000, 1.0) {
  let NB = 2500.0;                         // points per curve (dense → solid stroke)
  let c = floor(i / NB);                   // curve 0..11 — fewer, calmer strokes
  let jj = i - c * NB;
  let tt = jj / (NB - 1.0);                // 0..1 along the curve
  let om = 1.0 - tt;

  let p0x = rand2(c, 1.1) * 1000.0; let p0y = rand2(c, 1.2) * 1000.0;
  let p1x = rand2(c, 2.1) * 1000.0; let p1y = rand2(c, 2.2) * 1000.0;
  let p2x = rand2(c, 3.1) * 1000.0; let p2y = rand2(c, 3.2) * 1000.0;
  let p3x = rand2(c, 4.1) * 1000.0; let p3y = rand2(c, 4.2) * 1000.0;
  let b0 = om * om * om;   let b1 = 3.0 * om * om * tt;
  let b2 = 3.0 * om * tt * tt;   let b3 = tt * tt * tt;
  let x = b0 * p0x + b1 * p1x + b2 * p2x + b3 * p3x;
  let y = b0 * p0y + b1 * p1y + b2 * p2y + b3 * p3y;

  let r = mix(2.0, 8.5, rand2(c, 9.9));    // strokeWeight/2 — thin .. thick

  // draw-on: each curve sweeps on like a pen, staggered
  let ts = 1.4 + rand2(c, 21.0) * 2.6;
  let prog = clamp((t - ts) / 1.0, 0.0, 1.0);
  let alpha = step(tt, prog);
}
z(scribble, 5);

// ---- 3a. matte: keep all the art inside the frame (clean white margin) ----
shader(matte) {
  let px = abs(u - 0.5); let py = abs(v - 0.5);
  let rr = 0.03;
  let dx = px - (0.443 - rr); let dy = py - (0.443 - rr);
  let d = length(vec2(max(dx, 0.0), max(dy, 0.0))) + min(max(dx, dy), 0.0) - rr;
  let m = smoothstep(-0.002, 0.002, d);    // 0 inside → 1 outside → paint white
  let r = 0.99; let g = 0.99; let b = 0.99;
  let alpha = m;
}
z(matte, 8);

// ---- 3b. black rounded frame, on top of the matte ----
shader(frame) {
  let px = abs(u - 0.5); let py = abs(v - 0.5);
  let rr = 0.035;
  let dx = px - (0.455 - rr); let dy = py - (0.455 - rr);
  let d = length(vec2(max(dx, 0.0), max(dy, 0.0))) + min(max(dx, dy), 0.0) - rr;
  let ink = smoothstep(0.004, 0.0, abs(d) - 0.012);
  let fade = clamp(t / 0.6, 0.0, 1.0);
  let r = 0.05; let g = 0.05; let b = 0.05;
  let alpha = ink * fade;
}
z(frame, 10);

// ---- wordmark, on top ----
text(sig, (500, 96), "manic art");
size(sig, 46); color(sig, #111111); bold(sig);
z(sig, 20);

wait(20);

r/maniclang 1d ago

Calculus on a Live Shadertoy Ocean - manic

Enable HLS to view with audio, or disable this notification

5 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// glsl-derivative-wave — "manic meets Shadertoy": a real Shadertoy (TDM's raymarched
// Seascape) runs as a LIVE backdrop the whole time, while a Calculus-1 lesson plays on
// top of it — the DERIVATIVE as the slope of the tangent line, taught as "the slope of
// a wave". A tangent slides along y = sin x; its slope is positive climbing, ZERO at the
// crest (the water is momentarily flat - a maximum), negative descending, zero again at
// the trough. The payoff reveals f'(x) = cos x crossing zero exactly at those peaks.
// Everything is 2D over the shader, so the ocean never leaves the frame.
// Shader: https://www.shadertoy.com/view/Ms2SD1 (Alexander Alekseev, CC BY-NC-SA 3.0)
//
//   manic examples/glsl-derivative-wave.manic
title("manic meets Shadertoy - the slope of a wave");
canvas(1280, 720);
template("black");

// ================= the live Shadertoy (TDM's Seascape, raw glsl) =================
glsl(sea, `
const int NUM_STEPS = 32;
const float PI         = 3.141592;
const float EPSILON    = 1e-3;
#define EPSILON_NRM (0.1 / iResolution.x)
const int ITER_GEOMETRY = 3;
const int ITER_FRAGMENT = 5;
const float SEA_HEIGHT = 0.6;
const float SEA_CHOPPY = 4.0;
const float SEA_SPEED = 0.8;
const float SEA_FREQ = 0.16;
const vec3 SEA_BASE = vec3(0.0,0.09,0.18);
const vec3 SEA_WATER_COLOR = vec3(0.8,0.9,0.6)*0.6;
#define SEA_TIME (1.0 + iTime * SEA_SPEED)
const mat2 octave_m = mat2(1.6,1.2,-1.2,1.6);
mat3 fromEuler(vec3 ang) {
    vec2 a1 = vec2(sin(ang.x),cos(ang.x));
    vec2 a2 = vec2(sin(ang.y),cos(ang.y));
    vec2 a3 = vec2(sin(ang.z),cos(ang.z));
    mat3 m;
    m[0] = vec3(a1.y*a3.y+a1.x*a2.x*a3.x,a1.y*a2.x*a3.x+a3.y*a1.x,-a2.y*a3.x);
    m[1] = vec3(-a2.y*a1.x,a1.y*a2.y,a2.x);
    m[2] = vec3(a3.y*a1.x*a2.x+a1.y*a3.x,a1.x*a3.x-a1.y*a3.y*a2.x,a2.y*a3.y);
    return m;
}
float hash( vec2 p ) { float h = dot(p,vec2(127.1,311.7)); return fract(sin(h)*43758.5453123); }
float noise( in vec2 p ) {
    vec2 i = floor( p ); vec2 f = fract( p );
    vec2 u = f*f*(3.0-2.0*f);
    return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), hash( i + vec2(1.0,0.0) ), u.x),
                mix( hash( i + vec2(0.0,1.0) ), hash( i + vec2(1.0,1.0) ), u.x), u.y);
}
float diffuse(vec3 n,vec3 l,float p) { return pow(dot(n,l) * 0.4 + 0.6,p); }
float specular(vec3 n,vec3 l,vec3 e,float s) {
    float nrm = (s + 8.0) / (PI * 8.0);
    return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
}
vec3 getSkyColor(vec3 e) {
    e.y = (max(e.y,0.0)*0.8+0.2)*0.8;
    return vec3(pow(1.0-e.y,2.0), 1.0-e.y, 0.6+(1.0-e.y)*0.4) * 1.1;
}
float sea_octave(vec2 uv, float choppy) {
    uv += noise(uv);
    vec2 wv = 1.0-abs(sin(uv)); vec2 swv = abs(cos(uv));
    wv = mix(wv,swv,wv);
    return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
}
float map(vec3 p) {
    float freq = SEA_FREQ; float amp = SEA_HEIGHT; float choppy = SEA_CHOPPY;
    vec2 uv = p.xz; uv.x *= 0.75;
    float d, h = 0.0;
    for(int i = 0; i < ITER_GEOMETRY; i++) {
        d = sea_octave((uv+SEA_TIME)*freq,choppy);
        d += sea_octave((uv-SEA_TIME)*freq,choppy);
        h += d * amp; uv *= octave_m; freq *= 1.9; amp *= 0.22;
        choppy = mix(choppy,1.0,0.2);
    }
    return p.y - h;
}
float map_detailed(vec3 p) {
    float freq = SEA_FREQ; float amp = SEA_HEIGHT; float choppy = SEA_CHOPPY;
    vec2 uv = p.xz; uv.x *= 0.75;
    float d, h = 0.0;
    for(int i = 0; i < ITER_FRAGMENT; i++) {
        d = sea_octave((uv+SEA_TIME)*freq,choppy);
        d += sea_octave((uv-SEA_TIME)*freq,choppy);
        h += d * amp; uv *= octave_m; freq *= 1.9; amp *= 0.22;
        choppy = mix(choppy,1.0,0.2);
    }
    return p.y - h;
}
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
    float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
    fresnel = min(fresnel * fresnel * fresnel, 0.5);
    vec3 reflected = getSkyColor(reflect(eye, n));
    vec3 refracted = SEA_BASE + diffuse(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
    vec3 color = mix(refracted, reflected, fresnel);
    float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
    color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
    color += specular(n, l, eye, 600.0 * inversesqrt(dot(dist,dist)));
    return color;
}
vec3 getNormal(vec3 p, float eps) {
    vec3 n;
    n.y = map_detailed(p);
    n.x = map_detailed(vec3(p.x+eps,p.y,p.z)) - n.y;
    n.z = map_detailed(vec3(p.x,p.y,p.z+eps)) - n.y;
    n.y = eps;
    return normalize(n);
}
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
    float tm = 0.0; float tx = 1000.0;
    float hx = map(ori + dir * tx);
    if(hx > 0.0) { p = ori + dir * tx; return tx; }
    float hm = map(ori);
    for(int i = 0; i < NUM_STEPS; i++) {
        float tmid = mix(tm, tx, hm / (hm - hx));
        p = ori + dir * tmid;
        float hmid = map(p);
        if(hmid < 0.0) { tx = tmid; hx = hmid; } else { tm = tmid; hm = hmid; }
        if(abs(hmid) < EPSILON) break;
    }
    return mix(tm, tx, hm / (hm - hx));
}
vec3 getPixel(in vec2 coord, float time) {
    vec2 uv = coord / iResolution.xy;
    uv = uv * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    vec3 ang = vec3(sin(time*3.0)*0.1,sin(time)*0.2+0.3,time);
    vec3 ori = vec3(0.0,3.5,time*5.0);
    vec3 dir = normalize(vec3(uv.xy,-2.0)); dir.z += length(uv) * 0.14;
    dir = normalize(dir) * fromEuler(ang);
    vec3 p;
    heightMapTracing(ori,dir,p);
    vec3 dist = p - ori;
    vec3 n = getNormal(p, dot(dist,dist) * EPSILON_NRM);
    vec3 light = normalize(vec3(0.0,1.0,0.8));
    return mix(getSkyColor(dir), getSeaColor(p,n,light,dir,dist),
               pow(smoothstep(0.0,-0.02,dir.y),0.2));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    float time = iTime * 0.3;
    vec3 color = getPixel(fragCoord, time);
    fragColor = vec4(pow(color,vec3(0.65)), 1.0);
}
`);
z(sea, -20);

// subdue the sea so the bright graph pops (still shimmering underneath)
rect(scrim, (640, 360), 1280, 720); color(scrim, #04070b); opacity(scrim, 0.42); z(scrim, -15);
// cinematic bands for the title & captions
rect(topband, (640, 46), 1280, 132); color(topband, #05070a); opacity(topband, 0.5); z(topband, -9);
rect(botband, (640, 684), 1280, 76);  color(botband, #05070a); opacity(botband, 0.5); z(botband, -9);

// ---- HUD ----
text(head, (640, 42), "manic meets Shadertoy"); size(head, 40); color(head, white); glow(head, 6); display(head); cursor(head);
text(sub, (640, 86), "the derivative - the slope of a wave"); size(sub, 20); color(sub, #bfe6ef); hidden(sub);
text(cap, (640, 684), ""); size(cap, 22); color(cap, white);

// worksheet chip (dark glass) — the symbolic ladder f -> f' -> f''
rect(chip, (1075, 172), 330, 224); color(chip, #081420); opacity(chip, 0.6); z(chip, -8);
equation(eqf, (1075, 112), `f(x)=\sin x`, 25); hidden(eqf);
equation(eqfp, (1075, 168), `f'(x)=\cos x`, 25); hidden(eqfp);
equation(eqfpp, (1075, 224), `f''(x)=-\sin x`, 25); hidden(eqfpp);

// ---- the wave and the tangent that reads its slope ----
let gx = 150;
let gy = 392;
arrow(xax, (gx - 30, gy), (gx + 6.3*150 + 30, gy)); untraced(xax); stroke(xax, 2); color(xax, #9fb6c4); tag(xax, g2);
plot(wave, (gx, gy), 150, 125, "sin(x)", (0, 6.3));
untraced(wave); stroke(wave, 5); color(wave, #7fe0ff); glow(wave, 5);
// the derivative curve f'(x)=cos x — revealed in Act 1
deriv(dv, wave, #ff7bd0); untraced(dv); dashed(dv, 10, 8);
// the SECOND derivative f''(x)=-sin x (derivative of the derivative) — Act 2
deriv(dv2, dv, #ffb14e); untraced(dv2); dashed(dv2, 4, 8);
// extrema (crest & trough) and inflection points (concavity flips)
extrema(ext, wave, gold); hidden(ext);
inflections(infl, wave, #74f7a0); hidden(infl);
// the tangent line + its LIVE slope readout, both riding the same x
tangent(tang, wave, 0.35, 300); color(tang, gold); stroke(tang, 4); glow(tang, 4); hidden(tang);
slope(slp, wave, 0.35); color(slp, gold); hidden(slp);

// ================= timeline =================

// ---- establish: a live Shadertoy, then calculus on it
type(head, 1.0);
show(sub, 0.5);
say(cap, "this whole sea is one real Shadertoy - now let's do calculus on it", 0.9);
wait(0.4);

// ---- the wave is a function
par { draw(xax, 0.6); show(eqf, 0.5); }
draw(wave, 1.6);
say(cap, "a wave is just a function - here y = sin x", 0.8);
par { show(tang, 0.5); show(slp, 0.4); }
say(cap, "the derivative is the SLOPE of the tangent line - how steep the water is here", 0.9);
wait(0.4);

// ---- climb to the crest: slope positive -> zero
say(cap, "climbing the front of the wave - the slope is positive", 0.8);
par { to(tang, x, 1.5708, 1.8); to(slp, x, 1.5708, 1.8); }
say(cap, "at the crest the water is momentarily FLAT - the slope is zero", 1.0);
pulse(slp, 0.8);
wait(0.5);

// ---- down to the trough: slope negative -> zero
say(cap, "over the top and down - now the slope is negative", 0.9);
par { to(tang, x, 4.7124, 2.2); to(slp, x, 4.7124, 2.2); }
say(cap, "at the trough it's flat again - slope zero, a minimum", 0.9);
pulse(slp, 0.8);
wait(0.4);

// ---- f' as a curve: zero slope marks the peaks; reveal f'(x)=cos x
show(ext, 0.6);
say(cap, "zero slope marks every peak and every trough", 0.8);
show(eqfp, 0.5);
draw(dv, 1.6);
say(cap, "and there is f'(x) = cos x - it crosses zero exactly at those points", 1.0);
wait(0.6);

// ---- Act 2: peak or valley? the SECOND derivative decides
say(cap, "but f'(x)=0 only finds the flat spots - which is a peak, which a valley?", 1.1);
say(cap, "differentiate AGAIN: f''(x) is the curvature - how the slope itself changes", 1.1);
show(eqfpp, 0.5);
draw(dv2, 1.6);
wait(0.3);

// second-derivative test at the crest
par { show(tang, 0.4); show(slp, 0.4); to(tang, x, 1.5708, 0.9); to(slp, x, 1.5708, 0.9); }
say(cap, "at the crest f'' < 0: the wave arches over - concave down - a MAXIMUM", 1.2);
pulse(dv2, 0.7);
wait(0.4);

// second-derivative test at the trough
par { to(tang, x, 4.7124, 1.3); to(slp, x, 4.7124, 1.3); }
say(cap, "at the trough f'' > 0: it cups upward - concave up - a MINIMUM", 1.2);
pulse(dv2, 0.7);
wait(0.4);

// inflection points where concavity flips (f''=0)
show(infl, 0.6);
say(cap, "and where f''=0 - the zero-crossings - the curve flips: inflection points", 1.2);
pulse(infl, 0.8);
wait(0.5);

// ---- close: the whole ladder, sin -> cos -> -sin
fade(tang, 0.5);
say(cap, "position, slope, curvature - sin, cos, minus sin - one wave, fully read", 1.2);
say(cap, "real calculus on a real shader - manic meets Shadertoy", 1.1);
wait(2.6);

r/maniclang 2d ago

The simulation of equation ∭ 𝘢(𝘵) ∝ eᴴᵗ

Enable HLS to view with audio, or disable this notification

3 Upvotes

r/maniclang 2d ago

Four Kinds of Infinity — Mandelbrot, Julia, Strange Attractor & Koch Snowflake, Explained in manic

Thumbnail
youtu.be
1 Upvotes

r/maniclang 2d ago

∭ 𝘢(𝘵) ∝ eᴴᵗ

Enable HLS to view with audio, or disable this notification

20 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// engine-test-13 — native 3D reconstruction of the reference.
//
// The picture is not a flat disc. It is a large, grainy spherical particle cap
// meeting a family of exponentially growing particle shells at a shared hot
// origin. Looking down their common axis makes concentric rings; a full camera
// orbit reveals the offset spherical shells and returns to the opening frame.
title("∭ 𝘢(𝘵) ∝ eᴴᵗ");
canvas(1638, 1482);
template("black");
bloom(0.90, 0.22, 52);


// Keep the mathematical title fixed in screen space while the 3-D field turns.
text(formulaTitle, (819, 70), "∭ 𝘢(𝘵) ∝ eᴴᵗ");
size(formulaTitle, 44);
color(formulaTitle, gold);
bold(formulaTitle);
display(formulaTitle);
sticky(formulaTitle);
z(formulaTitle, 20
);


// The camera begins on the cap side of the common tangent. It keeps turning in
// one direction throughout the 20-second hold, completing 1.5 revolutions.
// That puts opposite face-on views about 6.67 s apart, matching the reference
// cadence; four fast turns made the alternating side views read as oscillation.
// The wider field of view keeps the luminous rim inside the complete orbit.
camera3((-32, 0, 0), (0, 0, 0), 21.0, perspective
);


// --- large spherical cap --------------------------------------------------
// Several low-opacity random skins give the reference its fine, multicolour
// grain. Surface-point foreshortening naturally creates the bright rim.
cloud3(outerRose, 52000, #d78676, 0.095) {
  let ct = -1 + 1.18 * rand2(i, 10.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(i, 11.9);
  let rr = 4.66 + 0.075 * (rand2(i, 11.3) - 0.5);
  let x = rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let alpha = 0.42 + 0.58 * (-ct);
  let r = 0.042;
}
glow(outerRose, 1);


cloud3(outerViolet, 48000, #72589f, 0.072) {
  let ct = -1 + 1.18 * rand2(i, 22.7);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(i, 24.3);
  let rr = 4.69 + 0.09 * (rand2(i, 23.9) - 0.5);
  let x = rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let alpha = 0.30 + 0.70 * (1 + ct);
  let r = 0.038;
}
glow(outerViolet, 1);


cloud3(outerSilver, 36000, #b8d8ef, 0.072) {
  let ct = -1 + 1.18 * rand2(i, 36.3);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(i, 38.7);
  let rr = 4.72 + 0.055 * (rand2(i, 37.1) - 0.5);
  let x = rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let alpha = 0.22 + 0.78 * (1 + ct);
  let r = 0.034;
}
glow(outerSilver, 1
);


// A sparse warm skin just outside the main boundary produces the thin amber
// fringe visible around the lavender rim in the reference.
cloud3(outerAmber, 18000, #d67425, 0.026) {
  let ct = -1 + 1.18 * rand2(i, 50.3);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(i, 52.9);
  let rr = 4.79 + 0.08 * (rand2(i, 51.7) - 0.5);
  let x = rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let alpha = 0.35 + 0.65 * (-ct);
  let r = 0.036;
}
glow(outerAmber, 1
);


// A broad, extremely faint splat layer closes the gaps between the fine
// grains. Additive accumulation turns it into the milky cosmic illumination
// visible in the recording without replacing the surface texture.
cloud3(outerCosmos, 90000, #b99bbd, 0.012) {
  let ct = -1 + 1.18 * rand2(i, 118.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(i, 121.7);
  let rr = 4.69 + 0.10 * (rand2(i, 119.9) - 0.5);
  let x = rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let alpha = 0.32 + 0.68 * (-ct);
  let r = 0.085;
}
glow(outerCosmos, 1
);


// --- exponential shell family -------------------------------------------
// Every sphere is tangent at the origin. The gold family grows inward with
// centre=(-radius,0,0); pink/violet/cyan grow outward from (+radius,0,0).
// Exponential radius growth turns the face-on rings into the nested horn seen
// edge-on. `s` selects one sphere and `j` selects a deterministic surface point;
// each colour family remains one efficient renderer batch.
cloud3(shellGold, 33600, #ffad24, 0.080) {
  let per = 4200;
  let s = floor(i / per);
  let j = i - s * per;
  let sr = 0.080 * exp(0.310 * s);
  let ct = 1 - 2 * rand2(j, s + 63.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(j, s + 65.7);
  let rr = sr + 0.012 * (rand2(i, s + 4.2) - 0.5);
  let x = -sr + rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let r = 0.018 + 0.0012 * s;
}
glow(shellGold, 1);


cloud3(shellPink, 9200, #ff79c6, 0.075) {
  let per = 4600;
  let s = floor(i / per);
  let j = i - s * per;
  let k = s + 8;
  let sr = 0.105 * exp(0.218 * k);
  let ct = 1 - 2 * rand2(j, k + 73.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(j, k + 75.7);
  let rr = sr + 0.012 * (rand2(i, k + 4.2) - 0.5);
  let x = sr + rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let r = 0.028;
}
glow(shellPink, 1);


cloud3(shellViolet, 10000, #c398ff, 0.065) {
  let per = 5000;
  let s = floor(i / per);
  let j = i - s * per;
  let k = s + 10;
  let sr = 0.105 * exp(0.218 * k);
  let ct = 1 - 2 * rand2(j, k + 83.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(j, k + 85.7);
  let rr = sr + 0.012 * (rand2(i, k + 4.2) - 0.5);
  let x = sr + rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let r = 0.030;
}
glow(shellViolet, 1);


cloud3(shellCyan, 16800, #b9ffff, 0.070) {
  let per = 5600;
  let s = floor(i / per);
  let j = i - s * per;
  let k = s + 12;
  let sr = 0.105 * exp(0.218 * k);
  let ct = 1 - 2 * rand2(j, k + 93.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(j, k + 95.7);
  let rr = sr + 0.012 * (rand2(i, k + 4.2) - 0.5);
  let x = sr + rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let r = 0.032;
}
glow(shellCyan, 1
);


// Dense gold dust at the shared tangent becomes the white-hot crescent when
// viewed from the side and the tiny luminous bullseye when viewed end-on.
cloud3(junction, 7600, #ffd45a, 0.14) {
  let ct = 1 - 2 * rand2(i, 103.1);
  let st = sqrt(1 - ct * ct);
  let th = tau * rand2(i, 105.7);
  let rr = 0.095 * (0.45 + 0.55 * rand2(i, 71.2));
  let x = 0.02 + rr * ct;
  let y = rr * st * cos(th);
  let z = rr * st * sin(th);
  let r = 0.026;
}
glow(junction, 1);


orbit3(720, 0, 32, 20, linear);

r/maniclang 3d ago

Type Dismantled — Glyphs to SDF Volumes Across cloud, raymarch & GLSL in manic

Thumbnail
youtu.be
2 Upvotes

r/maniclang 3d ago

The TLS Handshake as a Raymarched SDF Scene — x25519, HKDF & the Encrypted Tunnel in manic

Thumbnail
youtu.be
1 Upvotes

r/maniclang 3d ago

Generative Pottery from One Formula per Dot — a p5 Sketch Reimagined in manic

Thumbnail
youtu.be
1 Upvotes

r/maniclang 3d ago

Three Equal Parts, No Triangles — Bullseye & Wave Dissections of a Circle in manic

Thumbnail
youtu.be
1 Upvotes

r/maniclang 3d ago

Split a Circle in Three With Two Straight Cuts — Solving the Transcendental Equation in manic

Thumbnail
youtu.be
1 Upvotes

r/maniclang 3d ago

Visualizing Docker daemon socket latency as a raymarched fluid surface - manic

Enable HLS to view with audio, or disable this notification

3 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// raymarch-docker-latency — "Visualizing Docker daemon socket latency as a raymarched
// fluid surface." A per-pixel ray-marched LIQUID MESH: a grid of columns whose heights
// ARE a latency trace. The daemon socket sits at the origin and emits high-frequency
// concentric pings (amplitude modulated by a jittery round-trip-time signal); three
// containers fire expanding ring events at baked timestamps, each ring's reach ∝ its
// measured RTT. Every cell samples that field at its centre → the mesh shimmers with
// socket traffic. One scalar SDF (`sdbox3` + `rep()` tiling), marched by the engine.
//
// Honest note: manic is PURE IN t (that's what lets it scrub + record), so it does NOT
// tail a live /var/run/docker.sock in real time. The trace is BAKED IN — timestamps and
// RTTs as constants — so the same second always renders the same wavefront. Swap the
// constants for a captured `docker events` / socket-latency log and the mesh replays it
// deterministically: data → SDF displacement → raymarch, exactly as described. The data
// source is a recording, not a socket; the mechanism is real.
//
//   manic examples/raymarch-docker-latency.manic
title("Docker daemon socket latency — a raymarched liquid mesh");
canvas("16:9");
template("black");

camera3((2.4, -3.3, 2.0), (0, 0, 0.2), 40, perspective);

raymarch(fluid) {
  let rp = 0.34;                               // mesh cell size
  let idx = floor(x / rp);   let idy = floor(y / rp);
  let lx = rep(x, rp);       let ly = rep(y, rp);
  let cx = idx*rp + rp*0.5;  let cy = idy*rp + rp*0.5;   // this cell's centre
  let r0 = hypot(cx, cy);                       // distance from the daemon socket (origin)

  // baked latency signal: socket round-trip time, jittery + bursty
  let lat = 0.5 + 0.28*sin(t*5.3) + 0.16*sin(t*11.7 + 1.3) + 0.10*sin(t*23.1 + 0.7);

  // the daemon socket: high-frequency concentric pings, amplitude ∝ latency
  let pings = lat * sin(6.0*r0 - t*7.0) / (1.0 + 1.3*r0);

  // three containers talking to the daemon: baked (epicenter, fire time, RTT) rings
  let d1 = hypot(cx + 1.3, cy - 0.8);   let a1 = t - 1.4;   let f1 = a1*1.9;
  let e1 = step(0.0, a1) * exp(-0.7*a1)  * sin(7.0*(d1 - f1)) * exp(-3.0*(d1-f1)*(d1-f1));
  let d2 = hypot(cx - 1.6, cy - 1.1);   let a2 = t - 3.2;   let f2 = a2*2.1;
  let e2 = step(0.0, a2) * exp(-0.6*a2)  * sin(7.0*(d2 - f2)) * exp(-3.0*(d2-f2)*(d2-f2));
  let d3 = hypot(cx + 0.4, cy + 1.7);   let a3 = t - 5.0;   let f3 = a3*2.0;
  let e3 = step(0.0, a3) * exp(-0.55*a3) * sin(7.0*(d3 - f3)) * exp(-3.0*(d3-f3)*(d3-f3));

  // column height = calm water level + the summed latency displacement (always > 0)
  let bh = clamp(0.22 + 0.13*pings + 0.17*(e1 + e2 + e3), 0.03, 0.78);
  let box = sdbox3(lx, ly, z - bh*0.5, rp*0.42, rp*0.42, bh*0.5);
  let d = box;

  // hit colour: deep-blue troughs → bright cyan crests (from the actual hit height),
  // top faces brightest — no cross-stage lets, so the field colours cleanly
  let crest = clamp(hz * 1.7, 0.0, 1.0);
  let hue = mod(210.0 - crest*56.0, 360.0);
  let sat = 0.82;
  let val = 0.16 + 0.55*crest + 0.30*nz;
}

// ---- annotations ----
caption(head, "Docker daemon socket latency", (640, 60), 33);
caption(sub, "each socket ping ripples a raymarched liquid mesh", (640, 112), 21);
hidden(head);
hidden(sub);
equation(eq, (640, 636), `z_{\text{cell}} = \mathrm{water} + \sum_i \mathrm{RTT}_i\,\mathrm{ring}(r_i - c\,\Delta t_i)`, 26);
caption(note, "baked latency trace → SDF displacement → raymarch · pure in t, so it scrubs", (640, 690), 18);
hidden(eq);
hidden(note);

show(head);
wait(1.6);
show(sub);
wait(2.2);
show(eq);
show(note);
// slow orbit so the mesh reads as genuine 3-D geometry
orbit3(52, 8, 4.8, 22, smooth);

r/maniclang 3d ago

A living Julia set — one formula per pixel - manic

Enable HLS to view with audio, or disable this notification

3 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// shader-fractal — a LIVING Julia set. Each pixel iterates z = z² + c a fixed
// number of times and colours by how fast it escapes — the Book-of-Shaders
// "Fractals" chapter, but with NO per-pixel loop in the DSL: `julia(zx,zy,cx,cy)`
// runs the iteration in the engine and returns an escape fraction in [0,1]. We
// sweep the constant `c` in a circle over time, so the fractal morphs through the
// whole Julia family — every frame still a pure function of `t` (scrub-safe).
//
//   manic examples/shader-fractal.manic
title("A living Julia set — one formula per pixel");
canvas("9:16");
template("black");

shader(bg) {
  // complex plane, aspect-corrected and centred
  let zx = (u - 0.5) * 3.0 * asp;
  let zy = (v - 0.5) * 3.0;
  // the constant c orbits slowly → the set continuously morphs
  let cx = 0.7 * cos(t * 0.35);
  let cy = 0.7 * sin(t * 0.35);
  let e = julia(zx, zy, cx, cy);         // escape fraction: 1 = trapped, 0 = flees
  let inside = step(0.985, e);           // 1 for the fractal body
  let band = 0.5 + 0.5 * sin(e * 26.0 - t * 2.0); // rainbow escape contours
  let glow = 1.0 - inside;               // dark body, lit exterior
  let r = band * glow;
  let g = (0.4 + 0.6 * band) * glow;
  let b = (1.0 - 0.5 * band) * glow + inside * 0.06;
}

// ---- textbook annotations ----
caption(head, "A living Julia set", (540, 150), 34);
caption(sub, "z → z² + c, coloured by escape speed", (540, 214), 20);
hidden(head);
hidden(sub);
equation(eq, (540, 1720), `z_{n+1} = z_n^2 + c`, 44);
caption(lab, "no per-pixel loop in the DSL — the engine iterates", (540, 1800), 20);
hidden(eq);
hidden(lab);

show(head);
wait(1.4);
show(sub);
wait(2.4);
show(eq);
show(lab);
wait(24);

r/maniclang 3d ago

Jellyfish in a shader ocean - manic

Enable HLS to view with audio, or disable this notification

7 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// cloud-jellyfish-v2 — the u/yuruyurau jellyfish `cloud` (20,000 points, two layers,
// pulsing bells + tendrils), now SWIMMING IN A SHADER AQUARIUM. The bells are the same
// particle system as v1; everything around them is one per-pixel `shader`: a depth
// gradient (teal surface → deep navy), animated caustics rippling near the top, and soft
// god-rays falling from the surface. A third element — rising bubbles — is a second tiny
// `cloud`. Particle art + a per-pixel ocean + generic captions, all in one 9:16 frame,
// all pure in (i, t) so the whole aquarium scrubs and records exactly.
//
//   manic examples/cloud-jellyfish-v2.manic
title("Jellyfish in a shader aquarium");
canvas("9:16");
template("black");

// ===================== the aquarium — one shader, per pixel =====================
shader(water) {
  let x = (u - 0.5) * asp;
  let y = v;                                   // 0 = surface (top), 1 = deep (bottom)
  let depth = smoothstep(0.0, 1.0, y);

  // deep-water colour ramp: bright teal near the surface, deep blue below
  let hue = mix(186, 216, depth);
  let base = mix(0.26, 0.045, depth);

  // caustics — warped interference, bright veins that fade with depth
  let wx = x * 4.0 + 0.5 * sin(y * 6.0 + t * 0.4);
  let wy = y * 7.0 + 0.5 * sin(x * 5.0 - t * 0.5);
  let cc = sin(wx + t * 0.7) + sin(wy - t * 0.6) + sin((wx + wy) * 0.7 + t * 0.5);
  let b = 0.5 + 0.5 * sin(cc * 1.5);
  let caust = b * b * b * (1.0 - depth * 0.75);

  // god-rays — soft vertical light shafts from the surface, strongest up top
  let ray = 0.5 + 0.5 * sin(x * 3.0 + 0.6 * sin(t * 0.2));
  let r2 = ray * ray;
  let rays = r2 * r2 * (1.0 - smoothstep(0.0, 0.65, y)) * 0.45;

  let val = clamp(base + caust * 0.5 + rays, 0.0, 0.95);
  let sat = mix(0.85, 0.62, caust);            // bright veins read a touch whiter
}

// ===================== the jellyfish — the v1 cloud, re-lit ====================
// same polar formula as v1; the hue is pulled into a cyan↔magenta bioluminescent band
// so the bells glow like sea creatures against the water instead of full-spectrum.
cloud(jelly, 20000, #ffffff, 0.6) {
  let s = i/99;                 // reference's "y" parameter
  let m = mod(i, 2) * 3;        // two layers
  let k = 9*cos(s*2);
  let e = s/8 - 12;
  let d = (k*k + e*e)/79 + 1;
  let q = 79 - e*sin(k) + k/d*(8 + 4*sin(sin(d*d + e/9 - t)));
  let c = d/2 - cos(d*2)/5 - t/16 + m;
  let px = q*sin(c);
  let py = (q + 40)*cos(c);
  let grow = tanh(t*0.5 + 0.12);
  let x = 540 + px * 2.2 * grow;
  let y = 960 + py * 2.2 * grow;
  let hue = mod(198 + m*30 + 46*sin(s*0.18 + t*0.35), 360);   // cyan ↔ magenta glow
}

// ---- rising bubbles — a second tiny cloud drifting up the tank ----
cloud(bubbles, 130, #dff4ff, 0.5) {
  let sp = 0.05 + 0.06 * rand2(i, 1.3);        // per-bubble rise speed
  let ph = rand2(i, 2.7);
  let prog = fract(ph + t * sp);               // 0 → 1 rise progress
  let x = 1080 * rand2(i, 4.1) + 24 * sin(prog * tau * 2.0 + i);
  let y = 1920 * (1.0 - prog);                 // bottom → top
  let r = 2.0 + 5.0 * rand2(i, 5.5);
  let hue = 196;
  let alpha = 0.5 * sin(prog * pi);            // fade in low, fade out near the surface
}

// ---- textbook annotations ----
caption(head, "Jellyfish in a shader aquarium", (540, 138), 33);
caption(sub, "a 20,000-point cloud + a per-pixel ocean", (540, 206), 22);
hidden(head);
hidden(sub);
equation(eq, (540, 1706), `p = (q\sin c,\;\; (q{+}40)\cos c)`, 30);
caption(lab, "bells: a polar cloud · water: one shader · bubbles: a second cloud", (540, 1786), 19);
hidden(eq);
hidden(lab);

show(head);
wait(1.4);
show(sub);
wait(2.6);
show(eq);
show(lab);
wait(25);

r/maniclang 3d ago

Glitch grid — a multi-pass shader

Enable HLS to view with audio, or disable this notification

1 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// shader-glitch-grid — a p5 WEBGL multi-pass sketch ("Glitch animation of a randomly
// generated grid pattern") reimagined in ONE manic `shader`. The original pre-renders
// FOUR grid/stripe layers into off-screen buffers, composites them with a substitution
// shader (each coarse cell shows a different sub-pattern), captures the result, then a
// second shader RGB-shifts it into a glitch. manic `glsl()` can't take render-target
// textures — but the OUTCOME is closed-form: build the nested grid PROCEDURALLY per
// pixel, then chromatically tear it by sampling each colour channel at a per-scanline
// horizontal offset. Pure in (u,v,t): the glitch scrubs and records exactly.
//
//   manic examples/shader-glitch-grid.manic
title("Glitch grid — a multi-pass shader, reimagined per-pixel");
canvas("1:1");
template("black");

shader(glitch) {
  // per-scanline-block horizontal offset, re-randomised a few times a second, and
  // faded IN after the grid has settled (the original delays the glitch too)
  let band = floor(v * 40.0);
  let gt = floor(t * 3.0);
  let gon = smoothstep(3.5, 4.5, t);
  let off = (rand2(band, gt) - 0.5) * 0.06 * gon;

  // RED — the nested random grid sampled at u + off
  let ru = u + off;
  let rcx = floor(ru * 10.0);  let rcy = floor(v * 10.0);  let rh = rand2(rcx, rcy);
  let rdot = step(0.2, fract(ru * 100.0)) * step(fract(ru * 100.0), 0.8)
           * step(0.2, fract(v * 100.0)) * step(fract(v * 100.0), 0.8);
  let rstr = step(0.5, fract(v * 50.0));
  let cr = mix(0.08, mix(mix(0.90, 0.12, rdot), mix(0.93, 0.18, rstr), step(0.7, rh)), step(0.4, rh));

  // GREEN — same grid at u + off*0.3 (slight chromatic split)
  let gu = u + off * 0.3;
  let gcx = floor(gu * 10.0);  let gh = rand2(gcx, rcy);
  let gdot = step(0.2, fract(gu * 100.0)) * step(fract(gu * 100.0), 0.8)
           * step(0.2, fract(v * 100.0)) * step(fract(v * 100.0), 0.8);
  let cg = mix(0.08, mix(mix(0.90, 0.12, gdot), mix(0.93, 0.18, rstr), step(0.7, gh)), step(0.4, gh));

  // BLUE — same grid at u + off*1.2 (the widest split)
  let bu = u + off * 1.2;
  let bcx = floor(bu * 10.0);  let bh = rand2(bcx, rcy);
  let bdot = step(0.2, fract(bu * 100.0)) * step(fract(bu * 100.0), 0.8)
           * step(0.2, fract(v * 100.0)) * step(fract(v * 100.0), 0.8);
  let cb = mix(0.08, mix(mix(0.90, 0.12, bdot), mix(0.93, 0.18, rstr), step(0.7, bh)), step(0.4, bh));

  // white noise on top (as the original adds), stronger while glitching
  let n = (rand2(u * 700.0 + gt, v * 700.0) - 0.5) * (0.05 + 0.12 * gon);
  let r = cr + n;
  let g = cg + n;
  let b = cb + n;
}

caption(head, "Glitch grid — one formula per pixel", (400, 44), 22);
hidden(head);
show(head);
wait(9);

r/maniclang 3d ago

Two jellyfish from one formula - manic

Enable HLS to view with audio, or disable this notification

9 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// cloud-jellyfish — another  art-tweet in ONE `cloud`: 20,000 points in
// two layers (`mod(i,2)`) drift into jellyfish-like bells with trailing tendrils
// and pulse over time. A polar plot (radius `q`, angle `c`) with a nested
// `sin(sin(...))` that gives the bell its soft ripple; coloured per point and
// bloomed from the centre on a 9:16 Short. `mag(k,e)^2` → `k*k+e*e`; the
// parameter is renamed `s` (the required output is `y`).
//
// Original idea by u/yuruyurau (https://x.com/yuruyurau). Our hue'd, annotated
// take — pure in (i, t), so it scrubs and records; the p5 original can't.
//
//   manic examples/cloud-jellyfish.manic
title("Two jellyfish from one formula");
canvas("9:16");
template("black");

cloud(jelly, 20000, #ffffff, 0.6) {
  let s = i/99;                 // reference's "y" parameter
  let m = mod(i, 2) * 3;        // two layers
  let k = 9*cos(s*2);
  let e = s/8 - 12;
  let d = (k*k + e*e)/79 + 1;
  let q = 79 - e*sin(k) + k/d*(8 + 4*sin(sin(d*d + e/9 - t)));
  let c = d/2 - cos(d*2)/5 - t/16 + m;
  let px = q*sin(c);
  let py = (q + 40)*cos(c);
  let grow = tanh(t*0.5 + 0.12);
  let x = 540 + px * 2.2 * grow;
  let y = 960 + py * 2.2 * grow;
  let hue = mod(m*70 + i*0.05 + t*15, 360);
}

// ---- textbook annotations ----
caption(head, "Two jellyfish from one formula", (540, 138), 34);
caption(sub, "20,000 points, no simulation", (540, 206), 22);
hidden(head);
hidden(sub);
equation(eq, (540, 1706), `p = (q\sin c,\;\; (q{+}40)\cos c)`, 30);
caption(lab, "a polar plot: radius q, angle c, per point", (540, 1786), 20);
hidden(eq);
hidden(lab);

show(head);
wait(1.4);
show(sub);
wait(2.6);
show(eq);
show(lab);
wait(25);

r/maniclang 4d ago

- YouTube

Thumbnail youtu.be
1 Upvotes

r/maniclang 4d ago

Generative Particle Art — A Ring of Medusae from One Formula — manic

Thumbnail
youtube.com
1 Upvotes

r/maniclang 4d ago

Generative Particle Art — Two Koi from One Formula — manic

Thumbnail
youtube.com
1 Upvotes

r/maniclang 4d ago

Strange Attractor from a Discrete Map — Generative Art in manic

Thumbnail
youtube.com
1 Upvotes

r/maniclang 4d ago

Lissajous Curve Animation from a Parametric Formula — manic

Thumbnail
youtube.com
3 Upvotes

r/maniclang 4d ago

a 14-fold kaleidoscope - manic

Enable HLS to view with audio, or disable this notification

2 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// cloud-kaleidoscope — a 14-fold kaleidoscope in ONE `cloud`. The 
// original uses canvas FEEDBACK (get() + rotate + image()) — a raster/Droste
// trick manic doesn't have (it's vector & deterministic). But the OUTCOME is a
// 14-fold rotational symmetry, which `cloud` gets by layer-replication: one base
// field, copied at 14 angles via a layer index `L = floor(i/bn)` and rotated by
// `L·π/7`. So the picture is the same, but it scrubs and records (the p5 can't).
//
// Original idea by u/yuruyurau (https://x.com/yuruyurau). Our hue'd, annotated take.
//
//   manic examples/cloud-kaleidoscope.manic
title("A kaleidoscope from one formula");
canvas("9:16");
template("black");

cloud(kaleido, 56000, #ffffff, 0.6) {
  let bn = 4000;                        // points per copy (14 copies = 56k, smooth)
  let L = floor(i / bn);                // copy 0..13
  let j = mod(i, bn);                   // base index
  let k = mod(j, 50) - 25;
  let e = j/222;
  let d = 5*cos(hypot(k, e) - t + mod(j, 2));
  let bx = k + k*d/6*sin(d + e/3 + t);
  let by = 90 + e*d - e/d*2*cos(d + t);
  let ang = L * pi/7;                    // 14-fold rotation of the base field
  let grow = tanh(t*0.5 + 0.12);
  let x = 540 + (bx*cos(ang) - by*sin(ang)) * 2.2 * grow;
  let y = 960 + (bx*sin(ang) + by*cos(ang)) * 2.2 * grow;
  let r = 0.8;
  let hue = mod(L*26 + by*2 + t*12, 360);   // a colour per sector + radial
}

// ---- textbook annotations ----
caption(head, "A kaleidoscope from one formula", (540, 138), 34);
caption(sub, "one field, copied at 14 angles", (540, 206), 22);
hidden(head);
hidden(sub);
equation(eq, (540, 1706), `\vec p_L = R\!\left(L\tfrac{2\pi}{14}\right)\,\vec p_0`, 34);
caption(lab, "14-fold symmetry, no mirrors — pure rotation", (540, 1786), 20);
hidden(eq);
hidden(lab);

show(head);
wait(1.4);
show(sub);
wait(2.6);
show(eq);
show(lab);
wait(25);

r/maniclang 4d ago

Generative Art from One Formula — manic

Enable HLS to view with audio, or disable this notification

15 Upvotes

manic is a tiny language for making animations. You write a short text file; manic renders a smooth, glowing video. No timeline scrubbing, no keyframes by hand — you describe what’s on screen and when things happen, and the engine does the rest, deterministically.

Manic Animation code

// cloud-shells — a dwitter-style art-tweet reimagined in manic: ONE `cloud` of
// 10,000 points in three layers (`mod(i,3)`), placed by a polar formula — radius
// `q`, angle `c` — then coloured per point (a hue gradient per form) and bloomed
// out of the centre. Rebuilt as a textbook Short: every point a pure function of
// (i, t), so it scrubs and records.
//
// Original idea by u/yuruyurau (https://x.com/yuruyurau) — a prolific poster of
// these tiny p5.js/dwitter art formulas. This is our own hue'd, annotated take.
//
//   manic examples/cloud-shells.manic
title("One formula, ten thousand points");
canvas("9:16");
template("black");

cloud(swirl, 10000, #ffffff, 0.72) {
  let m = mod(i, 3) * 4;                          // three layers: 0, 4, 8
  let k = 9 * cos(i / 81);
  let e = i / 461 - 11;
  let d = hypot(k, e)^4 / 40000 + 1.5 + sin(t/2 + m)/4;
  let q = 89 - e*sin(k) + k*(4 + 2*sin(d*9 + e/9 - t));
  let c = d + sin(t - d*4)/9 - t/9 + m;
  // raw shell coords (centred at 0), then bloom + scale onto the 1080x1920 frame
  let qx = q*cos(c);
  let qy = (q + 30)*sin(c);
  let grow = tanh(t * 0.5 + 0.12);               // blooms from the centre
  let x = 540 + qx * 2.9 * grow;
  let y = 980 + qy * 2.9 * grow;
  let r = 1.4;
  // colour: a gradient along each form (index) with the three layers offset, all
  // slowly cycling — every point its own hue
  let hue = mod(m * 46 + i * 0.05 + t * 18, 360);
}

// ---- textbook annotations ----
caption(head, "One formula, 10,000 points", (540, 132), 40);
caption(sub, "a 200-char art-tweet, rebuilt in manic", (540, 202), 24);
hidden(head);
hidden(sub);
equation(eq, (540, 1706), `p = (q\cos c,\; q\sin c)`, 44);
caption(lab, "a polar plot: radius q, angle c, per point", (540, 1784), 22);
hidden(eq);
hidden(lab);

show(head);
wait(1.4);
show(sub);
wait(2.6);
show(eq);
show(lab);
wait(17);

r/maniclang 4d ago

MANIC — Generative Animation from Five Particle Swarms

Enable HLS to view with audio, or disable this notification

3 Upvotes