experimental backend WebGL2 · not opted in
Enable WebGPU controls in settings. WebGL2 remains unchanged. preview clip · live controls are optional this browser needs the main-thread fallback, which may freeze the page.
140.00
0.65
0.00
2.00
off
0.00
-1
/*{ "DESCRIPTION": "procedural, beat-synced 90s rave poster generator. A new flyer every 8 beats: bitmap type, smileys, checker tunnels, contour echoes, halftone crowds, glitch cuts. Pure math, no textures.", "CREDIT": "CC0", "ISFVSN": "2", "CATEGORIES": ["Generator", "Retro", "Text"], "INPUTS": [ { "NAME": "bpm", "LABEL": "BPM", "TYPE": "float", "DEFAULT": 140.0, "MIN": 60.0, "MAX": 200.0 }, { "NAME": "chaos", "LABEL": "Chaos", "TYPE": "float", "DEFAULT": 0.65, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "kick", "LABEL": "Kick (map to audio)", "TYPE": "float", "DEFAULT": 0.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "firstPoster", "LABEL": "First poster", "TYPE": "float", "DEFAULT": 2.0, "MIN": 0.0, "MAX": 63.0 }, { "NAME": "holdPoster", "LABEL": "Hold poster", "TYPE": "bool", "DEFAULT": false }, { "NAME": "seed", "LABEL": "Seed", "TYPE": "float", "DEFAULT": 0.0, "MIN": 0.0, "MAX": 99.0 }, { "NAME": "layoutLock", "LABEL": "Layout", "TYPE": "long", "DEFAULT": -1, "VALUES": [-1, 0, 1, 2, 3, 4, 5], "LABELS": ["Auto", "Header slab", "Echo contours", "Acid stack", "Lineup smiley", "Side spine", "Zine grid"] } ] }*/ // ==================================================================== // RAVE.GEN - procedural, beat-synced 90s rave poster generator // single pass, no textures: bitmap font, SDF graphics, halftones, // photocopy edges, glitch cuts. Everything below is pure math. // // Written in the GLSL ES 1.00 / GLSL 1.10 subset so one source runs in // ISF hosts, WebGL1, Shadertoy and TouchDesigner: no integer bit ops, // no const arrays (tables are generated lookup functions), constant // loop bounds only. // ==================================================================== #ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; precision highp int; #else precision mediump float; precision mediump int; #endif #endif #define PI 3.14159265359 #define TAU 6.28318530718 // ---------- frame globals (set in rave()) ---------- float gT; // seconds float gBeat; // beats since start float gKick; // 0..1 envelope, peaks on every beat float gChaos; // 0..1 float gPX; // one pixel in poster units (poster height = 1) float gW; // poster width (aspect) float gRough; // per-pixel edge jitter, gives the boiling xerox edge float gPhoto; // photo-input luminance for this pixel, < 0 = none int gLay; // forced layout, < 0 = generator picks vec3 cP, cI, cA; // paper, ink, accent // rarely-set text item extras (reset before each text item is built) float gTScr, gTWob, gTA; // scroll in chars, headline wobble, alpha bool gTRep; // repeat endlessly (marquees) // ---------- generated by build.py: 5x5 font + word tables ---------- // glyph bitmap split in two exact-in-float halves: (rows 0-2, rows 3-4) vec2 fontBits(float c) { if (c < 24.0) { if (c < 12.0) { if (c < 6.0) { if (c < 3.0) { if (c < 1.0) { return vec2(14911.0, 561.0); } else { if (c < 2.0) { return vec2(31294.0, 574.0); } else { return vec2(15888.0, 527.0); } } } else { if (c < 4.0) { return vec2(31281.0, 574.0); } else { if (c < 5.0) { return vec2(32286.0, 543.0); } else { return vec2(32286.0, 528.0); } } } } else { if (c < 9.0) { if (c < 7.0) { return vec2(15891.0, 559.0); } else { if (c < 8.0) { return vec2(17983.0, 561.0); } else { return vec2(31876.0, 159.0); } } } else { if (c < 10.0) { return vec2(1057.0, 558.0); } else { if (c < 11.0) { return vec2(18012.0, 593.0); } else { return vec2(16912.0, 543.0); } } } } } else { if (c < 18.0) { if (c < 15.0) { if (c < 13.0) { return vec2(18293.0, 561.0); } else { if (c < 14.0) { return vec2(18229.0, 625.0); } else { return vec2(14897.0, 558.0); } } } else { if (c < 16.0) { return vec2(31294.0, 528.0); } else { if (c < 17.0) { return vec2(14901.0, 589.0); } else { return vec2(31294.0, 593.0); } } } } else { if (c < 21.0) { if (c < 19.0) { return vec2(15886.0, 62.0); } else { if (c < 20.0) { return vec2(31876.0, 132.0); } else { return vec2(17969.0, 558.0); } } } else { if (c < 22.0) { return vec2(17969.0, 324.0); } else { if (c < 23.0) { return vec2(17973.0, 881.0); } else { return vec2(17732.0, 337.0); } } } } } } else { if (c < 36.0) { if (c < 30.0) { if (c < 27.0) { if (c < 25.0) { return vec2(17732.0, 132.0); } else { if (c < 26.0) { return vec2(31812.0, 287.0); } else { return vec2(14965.0, 814.0); } } } else { if (c < 28.0) { return vec2(4484.0, 142.0); } else { if (c < 29.0) { return vec2(30766.0, 543.0); } else { return vec2(30766.0, 62.0); } } } } else { if (c < 33.0) { if (c < 31.0) { return vec2(17983.0, 33.0); } else { if (c < 32.0) { return vec2(32286.0, 62.0); } else { return vec2(14878.0, 558.0); } } } else { if (c < 34.0) { return vec2(31778.0, 132.0); } else { if (c < 35.0) { return vec2(14894.0, 558.0); } else { return vec2(14895.0, 46.0); } } } } } else { if (c < 42.0) { if (c < 39.0) { if (c < 37.0) { return vec2(0.0, 0.0); } else { if (c < 38.0) { return vec2(4228.0, 4.0); } else { return vec2(14.0, 0.0); } } } else { if (c < 40.0) { return vec2(4224.0, 0.0); } else { if (c < 41.0) { return vec2(12877.0, 589.0); } else { return vec2(0.0, 4.0); } } } } else { if (c < 45.0) { if (c < 43.0) { return vec2(1092.0, 272.0); } else { if (c < 44.0) { return vec2(128.0, 128.0); } else { return vec2(142.0, 128.0); } } } else { if (c < 46.0) { return vec2(21983.0, 469.0); } else { if (c < 47.0) { return vec2(14886.0, 4.0); } else { return vec2(0.0, 136.0); } } } } } } } // text store leaves vec4 txtLeaf(float k) { if (k < 59.0) { if (k < 29.0) { if (k < 14.0) { if (k < 7.0) { if (k < 3.0) { if (k < 1.0) { return vec4(1134609.0, 819328.0, 4866957.0, 3948811.0); } else { if (k < 2.0) { return vec4(4456911.0, 4513923.0, 5506116.0, 3467524.0); } else { return vec4(3490381.0, 4997830.0, 3436676.0, 3441422.0); } } } else { if (k < 5.0) { if (k < 4.0) { return vec4(90317.0, 5563345.0, 4469828.0, 1066312.0); } else { return vec4(1897732.0, 33870.0, 4792321.0, 2622736.0); } } else { if (k < 6.0) { return vec4(90378.0, 3698961.0, 1852564.0, 4473816.0); } else { return vec4(62609.0, 5316866.0, 3466369.0, 524936.0); } } } } else { if (k < 10.0) { if (k < 8.0) { return vec4(9449986.0, 4801415.0, 5288900.0, 4719377.0); } else { if (k < 9.0) { return vec4(5538962.0, 2928644.0, 1606500.0, 4474055.0); } else { return vec4(5301393.0, 2891981.0, 1078400.0, 4473815.0); } } } else { if (k < 12.0) { if (k < 11.0) { return vec4(3424785.0, 1118466.0, 86549.0, 6304651.0); } else { return vec4(1123480.0, 6292248.0, 2932999.0, 6309006.0); } } else { if (k < 13.0) { return vec4(4539288.0, 1356050.0, 5129032.0, 5292295.0); } else { return vec4(558228.0, 840197.0, 5825602.0, 3408067.0); } } } } } else { if (k < 21.0) { if (k < 17.0) { if (k < 15.0) { return vec4(4997261.0, 9482952.0, 4735443.0, 3679060.0); } else { if (k < 16.0) { return vec4(4735758.0, 3470628.0, 1094798.0, 2175940.0); } else { return vec4(4764360.0, 2167636.0, 1069330.0, 1913540.0); } } } else { if (k < 19.0) { if (k < 18.0) { return vec4(409863.0, 2172032.0, 3770637.0, 3675220.0); } else { return vec4(4735822.0, 1066053.0, 4539288.0, 840204.0); } } else { if (k < 20.0) { return vec4(3466435.0, 5009800.0, 524559.0, 5563076.0); } else { return vec4(3490069.0, 4555976.0, 1111172.0, 4752578.0); } } } } else { if (k < 25.0) { if (k < 23.0) { if (k < 22.0) { return vec4(1915154.0, 2937732.0, 4771864.0, 2953494.0); } else { return vec4(1123211.0, 5301796.0, 2901137.0, 3442949.0); } } else { if (k < 24.0) { return vec4(1915149.0, 5294340.0, 1319442.0, 9450312.0); } else { return vec4(5301796.0, 2901137.0, 3442949.0, 1078500.0); } } } else { if (k < 27.0) { if (k < 26.0) { return vec4(4466948.0, 800142.0, 1057600.0, 2917604.0); } else { return vec4(934603.0, 3986816.0, 1056772.0, 5563108.0); } } else { if (k < 28.0) { return vec4(5390613.0, 6369805.0, 4736100.0, 4989199.0); } else { return vec4(4801299.0, 2244744.0, 1915154.0, 3410180.0); } } } } } } else { if (k < 44.0) { if (k < 36.0) { if (k < 32.0) { if (k < 30.0) { return vec4(1139853.0, 9495377.0, 1065682.0, 2177295.0); } else { if (k < 31.0) { return vec4(9482952.0, 4510994.0, 3425416.0, 5009800.0); } else { return vec4(148627.0, 1458449.0, 934990.0, 2106176.0); } } } else { if (k < 34.0) { if (k < 33.0) { return vec4(287560.0, 1626641.0, 5301796.0, 1927441.0); } else { return vec4(5054983.0, 2883851.0, 2152715.0, 9515462.0); } } else { if (k < 35.0) { return vec4(3465956.0, 1118534.0, 3770628.0, 3294292.0); } else { return vec4(840204.0, 2900229.0, 1078500.0, 4718692.0); } } } } else { if (k < 40.0) { if (k < 38.0) { if (k < 37.0) { return vec4(1914002.0, 5265668.0, 1119507.0, 9511460.0); } else { return vec4(5825380.0, 3208859.0, 8538532.0, 1123072.0); } } else { if (k < 39.0) { return vec4(1118340.0, 3717395.0, 2174978.0, 3441486.0); } else { return vec4(9494861.0, 1102347.0, 9316004.0, 6940962.0); } } } else { if (k < 42.0) { if (k < 41.0) { return vec4(8013722.0, 47002.0, 4788498.0, 3033892.0); } else { return vec4(1860107.0, 11682963.0, 2729956.0, 1606756.0); } } else { if (k < 43.0) { return vec4(4456902.0, 4513923.0, 5282052.0, 1094029.0); } else { return vec4(1128708.0, 3723714.0, 819328.0, 5300708.0); } } } } } else { if (k < 51.0) { if (k < 47.0) { if (k < 45.0) { return vec4(9454740.0, 17473.0, 16458.0, 558291.0); } else { if (k < 46.0) { return vec4(4997762.0, 8239378.0, 9491364.0, 9454035.0); } else { return vec4(3727588.0, 3727569.0, 3818641.0, 9490703.0); } } } else { if (k < 49.0) { if (k < 48.0) { return vec4(4040420.0, 1118540.0, 63748.0, 2983121.0); } else { return vec4(1135115.0, 9438180.0, 2373932.0, 9619730.0); } } else { if (k < 50.0) { return vec4(4727588.0, 9498636.0, 3441551.0, 3467539.0); } else { return vec4(1915149.0, 2152708.0, 7680454.0, 1118244.0); } } } } else { if (k < 55.0) { if (k < 53.0) { if (k < 52.0) { return vec4(4719428.0, 674596.0, 2929159.0, 5063588.0); } else { return vec4(3741971.0, 4760334.0, 9585480.0, 594434.0); } } else { if (k < 54.0) { return vec4(2244610.0, 9495757.0, 1598733.0, 9585860.0); } else { return vec4(1332516.0, 9584837.0, 4866627.0, 6316430.0); } } } else { if (k < 57.0) { if (k < 56.0) { return vec4(3750168.0, 9516160.0, 9474276.0, 5051285.0); } else { return vec4(9531667.0, 9446180.0, 4767751.0, 9507091.0); } } else { if (k < 58.0) { return vec4(1078692.0, 9585348.0, 5128332.0, 3675220.0); } else { return vec4(3557646.0, 4879168.0, 345252.0, 1368982.0); } } } } } } } else { if (k < 88.0) { if (k < 73.0) { if (k < 66.0) { if (k < 62.0) { if (k < 60.0) { return vec4(9507077.0, 2105380.0, 2140419.0, 2771203.0); } else { if (k < 61.0) { return vec4(5013770.0, 4479239.0, 148238.0, 5300354.0); } else { return vec4(4797268.0, 1915172.0, 2889988.0, 9498884.0); } } } else { if (k < 64.0) { if (k < 63.0) { return vec4(2373924.0, 4998564.0, 582820.0, 4868362.0); } else { return vec4(4986130.0, 2151313.0, 411914.0, 2621713.0); } } else { if (k < 65.0) { return vec4(16458.0, 6419.0, 4473219.0, 43300.0); } else { return vec4(9511808.0, 5784642.0, 1915172.0, 526596.0); } } } } else { if (k < 69.0) { if (k < 67.0) { return vec4(9449986.0, 1643394.0, 9585800.0, 4866188.0); } else { if (k < 68.0) { return vec4(4981970.0, 9585288.0, 3555907.0, 1079566.0); } else { return vec4(3944452.0, 1102727.0, 3033362.0, 4473984.0); } } } else { if (k < 71.0) { if (k < 70.0) { return vec4(524625.0, 3295492.0, 5253378.0, 4457682.0); } else { return vec4(671953.0, 3724096.0, 5130509.0, 3436676.0); } } else { if (k < 72.0) { return vec4(5129101.0, 9585422.0, 266246.0, 4483328.0); } else { return vec4(3461137.0, 936216.0, 3221769.0, 6308552.0); } } } } } else { if (k < 80.0) { if (k < 76.0) { if (k < 74.0) { return vec4(936216.0, 80137.0, 1120535.0, 3478803.0); } else { if (k < 75.0) { return vec4(3295501.0, 2169090.0, 9585870.0, 856071.0); } else { return vec4(4513923.0, 30980.0, 1127564.0, 936209.0); } } } else { if (k < 78.0) { if (k < 77.0) { return vec4(6701635.0, 9495620.0, 9446180.0, 2679873.0); } else { return vec4(9490698.0, 5058826.0, 9584907.0, 3555907.0); } } else { if (k < 79.0) { return vec4(3465485.0, 6961444.0, 2160931.0, 3465478.0); } else { return vec4(9585805.0, 9557661.0, 9449994.0, 3715492.0); } } } } else { if (k < 84.0) { if (k < 82.0) { if (k < 81.0) { return vec4(5055886.0, 9478280.0, 2888582.0, 9511752.0); } else { return vec4(5056804.0, 1053585.0, 2373924.0, 5300452.0); } } else { if (k < 83.0) { return vec4(1093716.0, 4457444.0, 9449738.0, 9446180.0); } else { return vec4(5288292.0, 3295511.0, 5323010.0, 4473807.0); } } } else { if (k < 86.0) { if (k < 85.0) { return vec4(4457873.0, 936196.0, 5318921.0, 4752461.0); } else { return vec4(9584914.0, 5915203.0, 1627025.0, 4457444.0); } } else { if (k < 87.0) { return vec4(9536721.0, 1118308.0, 1053312.0, 410816.0); } else { return vec4(9442177.0, 3932324.0, 3440659.0, 4719332.0); } } } } } } else { if (k < 103.0) { if (k < 95.0) { if (k < 91.0) { if (k < 89.0) { return vec4(4002066.0, 4797248.0, 2160932.0, 1126417.0); } else { if (k < 90.0) { return vec4(3168516.0, 9562404.0, 2679489.0, 7226500.0); } else { return vec4(43291.0, 9495449.0, 4030948.0, 5252164.0); } } } else { if (k < 93.0) { if (k < 92.0) { return vec4(9453652.0, 9474276.0, 4800530.0, 9453952.0); } else { return vec4(2942052.0, 411915.0, 2507592.0, 1057300.0); } } else { if (k < 94.0) { return vec4(4466948.0, 9586052.0, 3031619.0, 5784212.0); } else { return vec4(3215382.0, 575780.0, 5301412.0, 2771215.0); } } } } else { if (k < 99.0) { if (k < 97.0) { if (k < 96.0) { return vec4(4981898.0, 9553636.0, 1336576.0, 7750161.0); } else { return vec4(935645.0, 73860.0, 8235283.0, 4989860.0); } } else { if (k < 98.0) { return vec4(2167123.0, 9545508.0, 4764937.0, 7226560.0); } else { return vec4(3295259.0, 74816.0, 9292051.0, 278884.0); } } } else { if (k < 101.0) { if (k < 100.0) { return vec4(4457857.0, 5300676.0, 9322770.0, 2630531.0); } else { return vec4(3408586.0, 50307.0, 3733775.0, 9515848.0); } } else { if (k < 102.0) { return vec4(8241956.0, 1061716.0, 1915153.0, 4462852.0); } else { return vec4(1585681.0, 4751556.0, 803988.0, 4489252.0); } } } } } else { if (k < 110.0) { if (k < 106.0) { if (k < 104.0) { return vec4(1081681.0, 4075723.0, 9595148.0, 49187.0); } else { if (k < 105.0) { return vec4(9482944.0, 1860109.0, 4044499.0, 9595148.0); } else { return vec4(3147876.0, 1984412.0, 4789518.0, 7223515.0); } } } else { if (k < 108.0) { if (k < 107.0) { return vec4(9320155.0, 7748060.0, 7203047.0, 7469283.0); } else { return vec4(8824732.0, 3553447.0, 2959630.0, 9498884.0); } } else { if (k < 109.0) { return vec4(2917604.0, 5318923.0, 4752461.0, 9623812.0); } else { return vec4(5506148.0, 3467524.0, 3558244.0, 856071.0); } } } } else { if (k < 114.0) { if (k < 112.0) { if (k < 111.0) { return vec4(4513923.0, 9623812.0, 1627401.0, 11944203.0); } else { return vec4(1128749.0, 3723714.0, 150372.0, 9449986.0); } } else { if (k < 113.0) { return vec4(1985380.0, 1123211.0, 5301796.0, 2901137.0); } else { return vec4(2244939.0, 1915149.0, 5294340.0, 9445906.0); } } } else { if (k < 116.0) { if (k < 115.0) { return vec4(3033508.0, 524559.0, 9619716.0, 1135499.0); } else { return vec4(9619716.0, 5014356.0, 9619736.0, 4006161.0); } } else { if (k < 117.0) { return vec4(4989199.0, 4082468.0, 4866957.0, 3948811.0); } else { return vec4(157967.0, 0.0, 0.0, 0.0); } } } } } } } } // (first char, length) of words 2j and 2j+1 vec4 wordPair(float j) { if (j < 39.0) { if (j < 19.0) { if (j < 9.0) { if (j < 4.0) { if (j < 2.0) { if (j < 1.0) { return vec4(0.0, 4.0, 4.0, 4.0); } else { return vec4(8.0, 8.0, 16.0, 8.0); } } else { if (j < 3.0) { return vec4(24.0, 7.0, 31.0, 6.0); } else { return vec4(37.0, 6.0, 43.0, 8.0); } } } else { if (j < 6.0) { if (j < 5.0) { return vec4(51.0, 9.0, 60.0, 8.0); } else { return vec4(68.0, 9.0, 77.0, 9.0); } } else { if (j < 7.0) { return vec4(86.0, 10.0, 96.0, 8.0); } else { if (j < 8.0) { return vec4(104.0, 10.0, 114.0, 4.0); } else { return vec4(77.0, 9.0, 118.0, 7.0); } } } } } else { if (j < 14.0) { if (j < 11.0) { if (j < 10.0) { return vec4(125.0, 11.0, 136.0, 10.0); } else { return vec4(146.0, 10.0, 156.0, 7.0); } } else { if (j < 12.0) { return vec4(163.0, 7.0, 170.0, 6.0); } else { if (j < 13.0) { return vec4(176.0, 4.0, 180.0, 8.0); } else { return vec4(188.0, 6.0, 194.0, 5.0); } } } } else { if (j < 16.0) { if (j < 15.0) { return vec4(199.0, 4.0, 180.0, 8.0); } else { return vec4(188.0, 6.0, 203.0, 5.0); } } else { if (j < 17.0) { return vec4(208.0, 5.0, 213.0, 8.0); } else { if (j < 18.0) { return vec4(221.0, 3.0, 224.0, 8.0); } else { return vec4(232.0, 2.0, 234.0, 5.0); } } } } } } else { if (j < 29.0) { if (j < 24.0) { if (j < 21.0) { if (j < 20.0) { return vec4(239.0, 4.0, 243.0, 7.0); } else { return vec4(250.0, 4.0, 254.0, 8.0); } } else { if (j < 22.0) { return vec4(262.0, 7.0, 269.0, 5.0); } else { if (j < 23.0) { return vec4(274.0, 4.0, 278.0, 4.0); } else { return vec4(282.0, 4.0, 286.0, 7.0); } } } } else { if (j < 26.0) { if (j < 25.0) { return vec4(293.0, 5.0, 298.0, 4.0); } else { return vec4(302.0, 5.0, 307.0, 7.0); } } else { if (j < 27.0) { return vec4(194.0, 5.0, 314.0, 6.0); } else { if (j < 28.0) { return vec4(320.0, 4.0, 324.0, 6.0); } else { return vec4(330.0, 26.0, 356.0, 26.0); } } } } } else { if (j < 34.0) { if (j < 31.0) { if (j < 30.0) { return vec4(382.0, 15.0, 397.0, 24.0); } else { return vec4(421.0, 19.0, 440.0, 21.0); } } else { if (j < 32.0) { return vec4(461.0, 22.0, 483.0, 18.0); } else { if (j < 33.0) { return vec4(501.0, 14.0, 515.0, 14.0); } else { return vec4(529.0, 13.0, 542.0, 17.0); } } } } else { if (j < 36.0) { if (j < 35.0) { return vec4(559.0, 10.0, 569.0, 15.0); } else { return vec4(584.0, 22.0, 606.0, 25.0); } } else { if (j < 37.0) { return vec4(631.0, 22.0, 653.0, 20.0); } else { if (j < 38.0) { return vec4(673.0, 22.0, 695.0, 15.0); } else { return vec4(710.0, 10.0, 720.0, 19.0); } } } } } } } else { if (j < 59.0) { if (j < 49.0) { if (j < 44.0) { if (j < 41.0) { if (j < 40.0) { return vec4(739.0, 22.0, 761.0, 25.0); } else { return vec4(786.0, 4.0, 792.0, 17.0); } } else { if (j < 42.0) { return vec4(811.0, 5.0, 818.0, 14.0); } else { if (j < 43.0) { return vec4(834.0, 9.0, 845.0, 16.0); } else { return vec4(863.0, 8.0, 873.0, 15.0); } } } } else { if (j < 46.0) { if (j < 45.0) { return vec4(890.0, 8.0, 900.0, 19.0); } else { return vec4(921.0, 9.0, 932.0, 11.0); } } else { if (j < 47.0) { return vec4(945.0, 9.0, 956.0, 16.0); } else { if (j < 48.0) { return vec4(974.0, 9.0, 985.0, 15.0); } else { return vec4(1002.0, 9.0, 1013.0, 16.0); } } } } } else { if (j < 54.0) { if (j < 51.0) { if (j < 50.0) { return vec4(1031.0, 9.0, 1042.0, 17.0); } else { return vec4(1061.0, 10.0, 1073.0, 12.0); } } else { if (j < 52.0) { return vec4(1087.0, 9.0, 1098.0, 13.0); } else { if (j < 53.0) { return vec4(1113.0, 7.0, 1122.0, 16.0); } else { return vec4(1140.0, 7.0, 1149.0, 16.0); } } } } else { if (j < 56.0) { if (j < 55.0) { return vec4(1167.0, 7.0, 1176.0, 11.0); } else { return vec4(1189.0, 7.0, 1198.0, 17.0); } } else { if (j < 57.0) { return vec4(1217.0, 6.0, 1225.0, 16.0); } else { if (j < 58.0) { return vec4(1243.0, 7.0, 1252.0, 13.0); } else { return vec4(1267.0, 10.0, 1279.0, 14.0); } } } } } } else { if (j < 69.0) { if (j < 64.0) { if (j < 61.0) { if (j < 60.0) { return vec4(1295.0, 13.0, 1310.0, 18.0); } else { return vec4(1330.0, 9.0, 1341.0, 16.0); } } else { if (j < 62.0) { return vec4(1359.0, 9.0, 1370.0, 15.0); } else { if (j < 63.0) { return vec4(1387.0, 14.0, 1403.0, 11.0); } else { return vec4(1416.0, 7.0, 1426.0, 10.0); } } } } else { if (j < 66.0) { if (j < 65.0) { return vec4(1436.0, 10.0, 1446.0, 10.0); } else { return vec4(1456.0, 10.0, 1466.0, 10.0); } } else { if (j < 67.0) { return vec4(1476.0, 10.0, 569.0, 15.0); } else { if (j < 68.0) { return vec4(1486.0, 11.0, 1497.0, 9.0); } else { return vec4(1506.0, 13.0, 1519.0, 16.0); } } } } } else { if (j < 74.0) { if (j < 71.0) { if (j < 70.0) { return vec4(1535.0, 16.0, 559.0, 10.0); } else { return vec4(1551.0, 9.0, 1560.0, 9.0); } } else { if (j < 72.0) { return vec4(1569.0, 10.0, 1579.0, 8.0); } else { if (j < 73.0) { return vec4(1587.0, 4.0, 1591.0, 4.0); } else { return vec4(1595.0, 3.0, 1598.0, 3.0); } } } } else { if (j < 76.0) { if (j < 75.0) { return vec4(1601.0, 4.0, 1605.0, 4.0); } else { return vec4(1609.0, 3.0, 1612.0, 34.0); } } else { if (j < 77.0) { return vec4(1647.0, 36.0, 1684.0, 29.0); } else { if (j < 78.0) { return vec4(1714.0, 33.0, 786.0, 639.0); } else { return vec4(1748.0, 10.0, 0.0, 1.0); } } } } } } } } vec2 wordInfo(float w) { float j = floor(w * 0.5); vec4 v = wordPair(j); return w - 2.0 * j < 0.5 ? v.xy : v.zw; } // longest line of each four-line phrase float quadMax(int qi) { float q = float(qi); if (q < 4.0) { if (q < 2.0) { if (q < 1.0) { return 8.0; } else { return 8.0; } } else { if (q < 3.0) { return 8.0; } else { return 7.0; } } } else { if (q < 6.0) { if (q < 5.0) { return 8.0; } else { return 7.0; } } else { if (q < 7.0) { return 7.0; } else { return 6.0; } } } } #define G_HEAD 0 #define N_HEAD 16 #define G_HEAD2 16 #define N_HEAD2 8 #define G_QUAD 24 #define N_QUAD 8 #define G_TAG 56 #define N_TAG 12 #define G_INFO 68 #define N_INFO 12 #define G_DJ 80 #define N_DJ 47 #define G_DATE 127 #define N_DATE 6 #define G_PLACE 133 #define N_PLACE 6 #define G_HOUR 139 #define N_HOUR 5 #define G_YEAR 144 #define N_YEAR 7 #define G_MARQ 151 #define N_MARQ 4 #define W_LINEUP 155 #define W_NOSLEEP 156 struct Scene { float sd; int lay, bg, hero, pal, sty; int head, head2, tag, i0, i1, dj, quad, date, place, hour, yr, marq; bool echo, inv; }; // ---------- small integer helpers (ES 1.00 has no %, &, int min/clamp) ---------- int imod(int a, int b) { return a - (a / b) * b; } // a >= 0 int pickI(int n, float h) { return int(min(floor(h * float(n)), float(n - 1))); } int sel(int i, int a0, int a1, int a2, int a3, int a4, int a5, int a6) { if (i == 0) return a0; if (i == 1) return a1; if (i == 2) return a2; if (i == 3) return a3; if (i == 4) return a4; if (i == 5) return a5; return a6; } // ---------- palettes: paper / ink / accent ---------- void setPal(int i, bool inv) { if (i == 0) { cP = vec3(0.96, 0.88, 0.10); cI = vec3(0.07, 0.07, 0.07); cA = vec3(0.97, 0.96, 0.92); } // club yellow else if (i == 1) { cP = vec3(0.06, 0.06, 0.05); cI = vec3(0.98, 0.96, 0.55); cA = vec3(1.00, 0.45, 0.12); } // black + pale yellow else if (i == 2) { cP = vec3(0.82, 0.95, 0.22); cI = vec3(0.08, 0.08, 0.06); cA = vec3(0.95, 0.18, 0.50); } // lime flyer else if (i == 3) { cP = vec3(0.67, 0.50, 0.90); cI = vec3(0.10, 0.08, 0.10); cA = vec3(0.98, 0.93, 0.30); } // purple warehouse else if (i == 4) { cP = vec3(0.50, 0.78, 0.92); cI = vec3(0.04, 0.06, 0.10); cA = vec3(0.98, 0.98, 0.98); } // photocopy blue else if (i == 5) { cP = vec3(0.03, 0.04, 0.10); cI = vec3(0.30, 1.00, 0.18); cA = vec3(1.00, 0.55, 0.05); } // acid neon else if (i == 6) { cP = vec3(0.97, 0.93, 0.86); cI = vec3(0.93, 0.14, 0.45); cA = vec3(0.15, 0.80, 0.40); } // pink + green on cream else if (i == 7) { cP = vec3(0.05, 0.03, 0.03); cI = vec3(0.90, 0.10, 0.07); cA = vec3(0.62, 1.00, 0.95); } // red contour / cyan else if (i == 8) { cP = vec3(0.02, 0.02, 0.02); cI = vec3(0.97, 0.97, 0.95); cA = vec3(1.00, 0.88, 0.10); } // black + white else if (i == 9) { cP = vec3(0.93, 0.91, 0.84); cI = vec3(0.06, 0.06, 0.06); cA = vec3(0.90, 0.20, 0.10); } // cream checker else if (i == 10) { cP = vec3(0.03, 0.02, 0.02); cI = vec3(1.00, 0.32, 0.08); cA = vec3(1.00, 0.85, 0.20); } // orange on black else { cP = vec3(1.00, 0.32, 0.70); cI = vec3(0.06, 0.04, 0.20); cA = vec3(0.20, 0.95, 1.00); } // hot pink if (inv) { vec3 t = cP; cP = cI; cI = t; } } // ---------- hashing / noise ---------- float h11(float p) { p = fract(p * 0.1031); p *= p + 33.33; p *= p + p; return fract(p); } float h21(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * 0.1031); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z); } vec2 h22(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973)); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.xx + p3.yz) * p3.zy); } float vnoise(vec2 p) { vec2 i = floor(p), f = fract(p), u = f * f * (3.0 - 2.0 * f); return mix(mix(h21(i), h21(i + vec2(1.0, 0.0)), u.x), mix(h21(i + vec2(0.0, 1.0)), h21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float s = 0.0, a = 0.5; for (int i = 0; i < 4; i++) { s += a * vnoise(p); p = p * 2.03 + 17.1; a *= 0.5; } return s; } mat2 rot(float a) { float c = cos(a), s = sin(a); return mat2(c, s, -s, c); } // ---------- 2D SDF kit ---------- float sdBox(vec2 p, vec2 b) { vec2 d = abs(p) - b; return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); } float sdRBox(vec2 p, vec2 b, float r) { return sdBox(p, b - r) - r; } float sdSeg(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a, ba = b - a; return length(pa - ba * clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0)); } float sdEll(vec2 p, vec2 r) { float k0 = length(p / r), k1 = length(p / (r * r)); return k0 * (k0 - 1.0) / max(k1, 1e-6); } float sdArc(vec2 p, vec2 sc, float ra, float rb) { p.x = abs(p.x); return ((sc.y * p.x > sc.x * p.y) ? length(p - sc * ra) : abs(length(p) - ra)) - rb; } float sdStar(vec2 p, float r, float n, float m) { // n points, m in [2,n] = sharpness float an = PI / n, en = PI / m; vec2 acs = vec2(cos(an), sin(an)), ecs = vec2(cos(en), sin(en)); float bn = mod(atan(p.x, p.y), 2.0 * an) - an; p = length(p) * vec2(cos(bn), abs(sin(bn))); p -= r * acs; p += ecs * clamp(-dot(p, ecs), 0.0, r * acs.y / ecs.y); return length(p) * sign(p.x); } float smin(float a, float b, float k) { float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0); return mix(b, a, h) - k * h * (1.0 - h); } // coverage: 1px AA plus the boiling photocopy edge float fillD(float d) { return clamp(0.5 - (d + gRough) / gPX, 0.0, 1.0); } float strokeD(float d, float w) { return fillD(abs(d) - w); } void paint(inout vec3 col, vec3 c, float m) { col = mix(col, c, clamp(m, 0.0, 1.0)); } float lum(vec3 c) { return dot(c, vec3(0.299, 0.587, 0.114)); } vec3 inkOn(vec3 bg) { return abs(lum(bg) - lum(cI)) < 0.3 ? cP : cI; } // ink that reads on bg vec3 accOn() { return abs(lum(cA) - lum(cP)) < 0.22 ? cI : cA; } // accent that reads on paper // ==================================================================== // BITMAP FONT (5x5 glyphs, rendered as an SDF of font pixels) // ==================================================================== #define SOLID vec3(0.0, 0.0, 0.16) // glyph index at offset o (0..15) of a text-store leaf (4 floats x 4 six-bit chars) float charIn(vec4 lf, float o) { float comp = floor(o / 4.0); float sub = o - comp * 4.0; float v = dot(lf, vec4(equal(vec4(comp), vec4(0.0, 1.0, 2.0, 3.0)))); float inv = sub < 0.5 ? 1.0 : (sub < 1.5 ? 0.015625 : (sub < 2.5 ? 0.000244140625 : 0.000003814697265625)); return mod(floor(v * inv), 64.0); } // glyph indices of store characters idx and idx+1 (leaves overlap by one, so one lookup) vec2 charPair(float idx) { float k = floor((idx + 0.5) / 15.0); float o = idx - 15.0 * k; vec4 lf = txtLeaf(k); return vec2(charIn(lf, o), charIn(lf, o + 1.0)); } // signed distance to a line of text // org = bottom-left of first cell, cs = cell size (6x5 font pixels incl. spacing) // start/L = the word's characters, scr = scroll in characters, rep = endless repeat // sh = (corner rounding, extra bold, horizontal stem bold) in font pixels float sdText(vec2 p, vec2 org, vec2 cs, float start, float L, float scr, bool rep, vec3 sh) { vec2 q = (p - org) / cs; if (q.y < -0.35 || q.y > 1.35) return 1.0; if (rep) q.x += mod(scr, L); else if (q.x < -0.35 || q.x > L + 0.2) return 1.0; vec2 u = cs / vec2(6.0, 5.0); float mu = min(u.x, u.y); vec2 hb = 0.5 * u + vec2(sh.z * u.x, 0.0); float rr = sh.x * mu; vec2 g = q * vec2(6.0, 5.0); vec2 gi = floor(g - 0.5); // nearest 2x2 font pixels: gi .. gi+1 // (all styles stay within half a font pixel of the glyph, so 2x2 is exact enough) // the 2x2 block touches at most two characters (c0, c0+1): fetch both once. // Repeating words are stored with their first char appended, so c0+1 never wraps. float c0 = floor((gi.x + 0.5) / 6.0); float b = rep ? c0 - L * floor((c0 + 0.5) / L) : c0; bool shift = b < -0.5; // left of a plain word: only c0+1 can show vec2 cp = charPair(start + b + (shift ? 1.0 : 0.0)); bool v0 = !shift && (rep || b < L - 0.5); bool v1 = rep || (b > -1.5 && b < L - 1.5); vec2 g0 = vec2(0.0), g1 = vec2(0.0); for (int q = 0; q < 2; q++) { // loop keeps one copy of the font table if (q == 0 ? !v0 : !v1) continue; vec2 gb = fontBits(q == 0 ? cp.x : (shift ? cp.x : cp.y)); if (q == 0) g0 = gb; else g1 = gb; } float d = 1.0; for (int j = 0; j < 2; j++) { float cy = gi.y + float(j); if (cy < 0.0 || cy > 4.0) continue; for (int i = 0; i < 2; i++) { float cx = gi.x + float(i); float ci = floor((cx + 0.5) / 6.0); float cc = cx - ci * 6.0; if (cc > 4.5) continue; vec2 gl = ci < c0 + 0.5 ? g0 : g1; float bi = cy * 5.0 + 4.0 - cc; // bit index 0..24 float half_ = bi < 9.5 ? gl.y : gl.x; float e = bi < 9.5 ? bi : bi - 10.0; if (mod(floor((half_ + 0.5) / exp2(e)), 2.0) < 0.5) continue; vec2 lp = (g - vec2(cx, cy) - 0.5) * u; d = min(d, sh.x > 0.49 ? length(lp) - 0.5 * mu : sdRBox(lp, hb, rr)); } } return d - sh.y * mu - 0.6 * gPX; } // headline styles: 0 block, 1 dot-matrix, 2 outline, 3 bubble, 4 drop shadow vec3 styShape(int sty) { if (sty == 1) return vec3(0.5, -0.06, 0.0); if (sty == 2) return vec3(0.0, 0.25, 0.0); if (sty == 3) return vec3(0.42, 0.28, 0.12); return SOLID; } float textMask(float d, int sty, vec2 cs) { if (sty == 2) return strokeD(d, 0.09 * min(cs.x / 6.0, cs.y / 5.0) + 0.3 * gPX); return fillD(d); } // Each layout describes its type as text items. Text lines never overlap, so // every pixel picks the one item that can cover it (textSlot) and a single // shared renderer sizes and draws it - the word tables and glyph loop exist // once in the compiled shader, which keeps WebGL / ISF compile times short. // sz = (bw, cxm, cym, st): // cell width = min(bw / (len - 1/6), cxm), cell height = min(cym, width * st) // origin = anc - (text width, cell height) * aln // The item lands in the t* globals; scroll / repeat / wobble / alpha are the gT* globals. vec2 tP, tAnc, tAln; vec4 tSz; int tW, tSty; vec3 tCol; void tItem(vec2 p, vec2 anc, vec2 aln, int w, vec4 sz, int sty, vec3 col) { tP = p; tAnc = anc; tAln = aln; tSz = sz; tW = w; tSty = sty; tCol = col; } // ==================================================================== // BACKGROUNDS -> (ink coverage, ink->accent mix) // ==================================================================== float ripField(vec2 c, float sd) { return fbm(c * 1.5 + vec2(sd * 3.7, gT * 0.1)) * 2.2 + length(c * vec2(1.0, 0.8)) * 1.4 + 0.12 * gKick; } float halftone(vec2 p, float v, float cell) { vec2 f = fract(rot(0.785398) * p / cell) - 0.5; return fillD((length(f) - sqrt(clamp(v, 0.0, 1.0)) * 0.6) * cell); } vec2 background(vec2 c, int type, float sd) { float r = length(c); if (type == 0) { // warped checkerboard if (h11(sd * 3.1) < 0.5) { vec2 q = rot(2.4 * sin(gT * 0.45 + sd) * exp(-r * 2.2) + gT * 0.12) * c; float sc = 7.0 + 2.0 * h11(sd); q *= sc; q += 0.4 * vec2(sin(q.y * 0.6 + gT * 1.3), cos(q.x * 0.6 - gT * 1.1)); float fw = PI * sc * gPX * 1.6; return vec2(0.5 + 0.5 * clamp(sin(q.x * PI) / fw, -1.0, 1.0) * clamp(sin(q.y * PI) / fw, -1.0, 1.0), 0.0); } float a = atan(c.y, c.x); // log-polar checker tunnel float u = a / TAU * 16.0 + gT * 0.2 + 0.35 * sin(r * 9.0 - gT * 2.0); float z = log(r + 1e-4) * 5.0 - gT * 1.5; float fu = PI * (16.0 / TAU / max(r, 1e-3) + 3.2) * gPX * 1.3; float fz = PI * 5.0 / max(r, 1e-3) * gPX * 1.3; return vec2(0.5 + 0.5 * clamp(sin(u * PI) / fu, -1.0, 1.0) * clamp(sin(z * PI) / fz, -1.0, 1.0), 0.0); } if (type == 1) { // wireframe box tunnel vec2 q = rot(0.2 * sin(gT * 0.35 + sd)) * c + 0.03 * vec2(sin(gT * 0.7), cos(gT * 0.5)); float ax = abs(q.x), ay = abs(q.y), m = max(max(ax, ay), 1e-3); float zz = 0.3 / m + gT * 1.8; float dz = abs(fract(zz + 0.5) - 0.5) * m * m / 0.3; float u = (ax > ay ? q.y : q.x) / m; float du = abs(fract(u * 3.0 + 0.5) - 0.5) * m / 3.0; float w = 0.0012 + 0.01 * m; float ln = max(fillD(dz - w), fillD(du - w)) * smoothstep(0.02, 0.12, m); return vec2(ln, smoothstep(0.08, 0.45, m)); } if (type == 2) { // contour ripples float f0 = ripField(c, sd); vec2 gr = vec2(ripField(c + vec2(gPX, 0.0), sd) - f0, ripField(c + vec2(0.0, gPX), sd) - f0) / gPX; float N = 6.0 + 4.0 * h11(sd * 5.3); float v = f0 * N - gT * 0.9; float gl = max(length(gr) * N, 1e-3); float d = h11(sd * 7.7) < 0.5 ? (abs(fract(v) - 0.5) - 0.25) / gl : abs(fract(v + 0.5) - 0.5) / gl - 0.0025; return vec2(fillD(d), 0.0); } if (type == 3) { // halftone shock rings float v = 0.5 + 0.5 * sin(r * 10.0 - gT * 3.0 + fbm(c * 2.5 + sd) * 4.0); v = v * (1.0 - smoothstep(0.25, 0.95, r)) + 0.2 * gKick; return vec2(halftone(c, v, 0.016), 0.0); } if (type == 4) { // sunburst float a = atan(c.y, c.x); float N = 18.0 + 2.0 * floor(h11(sd * 2.9) * 6.0); float u = a / TAU * N + gT * 0.15 + 0.25 * sin(r * 7.0 - gT * 2.5); float d = (abs(fract(u) - 0.5) - 0.25) * TAU * r / N; return vec2(fillD(d) * smoothstep(0.0, 0.04, r), 0.0); } if (type == 6) { // op-art moire vec2 a = vec2(sin(gT * 0.6), cos(gT * 0.45)) * 0.2; vec2 b = vec2(cos(gT * 0.37 + 1.0), sin(gT * 0.52)) * 0.22; float k = 30.0; float m1 = fillD((abs(fract(length(c - a) * k) - 0.5) - 0.25) / k); float m2 = fillD((abs(fract(length(c - b) * k) - 0.5) - 0.25) / k); return vec2(m1 + m2 - 2.0 * m1 * m2, 0.0); } // 5: plain stock with drifting sparkles vec2 g = c * 6.0 + vec2(0.0, gT * 0.2); vec2 id = floor(g), f = fract(g) - 0.5; float h = h21(id + sd); if (h > 0.78) { vec2 o = (h22(id + sd) - 0.5) * 0.4; float s = 0.18 * (0.6 + 0.4 * sin(gT * 4.0 + h * 40.0)); return vec2(fillD(sdStar(rot(gT * (h - 0.9) * 4.0) * (f - o), s, 4.0, 2.3) / 6.0), 0.0); } return vec2(0.0); } // ==================================================================== // HERO GRAPHICS -> (ink sdf, silhouette sdf) // ==================================================================== vec3 smileyShape(vec2 p, float R, bool filled) { // (ink, face, features) float face = length(p) - R; float bl = 1.0 - smoothstep(0.0, 0.05, abs(fract(gBeat * 0.25 + 0.4) - 0.05)); vec2 ep = vec2(abs(p.x) - 0.33 * R, p.y - 0.2 * R); float eye = sdEll(ep, vec2(0.1, mix(0.19, 0.03, bl)) * R); float ta = 1.0 + 0.25 * gKick; float mouth = sdArc(vec2(p.x, -p.y), vec2(sin(ta), cos(ta)), 0.58 * R, 0.06 * R); float feat = min(eye, mouth); float ink = filled ? max(face, -feat) : min(abs(face) - 0.045 * R, feat); return vec3(ink, face, feat); } vec2 globe(vec2 p, float R, Scene s) { float r = length(p); float sil = r - R; float lw = R * 0.018; float ink = abs(sil) - lw * 1.3; if (r < R) { float z = sqrt(max(R * R - r * r, 0.0)) / R; float ay = gT * 0.6 + s.sd, ax = 0.35 + 0.25 * sin(gT * 0.3); float lonN = 10.0 + 2.0 * floor(h11(s.sd) * 3.0); for (int k = 0; k < 2; k++) { vec3 q = vec3(p / R, k == 0 ? z : -z); q.yz = rot(ax) * q.yz; q.xz = rot(ay) * q.xz; float lat = asin(clamp(q.y, -1.0, 1.0)); float lon = atan(q.x, q.z); float dLon = abs(fract(lon / TAU * lonN + 0.5) - 0.5) * TAU / lonN * cos(lat) * R; float dLat = abs(fract(lat / PI * 8.0 + 0.5) - 0.5) * PI / 8.0 * R; ink = min(ink, min(dLon, dLat) - (k == 0 ? lw : lw * 0.45)); } } return vec2(ink, sil); } vec2 burst(vec2 p, float R, Scene s) { float n = floor(9.0 + 10.0 * h11(s.sd * 1.7)); float m = mix(2.1, 3.2, h11(s.sd * 2.3)); float r = length(p); float st = sdStar(rot(gT * 0.4 + gKick * 0.2) * p, R * (0.9 + 0.1 * gKick), n, m); float ink = max(st, -(r - R * 0.38)); ink = min(ink, r - R * 0.28); ink = min(ink, abs(r - R * 1.1) - R * 0.022); return vec2(ink, r - R * 1.14); } vec2 butterfly(vec2 p, float R) { float flap = 0.72 + 0.28 * cos(gBeat * PI); p.x /= flap; vec2 q = vec2(abs(p.x), p.y); vec2 a = rot(-0.5) * (q - vec2(0.46, 0.24) * R); vec2 b = rot(0.6) * (q - vec2(0.3, -0.3) * R); float up = sdEll(a, vec2(0.46, 0.34) * R); float lo = sdEll(b, vec2(0.3, 0.22) * R); float body = sdEll(p - vec2(0.0, -0.02 * R), vec2(0.06, 0.42) * R); float shape = smin(smin(up, lo, 0.06 * R), body, 0.04 * R); shape = min(shape, sdSeg(q, vec2(0.02, 0.36) * R, vec2(0.16, 0.62) * R) - 0.016 * R); float holes = min(sdEll(a + vec2(0.03, 0.0) * R, vec2(0.27, 0.17) * R), sdEll(b, vec2(0.15, 0.1) * R)); return vec2(max(shape, -holes), shape) * flap; } vec2 cubeProj(vec3 q, float a1, float a2, float R) { q.xz = rot(a1) * q.xz; q.yz = rot(a2) * q.yz; return q.xy * (3.0 / (4.0 + q.z)) * R * 0.62; } vec2 cube(vec2 p, float R, Scene s) { float d = 1e2; for (int c = 0; c < 2; c++) { float sc = c == 0 ? 1.0 : 0.5; float a1 = gT * (c == 0 ? 0.7 : -1.1) + s.sd, a2 = gT * (c == 0 ? 0.45 : -0.8) + 1.0; for (int e = 0; e < 12; e++) { // 4 edges along each axis float fe = float(e); float ax = floor(fe / 4.0); float j = fe - ax * 4.0; float u = mod(j, 2.0) * 2.0 - 1.0, v = floor(j / 2.0) * 2.0 - 1.0; vec3 ea = ax < 0.5 ? vec3(-1.0, u, v) : (ax < 1.5 ? vec3(u, -1.0, v) : vec3(u, v, -1.0)); vec3 eb = ax < 0.5 ? vec3( 1.0, u, v) : (ax < 1.5 ? vec3(u, 1.0, v) : vec3(u, v, 1.0)); d = min(d, sdSeg(p, cubeProj(ea * sc, a1, a2, R), cubeProj(eb * sc, a1, a2, R))); } } float ink = d - R * 0.02; return vec2(ink, ink); } vec2 swarm(vec2 p, float R, Scene s) { float ink = 1e2, sil = 1e2; for (int i = 0; i < 5; i++) { float fi = float(i); vec2 o = vec2(sin(gT * (0.6 + 0.13 * fi) + fi * 2.4 + s.sd), cos(gT * (0.47 + 0.11 * fi) + fi * 1.7)) * R * vec2(0.75, 0.7); float r = R * (0.22 + 0.1 * h11(fi + s.sd)) * (1.0 + 0.1 * gKick); vec3 sm = smileyShape(rot(sin(gT * 1.3 + fi) * 0.6) * (p - o), r, true); ink = min(ink, sm.x); sil = min(sil, sm.y); } return vec2(ink, sil); } vec2 vinyl(vec2 p, float R) { float r = length(p); float sil = r - R; float gs = R * 0.04; float a = atan(p.y, p.x); float shine = 1.0 - smoothstep(0.0, 0.3, abs(mod(a - 0.8 + PI * 0.5, PI) - PI * 0.5)); float groove = abs(fract(r / gs + 0.5) - 0.5) * gs - gs * (0.1 + 0.25 * shine); groove = max(groove, max(R * 0.42 - r, r - R * 0.95)); float ink = max(max(sil, -groove), -(r - R * 0.36)); vec2 lp = rot(gT * 3.49) * p; // two-tone label spinning at 33 rpm ink = min(ink, max(r - R * 0.3, lp.y)); ink = max(ink, -(length(lp - vec2(0.0, -0.16 * R)) - 0.045 * R)); ink = min(ink, length(lp - vec2(0.0, 0.16 * R)) - 0.045 * R); ink = max(ink, -(r - R * 0.025)); ink = min(ink, abs(r - R * 0.33) - R * 0.006); return vec2(ink, sil); } vec2 heroSD(vec2 p, float R, Scene s) { p = rot(0.15 * sin(gT * 0.9 + s.sd) * gChaos) * p; p *= 1.0 - 0.06 * gKick; if (s.hero == 0) return smileyShape(p, R, h11(s.sd * 4.4) < 0.5).xy; if (s.hero == 1) return globe(p, R, s); if (s.hero == 2) return burst(p, R, s); if (s.hero == 3) return butterfly(p, R); if (s.hero == 4) return cube(p, R, s); if (s.hero == 5) return swarm(p, R, s); return vinyl(p, R); } float echoRings(float d, vec2 p, float R) { // wobbly contour echoes around a shape if (d <= 0.0) return 0.0; float sp = R * 0.1; float an = atan(p.y, p.x); float wob = (sin(an * 6.0 + gT * 3.0) * 0.3 + sin(an * 11.0 - gT * 4.0) * 0.15) * (0.4 + gChaos); float dd = d + wob * sp * smoothstep(0.0, R * 0.6, d); float ring = abs(fract(dd / sp - gT * 0.6 + 0.5) - 0.5) * sp; float lw = sp * 0.2 * smoothstep(sp * 0.3, sp * 1.1, dd) * (1.0 - smoothstep(sp * 4.0, sp * 6.0, dd)); return lw > 0.0 ? fillD(ring - lw) : 0.0; } void drawHero(inout vec3 col, vec2 p, float R, Scene s, vec3 back, vec3 ink, vec3 ech, bool echo) { vec2 h = heroSD(p, R, s); if (echo) paint(col, ech, echoRings(h.y, p, R)); paint(col, back, fillD(min(h.y, h.x - R * 0.03))); // knock-out halo paint(col, ink, fillD(h.x)); } // ==================================================================== // PHOTO PANELS (halftoned crowd + lasers, or your own input) // ==================================================================== float crowd(vec2 q, float asp, float sd, float ph) { // q: x 0..asp, y 0..1 float px = gPX / ph; float v = 0.25 + 0.45 * fbm(q * vec2(3.0, 2.0) + vec2(gT * 0.15, sd)); vec2 dq = q - vec2(asp * (0.5 + 0.35 * sin(gT * 0.6 + sd)), 1.1); float fan = abs(fract(atan(dq.x, -dq.y) * 3.0 + gT * 0.5) - 0.5); v += (1.0 - smoothstep(0.02, 0.1, fan)) * (0.5 + 0.5 * gKick) * smoothstep(-0.2, 0.8, q.y); float sil = 1e2; for (int i = 0; i < 8; i++) { float fi = float(i); float x = ((fi + 0.5) / 8.0 + (h11(fi + sd * 13.0) - 0.5) * 0.08) * asp; float jump = abs(sin(gBeat * PI + fi * 1.3)) * 0.06; float y = 0.3 + h11(fi * 3.1 + sd) * 0.12 + jump; float r = 0.06 + 0.025 * h11(fi * 7.7 + sd); sil = min(sil, length((q - vec2(x, y)) * vec2(1.0, 0.85)) - r); sil = min(sil, sdRBox(q - vec2(x, y - r - 0.25), vec2(r * 1.7, 0.25), r)); if (h11(fi * 5.3 + sd) > 0.45) { vec2 hand = vec2(x + 0.1 * sin(gT * 2.5 + fi), y + 0.28); sil = min(sil, sdSeg(q, vec2(x + r * 0.8, y - r), hand) - 0.02); } } return mix(v, 0.03, clamp(0.5 - sil / px, 0.0, 1.0)); } // zine layout photo panels: top-left (top = true) or bottom-left, as (x0, y0, x1, y1) vec4 photoRect(bool top) { float x0 = 0.052, iw = gW - 2.0 * x0; return top ? vec4(x0, 0.6, x0 + iw * 0.45, 1.0 - x0) : vec4(x0, x0, x0 + iw * 0.55, 0.318); } void photoPanel(inout vec3 col, vec2 P, vec4 rc, float sd) { vec2 a = rc.xy, b = rc.zw; float bd = sdBox(P - (a + b) * 0.5, (b - a) * 0.5); if (bd < 0.006) { float ph = b.y - a.y; float v = gPhoto >= 0.0 ? gPhoto : crowd((P - a) / ph, (b.x - a.x) / ph, sd, ph); paint(col, cI, halftone(P, v, 0.0085) * fillD(bd)); paint(col, cI, strokeD(bd, 0.0016)); } } // ==================================================================== // SCENE GENERATION // ==================================================================== Scene makeScene(float id) { Scene s; s.sd = mod(id * 7.31, 97.0) + h11(id) * 13.0; s.lay = gLay >= 0 ? gLay : pickI(6, h21(vec2(id, 1.1))); s.pal = pickI(12, h21(vec2(id, 2.2))); s.sty = pickI(5, h21(vec2(id, 3.3))); s.hero = pickI(7, h21(vec2(id, 4.4))); s.bg = sel(pickI(6, h21(vec2(id, 5.5))), 0, 1, 2, 3, 4, 6, 6); s.head = G_HEAD + pickI(N_HEAD, h21(vec2(id, 6.6))); s.head2 = G_HEAD2 + pickI(N_HEAD2, h21(vec2(id, 7.7))); s.tag = G_TAG + pickI(N_TAG, h21(vec2(id, 8.8))); int i0 = pickI(N_INFO, h21(vec2(id, 9.9))); s.i0 = G_INFO + i0; s.i1 = G_INFO + imod(i0 + 1 + pickI(N_INFO - 1, h21(vec2(id, 10.1))), N_INFO); s.dj = pickI(N_DJ, h21(vec2(id, 11.1))); s.quad = pickI(N_QUAD, h21(vec2(id, 12.1))); s.date = G_DATE + pickI(N_DATE, h21(vec2(id, 13.1))); s.place = G_PLACE + pickI(N_PLACE, h21(vec2(id, 14.1))); s.hour = G_HOUR + pickI(N_HOUR, h21(vec2(id, 15.1))); s.yr = G_YEAR + pickI(N_YEAR, h21(vec2(id, 16.1))); s.marq = G_MARQ + pickI(N_MARQ, h21(vec2(id, 17.1))); s.echo = h21(vec2(id, 18.1)) < 0.5; s.inv = h21(vec2(id, 19.1)) < 0.2; float hb = h21(vec2(id, 20.1)), hc = h21(vec2(id, 21.1)), hd = h21(vec2(id, 22.1)); if (s.lay == 1) { s.bg = sel(pickI(4, hb), 5, 3, 2, 6, 0, 0, 0); s.hero = sel(pickI(5, hc), 3, 2, 0, 6, 3, 0, 0); s.pal = sel(pickI(7, hd), 3, 2, 0, 4, 6, 9, 11); s.echo = true; s.inv = false; } if (s.lay == 2) { s.bg = 1; s.pal = sel(pickI(5, hd), 5, 11, 7, 10, 2, 0, 0); s.inv = false; } if (s.lay == 3) { s.bg = 5; s.pal = sel(pickI(6, hd), 8, 1, 10, 5, 7, 4, 0); s.inv = false; } if (s.lay == 4) { s.bg = sel(pickI(4, hb), 2, 2, 6, 0, 0, 0, 0); s.hero = sel(pickI(5, hc), 1, 4, 3, 0, 1, 0, 0); s.pal = sel(pickI(6, hd), 7, 10, 5, 1, 8, 11, 0); s.inv = false; } if (s.lay == 5) s.pal = sel(pickI(7, hd), 1, 0, 2, 3, 4, 8, 9); return s; } // ==================================================================== // LAYOUTS = a shapes pass + a list of text items // ==================================================================== // ---- 0: header slab, hero over pattern, info footer, sticker badge ---- void shapesHeader(inout vec3 col, vec2 P, Scene s) { float W = gW, cx = W * 0.5, m = 0.035, sc = min(W / 0.8, 1.0); float slab = sdRBox(P - vec2(cx, 0.875), vec2(cx - m, 0.085), 0.015); paint(col, cP, fillD(slab - 0.007)); paint(col, cI, fillD(slab)); paint(col, cP, fillD(P.y - 0.205)); paint(col, cI, strokeD(P.y - 0.205, 0.0025)); vec2 bc = P - vec2(W - m - 0.075 * sc, 0.29); float bd = sdStar(rot(gT * 0.5) * bc, 0.07 * sc * (1.0 + 0.06 * gKick), 14.0, 5.0); paint(col, cA, fillD(bd)); paint(col, cI, strokeD(bd, 0.0015)); } // ---- 1: flat stock, hero with echo contours, two-line headline, date pill ---- void shapesWicked(inout vec3 col, vec2 P, Scene s) { float W = gW, cx = W * 0.5, m = 0.04; float dw = min(W * 0.5, (10.0 - 1.0 / 6.0) * 0.022 / 1.3) * 0.5 + 0.02; // dates are 10 chars vec2 dp = P - vec2(cx, 0.105); paint(col, cI, strokeD(sdRBox(dp, vec2(dw, 0.02), 0.02), 0.0025)); paint(col, cI, fillD(max(abs(dp.y) - 0.0012, max(dw + 0.015 - abs(dp.x), abs(dp.x) - (cx - m))))); paint(col, cI, strokeD(length(vec2(abs(dp.x) - (cx - m), dp.y)) - 0.004, 0.0012)); } // ---- 2: acid - box tunnel, coin smileys, waving word stack, info box ---- void shapesAcid(inout vec3 col, vec2 P, Scene s) { float W = gW, m = 0.035, sc = min(W / 0.8, 1.0); vec2 cq = P - vec2(m, 0.36); // fading checker strip if (cq.x > 0.0 && cq.x < W * 0.44 && cq.y > 0.0 && cq.y < 0.1) { vec2 g = cq / 0.025 + vec2(gT * 1.5, 0.0); float fw = PI / 0.025 * gPX; float v = clamp(sin(g.x * PI) / fw, -1.0, 1.0) * clamp(sin(g.y * PI) / fw, -1.0, 1.0); paint(col, accOn(), (0.5 + 0.5 * v) * (1.0 - smoothstep(0.0, W * 0.44, cq.x))); } for (int i = 0; i < 2; i++) { // tumbling coin smileys float fi = float(i); vec2 c = vec2(W * (0.22 + 0.1 * fi), 0.64 - 0.17 * fi) + vec2(sin(gT * 0.9 + fi * 2.0), cos(gT * 0.7 + fi)) * 0.03; float R = (i == 0 ? 0.13 : 0.095) * sc * (1.0 + 0.06 * gKick); float tilt = sin(gT * 1.2 + fi * 1.7) * 0.9; vec2 p = rot(0.4 * sin(gT * 0.8 + fi)) * (P - c); p.x /= max(cos(tilt), 0.25); paint(col, cA, fillD(smileyShape(p + vec2(sin(tilt) * 0.16, -0.1) * R, R, true).y)); vec3 sm = smileyShape(p, R, true); paint(col, cI, fillD(sm.y)); paint(col, cP, fillD(max(sm.z, sm.y))); } float tbd = sdRBox(P - vec2(W * 0.5, 0.93), vec2(W * 0.5 - m, 0.026), 0.008); // window bar paint(col, cP, fillD(tbd)); paint(col, cI, strokeD(tbd, 0.002)); vec2 xp = P - vec2(W - m - 0.022, 0.93); paint(col, cI, fillD(min(sdSeg(xp, vec2(-0.008), vec2(0.008)), sdSeg(xp, vec2(-0.008, 0.008), vec2(0.008, -0.008))) - 0.0018)); vec2 b0 = vec2(m, 0.05), b1 = vec2(W * 0.46, 0.33); // info box float bd = sdRBox(P - (b0 + b1) * 0.5, (b1 - b0) * 0.5, 0.012); paint(col, cP, fillD(bd)); paint(col, cI, strokeD(bd, 0.0022)); for (int i = 0; i < 3; i++) { // sparkles float fi = float(i); float r = 0.022 * (0.7 + 0.5 * abs(sin(gT * 2.0 + fi * 2.0))); paint(col, accOn(), fillD(sdStar(P - vec2(W * (0.52 + 0.17 * fi), 0.86 - 0.05 * fi), r, 4.0, 2.3))); } } // ---- 3: the lineup IS the smiley ---- // ---- 4: contour field, side spine with vertical title ---- void shapesVertical(inout vec3 col, vec2 P, Scene s) { float W = gW, m = 0.03, sx0 = W * 0.76, sw = W - m - sx0; paint(col, cP, fillD(sdBox(P - vec2(sx0 + sw * 0.5, 0.5), vec2(sw * 0.5, 0.5 - m)))); vec2 bc = vec2(m + 0.075, m + 0.05); float bd = sdBox(P - bc, vec2(0.075, 0.05)); paint(col, cP, fillD(bd)); paint(col, accOn(), strokeD(bd, 0.002)); paint(col, cP, fillD(sdBox(P - vec2(sx0 * 0.5, 0.95), vec2(sx0 * 0.5 - m, 0.018)))); } // ---- 5: zine grid - marquee border, halftone photos, outline type, barcodes ---- void gridRowB(vec2 P, Scene s, float x0, float iw, float yb0, float yb1, out int w, out vec2 org, out vec2 cs, out int i) { int qi = imod(s.quad + 1 + pickI(N_QUAD - 1, h11(s.sd)), N_QUAD); float lh = (yb1 - yb0) / 4.0; cs = vec2(min(iw * 0.74 / (quadMax(qi) - 1.0 / 6.0), lh * 0.86), lh * 0.86); i = int(clamp(floor((yb1 - P.y) / lh), 0.0, 3.0)); w = G_QUAD + qi * 4 + i; org = vec2(x0, yb1 - lh * float(i + 1) + lh * 0.07); } void shapesGrid(inout vec3 col, vec2 P, Scene s) { float W = gW, m0 = 0.012, bw = 0.028; vec2 cp = vec2(min(P.x, W - P.x), min(P.y, 1.0 - P.y)) - vec2(m0 + bw * 0.5); paint(col, cI, fillD(sdStar(rot(gT) * cp, bw * 0.45, 4.0, 2.3))); float x0 = m0 + bw + 0.012, x1 = W - x0, y0 = x0, y1 = 1.0 - x0, iw = x1 - x0, g = 0.012; float ya = 0.6, xa = x0 + iw * 0.45, yb0 = 0.33, yb1 = ya - g, yc1 = yb0 - g, xc = x0 + iw * 0.55; paint(col, cI, strokeD(sdBox(P - vec2(W * 0.5, 0.5), vec2(W * 0.5 - x0 + 0.006, 0.5 - x0 + 0.006)), 0.0015)); bool top = P.y > 0.45; photoPanel(col, P, photoRect(top), s.sd + (top ? 0.0 : 7.0)); vec2 ta = vec2(xa + g, ya + (y1 - ya) * 0.32), tb = vec2(x1, y1); paint(col, cI, fillD(sdRBox(P - (ta + tb) * 0.5, (tb - ta) * 0.5, 0.03))); vec2 ia = vec2(xa + g, ya), ib = vec2(x1, ta.y - g); vec2 ic = (ia + ib) * 0.5, ih = (ib - ia) * 0.5; paint(col, cI, strokeD(sdBox(P - ic, ih), 0.0015)); float isz = ih.y * 0.75; vec2 icc = vec2(ib.x - ih.y, ic.y); paint(col, cI, strokeD(sdBox(P - icc, vec2(isz)), 0.0015)); paint(col, cI, fillD(sdStar(rot(gT * 0.8) * (P - icc), isz * 0.85, 4.0, 2.3))); vec2 na = vec2(xc + g, y0), nb = vec2(x1, yc1); paint(col, cI, strokeD(sdBox(P - (na + nb) * 0.5, (nb - na) * 0.5), 0.0015)); } // Text items are table-style: branches only set the few values that differ, // then one tItem() call (branches that compute whole items each cost the // WebGL compiler ~0.2 s; branches that pick values are nearly free). // Fitted text: sz = (bw, bh / st, bh, st). Fixed cell: (1e3, cell w, cell h, 1e3). void itemHeader(int k, vec2 P, Scene s) { float W = gW, cx = W * 0.5, m = 0.035, sc = min(W / 0.8, 1.0); vec2 p = P, anc = vec2(cx, 0.068), aln = vec2(0.5); float bw = W - 2.0 * m, bh = 0.022, st = 1.3, cxm = -1.0; int w = s.i1, sty = 0; vec3 col = cI; if (k == 0) { anc.y = 0.875; bw = (cx - m) * 1.84; bh = 0.13; w = s.head; sty = s.sty; col = cP; gTWob = 1.0; } else if (k == 1) { anc.y = 0.162; bh = 0.038; w = s.tag; } else if (k == 2) { anc.y = 0.108; bh = 0.026; w = s.i0; } else if (k == 4) { // lineup ticker anc = vec2(m, 0.016); aln = vec2(0.0); bw = 1e3; cxm = 0.0125; bh = 0.016; st = 1e3; w = W_LINEUP; col = accOn(); gTScr = gT * 3.0; gTRep = true; gTA = fillD(abs(P.x - cx) - (cx - m)); } else if (k == 5) { // year on the sticker p = rot(-0.25) * (P - vec2(W - m - 0.075 * sc, 0.29)); anc = vec2(0.0); bw = 0.084 * sc; bh = 0.042 * sc; st = 1.2; w = s.yr; col = inkOn(cA); } tItem(p, anc, aln, w, vec4(bw, cxm < 0.0 ? bh / st : cxm, bh, st), sty, col); } void itemWicked(int k, vec2 P, Scene s) { float W = gW; vec2 anc = vec2(W * 0.5, 0.032); float bw = W - 0.08, bh = 0.016, st = 1.3; int w = s.i0, sty = 0; if (k == 0) { anc.y = 0.958; w = s.i1; } else if (k == 1) { // three DJ columns, picked by x float i = clamp(floor(P.x / W * 3.0), 0.0, 2.0); anc = vec2(W * (0.2 + 0.3 * i), 0.905); bw = W * 0.26; bh = 0.026; w = G_DJ + imod(s.dj + int(i), N_DJ); } else if (k == 2) { anc.y = 0.305; bh = 0.085; st = 1.15; w = s.head; sty = s.sty; gTWob = 1.0; } else if (k == 3) { anc.y = 0.215; bh = 0.085; st = 1.15; w = s.head2; sty = s.sty; gTWob = 1.0; } else if (k == 4) { anc.y = 0.153; bw = W * 0.7; bh = 0.02; w = s.tag; } else if (k == 5) { anc.y = 0.105; bw = W * 0.5; bh = 0.022; w = s.date; } else if (k == 6) { anc.y = 0.058; w = s.place; } tItem(P, anc, vec2(0.5), w, vec4(bw, bh / st, bh, st), sty, cI); } void itemAcid(int k, vec2 P, Scene s) { float W = gW, m = 0.035; vec2 p = P, anc = vec2(W * 0.5 - 0.03, 0.93), aln = vec2(0.5); float bw = W - 2.0 * m - 0.1, bh = 0.02, st = 1.3, cxm = -1.0; int w = s.tag, sty = 0; vec3 col = accOn(); if (k == 0) { // the waving stack: one row per pixel float x0 = W * 0.5, x1 = W - m, rowH = 0.75 / 9.0; float yy = P.y - 0.05 + gT * 0.4 * rowH; float row = floor(yy / rowH); float wv = sin(row * 0.9 - gT * 3.0) * 0.5 + 0.5; // slide left/right p = vec2(P.x, yy - row * rowH + sin(P.x * 30.0 + gT * 4.0 + row) * 0.003); anc = vec2(x0 + (x1 - x0) * wv, rowH * 0.04); aln = vec2(wv, 0.0); bw = x1 - x0; bh = rowH * 0.92; cxm = bh / 0.75; st = 1e3; // full row height, any width w = (P.x < x0 - 0.01 || P.x > x1 + 0.01 || P.y < 0.05 || P.y > 0.8) ? -1 : s.head; sty = mod(row, 3.0) < 1.0 ? 2 : 0; col = mix(cI, accOn(), 0.5 + 0.5 * sin(row * 0.7 - gT * 2.0)); } else if (k == 2) { // info box line, picked by y float lh = 0.0625; float i = clamp(floor((0.315 - P.y) / lh), 0.0, 3.0); int ii = int(i); anc = vec2(m + 0.015, 0.315 - lh * (i + 0.9)); aln = vec2(0.0); bw = W * 0.46 - m - 0.03; bh = lh * (ii == 3 ? 0.85 : 0.6); st = 1.25; w = ii == 0 ? s.date : (ii == 1 ? s.place : (ii == 2 ? s.hour : s.head)); col = mod(i, 2.0) < 0.5 ? cI : accOn(); } tItem(p, anc, aln, w, vec4(bw, cxm < 0.0 ? bh / st : cxm, bh, st), sty, col); } void itemSmiley(int k, vec2 P, Scene s) { float W = gW, cx = W * 0.5, sc = min(W / 0.8, 1.0); vec2 p = P, anc = vec2(cx, 0.972), aln = vec2(0.5); float bw = W * 0.5, bh = 0.022, st = 1.3, cxm = -1.0; int w = s.head, sty = 0; vec3 col = cI; if (k == 0) { // lineup rows clipped to the face float R = min(W * 0.47, 0.44) * (1.0 + 0.03 * gKick); vec2 c = P - vec2(cx, 0.53); vec3 sm = smileyShape(rot(0.08 * sin(gT * 0.7)) * c, R, true); float rowH = 2.0 * R / 26.0; float row = floor((c.y + R) / rowH); float hr = h21(vec2(row, s.sd)); bool big = hr > 0.78; p = c; anc = vec2(-W, -R + row * rowH + rowH * 0.08); aln = vec2(0.0); bw = 1e3; cxm = rowH * ((big ? 1.05 : 0.5) + 0.1 * hr); bh = rowH * 0.84; st = 1e3; w = W_LINEUP; sty = big && s.sty != 2 ? s.sty : 0; col = hr > 0.9 ? accOn() : cI; gTScr = hr * 300.0 + (mod(row, 2.0) < 0.5 ? 1.0 : -1.0) * gT * (1.2 + 2.0 * hr); gTRep = true; gTA = fillD(sm.y) * fillD(-(sm.z - R * 0.05)); } else if (k == 1) { anc = vec2(W - 0.13 * sc, 0.075); bw = 0.2 * sc; bh = 0.09; st = 1.25; w = s.yr; gTWob = 1.0; } else if (k == 3) { anc = vec2(0.03); aln = vec2(0.0); bw = W * 0.45; bh = 0.02; w = s.date; } tItem(p, anc, aln, w, vec4(bw, cxm < 0.0 ? bh / st : cxm, bh, st), sty, col); } void itemVertical(int k, vec2 P, Scene s) { float W = gW, m = 0.03, sx0 = W * 0.76, sw = W - m - sx0; vec2 p = P, anc = vec2(sx0 * 0.5, 0.95), aln = vec2(0.5); float bw = sx0 - 2.0 * m - 0.02, bh = 0.02, st = 1.3, cxm = -1.0; int w = s.tag, sty = 0; vec3 col = accOn(); if (k == 0) { // title reading down the spine p = vec2(1.0 - m - 0.025 - P.y, P.x - sx0 - sw * 0.06); anc = vec2(0.0); aln = vec2(0.0); bw = 1.0 - 2.0 * m - 0.05; bh = sw * 0.6; st = 1.1; w = s.head; sty = s.sty; } else if (k == 1) { // marquee down the spine p = vec2(1.0 - P.y, P.x - sx0 - sw * 0.72); anc = vec2(0.0); aln = vec2(0.0); bw = 1e3; cxm = sw * 0.16; bh = sw * 0.2; st = 1e3; w = s.marq; col = cI; gTScr = gT * 2.0; gTRep = true; gTA = fillD(sdBox(P - vec2(sx0 + sw * 0.5, 0.5), vec2(sw * 0.5, 0.5 - m))); } else if (k == 2) { anc = vec2(m + 0.075, m + 0.05); bw = 0.12; bh = 0.06; st = 1.2; w = s.yr; } tItem(p, anc, aln, w, vec4(bw, cxm < 0.0 ? bh / st : cxm, bh, st), sty, col); } void itemGrid(int k, vec2 P, Scene s) { float W = gW, m0 = 0.012, bw0 = 0.028; float x0 = m0 + bw0 + 0.012, x1 = W - x0, y0 = x0, y1 = 1.0 - x0, iw = x1 - x0, g = 0.012; float ya = 0.6, xa = x0 + iw * 0.45, yb0 = 0.33, yb1 = ya - g, yc1 = yb0 - g, xc = x0 + iw * 0.55; float tay = ya + (y1 - ya) * 0.32; // bottom of the title slab vec2 p = P, anc = vec2(0.0), aln = vec2(0.0); float bw = 1e3, bh = 1.0, st = 1e3, cxm = 1.0; // fixed cells unless set int w = -1, sty = 0; vec3 col = cI; if (k == 0) { // marquee crawling around the border float dl = P.x, dr = W - P.x, db = P.y, dt = 1.0 - P.y; float e = min(min(dl, dr), min(db, dt)); float sa = e == dt ? P.x : (e == dr ? W + 1.0 - P.y : (e == db ? 2.0 * W + 1.0 - P.x : 2.0 * W + 1.0 + P.y)); float ch = bw0 * 0.72; p = vec2(sa, m0 + bw0 - e); anc = vec2(0.0, (bw0 - ch) * 0.5); cxm = ch / 1.25; bh = ch; w = (e < m0 || e > m0 + bw0 || (min(dl, dr) < m0 + bw0 && min(db, dt) < m0 + bw0)) ? -1 : s.marq; gTScr = gT * 2.5; gTRep = true; } else if (k == 1) { // title slab, right aligned float lh = (y1 - tay - 0.02) / 4.0; float i = clamp(floor((y1 - 0.01 - P.y) / lh), 0.0, 3.0); anc = vec2(x1 - 0.015, y1 - 0.01 - lh * (i + 1.0) + lh * 0.06); aln = vec2(1.0, 0.0); cxm = min((x1 - xa - g - 0.03) / (quadMax(s.quad) - 1.0 / 6.0), lh * 0.8); bh = lh * 0.88; w = P.x < xa + g ? -1 : G_QUAD + s.quad * 4 + int(i); col = cP; } else if (k == 2) { // info strip, three small lines float ihy = (tay - g - ya) * 0.5, lx = xa + g + 0.008; float i = clamp(floor((tay - g - ihy * 0.12 - P.y) / (ihy * 0.6)), 0.0, 2.0); int ii = int(i); anc = vec2(lx, tay - g - ihy * 0.12 - ihy * 0.6 * (i + 1.0)); bw = x1 - ihy * 1.75 - 0.01 - lx; bh = ihy * 0.4; st = 1.3; cxm = bh / st; w = (P.x < xa + g || P.y < ya || P.y > tay - g) ? -1 : (ii == 0 ? s.tag : (ii == 1 ? s.i0 : s.hour)); } else if (k == 3) { // outlined lines (+ barcode in the renderer) int ww, i; vec2 org, cs; gridRowB(P, s, x0, iw, yb0, yb1, ww, org, cs, i); anc = org; cxm = cs.x; bh = cs.y; sty = 2; w = (P.y < yb0 || P.y > yb1) ? -1 : ww; } else { // NO SLEEP stack, scrolling vec2 na = vec2(xc + g, y0), nb = vec2(x1, yc1); float lh = (nb.y - na.y) / 6.0; float yy = P.y - na.y + gT * 0.5 * lh; p = vec2(P.x, yy - floor(yy / lh) * lh); anc = vec2(na.x + 0.008, lh * 0.5); aln = vec2(0.0, 0.5); bw = nb.x - na.x - 0.016; cxm = 1e3; bh = lh * 0.84; st = 1.8; w = W_NOSLEEP; gTA = fillD(sdBox(P - (na + nb) * 0.5, (nb - na) * 0.5) + 0.003); } tItem(p, anc, aln, w, vec4(bw, cxm, bh, st), sty, col); } // which text item (if any) can cover this pixel - text lines never overlap int textSlot(vec2 P, Scene s) { float W = gW, sc = min(W / 0.8, 1.0); if (s.lay == 0) { if (P.y > 0.6) return 0; if (length(P - vec2(W - 0.035 - 0.075 * sc, 0.29)) < 0.09 * sc) return 5; if (P.y > 0.135) return 1; if (P.y > 0.088) return 2; if (P.y > 0.045) return 3; return 4; } if (s.lay == 1) { if (P.y > 0.935) return 0; if (P.y > 0.8) return 1; if (P.y > 0.26) return 2; if (P.y > 0.18) return 3; if (P.y > 0.128) return 4; if (P.y > 0.08) return 5; if (P.y > 0.045) return 6; return 7; } if (s.lay == 2) return P.y > 0.86 ? 1 : (P.x > W * 0.48 ? 0 : 2); if (s.lay == 3) { if (length(P - vec2(W * 0.5, 0.53)) < min(W * 0.47, 0.44) * 1.05) return 0; if (P.y > 0.9) return 2; return P.x > W * 0.5 ? 1 : 3; } if (s.lay == 4) { float sx0 = W * 0.76, sw = W - 0.03 - sx0; if (P.x > sx0) return P.x < sx0 + sw * 0.69 ? 0 : 1; return P.y > 0.85 ? 3 : 2; } float m0 = 0.012, bw = 0.028, x0 = m0 + bw + 0.012; // 5: zine grid if (min(min(P.x, W - P.x), min(P.y, 1.0 - P.y)) < m0 + bw + 0.004) return 0; if (P.y > 0.594) return P.y > 0.6 + (0.4 - x0) * 0.32 ? 1 : 2; return P.y > 0.33 ? 3 : 4; } void textItem(int k, vec2 P, Scene s) { if (s.lay == 0) itemHeader(k, P, s); else if (s.lay == 1) itemWicked(k, P, s); else if (s.lay == 2) itemAcid(k, P, s); else if (s.lay == 3) itemSmiley(k, P, s); else if (s.lay == 4) itemVertical(k, P, s); else itemGrid(k, P, s); } vec3 renderScene(vec2 P, float id) { Scene s = makeScene(id); // chaos: re-roll pieces of the poster on the beat float bt = floor(gBeat), b2 = floor(gBeat * 0.5); if (h21(vec2(bt, id + 0.5)) < gChaos * 0.4) s.head = G_HEAD + pickI(N_HEAD, h21(vec2(bt, id + 1.5))); if (h21(vec2(bt, id + 2.5)) < gChaos * 0.3) s.sty = pickI(5, h21(vec2(bt, id + 3.5))); if (h21(vec2(b2, id + 4.5)) < gChaos * 0.3) s.pal = pickI(12, h21(vec2(b2, id + 5.5))); if (h21(vec2(floor(gBeat * 2.0), id + 6.5)) < gChaos * 0.12) s.inv = !s.inv; if (s.lay == 0 && h21(vec2(b2, id + 7.5)) < gChaos * 0.35) s.hero = pickI(7, h21(vec2(b2, id + 8.5))); if (s.lay == 0 && h21(vec2(b2, id + 9.5)) < gChaos * 0.3) s.bg = sel(pickI(6, h21(vec2(b2, id + 10.5))), 0, 1, 2, 3, 4, 6, 6); setPal(s.pal, s.inv); float W = gW, cx = W * 0.5, sc = min(W / 0.8, 1.0), sx0 = W * 0.76; vec3 col = cP; if (s.lay != 5) { // shared background vec2 bc = s.lay == 1 ? vec2(cx, 0.6) : (s.lay == 2 ? vec2(cx, 0.56) : (s.lay == 4 ? vec2(W * 0.4, 0.55) : vec2(cx, 0.49))); vec2 bg = background(P - bc, s.bg, s.sd); vec3 bcol = s.lay == 1 ? mix(cP, cI, 0.16) : (s.lay == 3 ? cA : mix(cI, cA, bg.y)); paint(col, bcol, bg.x * (s.lay == 3 ? 0.7 : 1.0)); } if (s.lay == 0 || s.lay == 1 || s.lay == 4) { // shared hero vec2 hc = s.lay == 0 ? vec2(cx, 0.49) : (s.lay == 1 ? vec2(cx, 0.6) : vec2(sx0 * 0.5, 0.56)); float R = s.lay == 0 ? 0.23 * sc : (s.lay == 1 ? 0.19 * sc : min(sx0 * 0.42, 0.3)); vec3 ink = s.lay == 4 ? accOn() : cI; drawHero(col, P - hc, R, s, cP, ink, ink, s.echo); } if (s.lay == 0) shapesHeader(col, P, s); else if (s.lay == 1) shapesWicked(col, P, s); else if (s.lay == 2) shapesAcid(col, P, s); else if (s.lay == 4) shapesVertical(col, P, s); else if (s.lay == 5) shapesGrid(col, P, s); gTScr = 0.0; gTWob = 0.0; gTA = 1.0; gTRep = false; tW = -1; int slot = textSlot(P, s); textItem(slot, P, s); // the one text line here if (tW >= 0 && gTA > 0.0) { vec2 wi = wordInfo(float(tW)); float L1 = wi.y - 1.0 / 6.0; float cxs = min(tSz.x / L1, tSz.y); vec2 cs = vec2(cxs, min(tSz.z, cxs * tSz.w)); vec2 org = tAnc - vec2(L1 * cs.x, cs.y) * tAln; vec2 p = tP; p.y += sin(p.x * 18.0 + gT * 5.0) * cs.y * 0.05 * gChaos * gTWob; vec3 sh = styShape(tSty); vec2 off = vec2(0.9, -0.7) * (1.0 + 1.5 * gKick) * cs / vec2(6.0, 5.0); for (int k = 0; k < 2; k++) { // 0: style-4 drop shadow, 1: ink if (k == 0 && tSty != 4) continue; float d = sdText(k == 0 ? p - off : p, org, cs, wi.x, wi.y, gTScr, gTRep, sh); paint(col, k == 0 ? cA : tCol, (k == 0 ? fillD(d) : textMask(d, tSty, cs)) * gTA); } if (s.lay == 5 && slot == 3) { // zine: barcode trailing the outline type float u = 0.0035, bx0 = org.x + L1 * cs.x + 0.014; if (P.x > bx0 && P.x < gW - 0.052 && P.y > org.y && P.y < org.y + cs.y) { float bxx = (P.x - bx0) / u + floor(gT * 6.0) * 3.0 * gChaos; float hb = h21(vec2(floor(bxx), org.y * 97.0 + s.sd)); float wf = hb > 0.45 ? 0.3 + 0.6 * h11(hb * 91.0) : 0.0; paint(col, cI, wf > 0.0 ? fillD((abs(fract(bxx) - 0.5) - 0.5 * wf) * u) : 0.0); } } } return col; } // ==================================================================== // ENTRY: fragCoord / res in pixels, tm in seconds. // firstIn = poster shown at tm = 0, holdIn = stay on that poster, // layIn = force a layout 0..5 (< 0 = generator picks). // ==================================================================== vec3 rave(vec2 fragCoord, vec2 res, float tm, float bpmIn, float chaosIn, float seedIn, float kickIn, float firstIn, bool holdIn, int layIn) { gT = tm; gBeat = tm * bpmIn / 60.0; gChaos = clamp(chaosIn, 0.0, 1.0) * smoothstep(0.0, 2.0, gBeat); // calm first frame (poster grabs) gLay = layIn; // portrait / square canvases are the poster; wider ones hang a 4:5 poster on a wall float asp = res.x / res.y; bool wall = asp > 1.05; float ps = wall ? 0.92 : 1.0; gW = wall ? 0.8 : asp; gPX = 1.0 / (res.y * ps); vec2 Q = vec2((fragCoord.x / res.x - 0.5) * asp, fragCoord.y / res.y - 0.5); vec2 P = Q / ps + vec2(gW * 0.5, 0.5); vec2 uv = P / vec2(gW, 1.0); // poster-relative 0..1 gPhoto = -1.0; // sample the photo input up front, #ifdef RAVE_INPUT // outside any branch or loop vec4 pr = photoRect(P.y > 0.45); gPhoto = RAVE_INPUT(clamp((P - pr.xy) / (pr.zw - pr.xy), 0.0, 1.0)); #endif float s16 = floor(gBeat * 4.0); if (h11(s16 * 2.71 + 0.3) < gChaos * 0.12) { // stutter: freeze on a 16th gBeat = s16 * 0.25; gT = gBeat * 60.0 / bpmIn; } gKick = max(exp(-fract(gBeat) * 6.0), clamp(kickIn, 0.0, 1.0)); vec2 ctr = vec2(gW * 0.5, 0.5); // kick punch + shake P = ctr + (P - ctr) / (1.0 + 0.035 * gKick * gChaos); P += (h22(vec2(mod(floor(gT * 24.0), 997.0), 1.0)) - 0.5) * 0.006 * gChaos * gKick; gRough = (vnoise(P * 520.0 + mod(floor(gT * 12.0), 500.0) * 7.13) - 0.5) * 2.2 * gPX * (0.5 + gChaos); // new poster every 2 bars; the last beat flickers with the next one float sid = floor(firstIn) + floor(seedIn) * 101.0; if (!holdIn) { sid += floor(gBeat / 8.0); if (mod(gBeat, 8.0) > 7.0 && h11(s16 * 1.31) < 0.3 + 0.6 * gChaos) sid += 1.0; } bool split = false; // horizontal tear bands if (h11(s16 * 0.731 + 3.7) < gChaos * 0.5) { float nb = floor(mix(5.0, 28.0, h11(s16 + 9.1))); float band = floor(uv.y * nb); float hb = h21(vec2(band, s16)); if (hb < 0.15 + 0.3 * gChaos) { P.x += (h21(vec2(band, s16 + 1.0)) - 0.5) * 0.3 * gChaos; if (hb < 0.1 * gChaos + 0.03) sid += floor(1.0 + h21(vec2(band, s16 + 2.0)) * 5.0); split = hb > 0.12; } } vec3 col = renderScene(P, sid); if (split) col = mix(col, col.gbr, 0.7); // misprinted ink in the tears float s8 = floor(gBeat * 2.0); // block inversions for (int i = 0; i < 3; i++) { float fi = float(i); vec4 hb = vec4(h21(vec2(s8, fi)), h21(vec2(s8, fi + 0.5)), h21(vec2(s8, fi + 0.7)), h21(vec2(s8, fi + 0.9))); if (hb.x < gChaos * 0.3) { vec2 a = hb.yz * vec2(gW, 1.0) - 0.1; vec2 sz = vec2(0.1 + 0.4 * hb.w, 0.015 + 0.09 * hb.y); if (all(greaterThan(P, a)) && all(lessThan(P, a + sz))) col = 1.0 - col; } } if (fract(gBeat / 4.0) < 0.035 && h11(floor(gBeat / 4.0) + 0.3) < gChaos * 0.5) col = 1.0 - col; // downbeat strobe // print finish: grain, paper mottle, fold creases, vignette col += (h21(fragCoord + fract(gT * 13.7) * vec2(97.0, 53.0)) - 0.5) * 0.05; col *= 0.93 + 0.07 * fbm(uv * vec2(gW, 1.0) * 5.0 + seedIn); float cr = exp(-abs(uv.x - 0.5) * 500.0) + 0.7 * (exp(-abs(uv.y - 0.333) * 500.0) + exp(-abs(uv.y - 0.666) * 500.0)); col *= (1.0 - 0.07 * cr) * (1.0 + 0.015 * sign(uv.x - 0.5)); col *= 1.0 - 0.2 * pow(length(uv - 0.5) * 1.25, 2.5); if (wall) { // dark wall + drop shadow vec2 hw = vec2(gW * 0.5, 0.5); vec3 wc = vec3(0.075, 0.07, 0.068) * (0.75 + 0.5 * vnoise(Q * 40.0)) * (1.0 - 0.5 * length(Q)); wc *= 1.0 - 0.55 * exp(-max(sdBox(P - hw - vec2(0.012, -0.018), hw), 0.0) * 40.0); col = mix(wc, col, clamp(0.5 - sdBox(P - hw, hw) / gPX, 0.0, 1.0)); } return clamp(col, 0.0, 1.0); } void main() { vec3 c = rave(isf_FragNormCoord.xy * RENDERSIZE, RENDERSIZE, TIME, bpm, chaos, seed, kick, firstPoster, holdPoster, layoutLock); gl_FragColor = vec4(c, 1.0); }
procedural, beat-synced 90s rave poster generator. A new flyer every 8 beats: bitmap type, smileys, checker tunnels, contour echoes, halftone crowds, glitch cuts. Pure math, no textures.
by ksinwitnessed_generationmade with ClaudeCC0-1.0credit: CC0active·created 2026-10-04 22:48Z168 views0 forks7 paramsClaude-Opus-5.5
export clip · render a video in your browser
Renders to video in your browser (no upload), stepping the real renderer frame by frame so multipass + feedback come out right. motion auto-animates the shader's own knobs — each export rolls a fresh take (🎲 re-roll, 🔒 to pin one you like). GIF is slower with a tighter length cap; MP4/WebM are faster. Some devices record in real time (noted below if so) — keep the tab visible.
caps: ≤1920 per side, ≤60fps, ≤18000 frames (GIF ≤300)
embed · drop this shader into any page
Renders client-side in the reader's browser (CC0 — no attribution required, but the backlink is appreciated).