open .fs {
"DESCRIPTION" : "Wagara Kamon - a Japanese textile-pattern generator built for VJing. One 'morph' knob walks four traditional wagara: seigaiha (blue ocean waves) -> asanoha (hemp leaf) -> shippou (seven treasures) -> yagasuri (arrow fletching), all drawn as their real construction rather than faked with noise: seigaiha uses the unit-circle lattice where neighbours cut every fan into an exact 120-degree scallop, and asanoha is the triangular lattice with a Y from every triangle's centroid, which resolves to twelve radial spokes per hexagonal cell. 'crest' stamps a kamon over the field: a spinning 16-petal kikumon whose disc inverts the pattern's ink/paper polarity like a stencilled family emblem. 'fill' travels from thin line-art to solid woodblock bands; 'weight' is resolution-aware so lines never alias out at high density. Single pass, no feedback buffer, no internal state: every parameter is read straight, so a host that automates natively owns all the motion. 'scroll' and 'twist' are phase positions that wrap at 0/1 onto an exact lattice period, so any ramp or LFO driving them runs forever without a seam; 'flow' and 'spin' are free-run rates for when you would rather not automate at all. 'hit' takes a beat envelope directly: it kicks the zoom, swells the crest, and throws an accent shockwave that expands as the envelope decays. 'energy' maps straight to audio RMS. Four traditional palettes (indigo/vermilion/sumi/gold) blend to a hue-driven neon via 'neon', and 'inkOnly' drops the paper for black-ground additive layering." ,
"CREDIT" : "CC0" ,
"CATEGORIES" : [ "generator" , "vj" , "pattern" , "geometry" ] ,
"INPUTS" : [
{ "NAME" : "morph" , "TYPE" : "float" , "DEFAULT" : 0.0 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "density" , "TYPE" : "float" , "DEFAULT" : 0.45 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "weight" , "TYPE" : "float" , "DEFAULT" : 0.45 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "fill" , "TYPE" : "float" , "DEFAULT" : 0.35 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "scroll" , "TYPE" : "float" , "DEFAULT" : 0.0 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "flow" , "TYPE" : "float" , "DEFAULT" : 0.30 , "MIN" : -1.0 , "MAX" : 1.0 } ,
{ "NAME" : "twist" , "TYPE" : "float" , "DEFAULT" : 0.0 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "spin" , "TYPE" : "float" , "DEFAULT" : 0.06 , "MIN" : -1.0 , "MAX" : 1.0 } ,
{ "NAME" : "crest" , "TYPE" : "float" , "DEFAULT" : 0.85 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "crestSize" , "TYPE" : "float" , "DEFAULT" : 0.42 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "palette" , "TYPE" : "long" , "DEFAULT" : 0 ,
"VALUES" : [ 0 , 1 , 2 , 3 ] ,
"LABELS" : [ "Ai (indigo)" , "Shu (vermilion)" , "Sumi (ink)" , "Kin (gold)" ] } ,
{ "NAME" : "hue" , "TYPE" : "float" , "DEFAULT" : 0.33 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "neon" , "TYPE" : "float" , "DEFAULT" : 0.0 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "energy" , "TYPE" : "float" , "DEFAULT" : 0.25 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "hit" , "TYPE" : "float" , "DEFAULT" : 0.0 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "glow" , "TYPE" : "float" , "DEFAULT" : 0.3 , "MIN" : 0.0 , "MAX" : 1.0 } ,
{ "NAME" : "inkOnly" , "TYPE" : "bool" , "DEFAULT" : false }
]
}
#define TAU 6.28318530718
#define PI 3.14159265359
#define SQ3 1.73205080757
vec3 hueRGB (float h) {
return 0.5 + 0.5 * cos (TAU * (h + vec3 (0.0 , 0.333333 , 0.666667 )));
}
mat2 rot2 (float a) {
float c = cos (a), s = sin (a);
return mat2 (c, -s, s, c);
}
float stroke (float d, float w, float px) {
return smoothstep (w + px, w - px, abs (d));
}
float bands (float x, float e) {
return smoothstep (-e, e, -sin (PI * x));
}
vec3 seigaiha (vec2 p, float px, float w) {
vec2 q = p * SQ3;
float pq = px * SQ3;
float rings = 4.0 ;
float j0 = floor (q.y * 2.0 + 0.5 );
float bestY = 1000.0 ;
vec2 bestC = vec2 (0.0 );
for (int jj = 0 ; jj < 5 ; jj++) {
float j = j0 + float (jj) - 2.0 ;
float cy = j * 0.5 ;
float ox = mod (j, 2.0 ) * (SQ3 * 0.5 );
float i0 = floor ((q.x - ox) / SQ3 + 0.5 );
for (int ii = 0 ; ii < 3 ; ii++) {
vec2 c = vec2 ((i0 + float (ii) - 1.0 ) * SQ3 + ox, cy);
if (length (q - c) < 1.0 && cy < bestY) { bestY = cy; bestC = c; }
}
}
float d = length (q - bestC);
float bd = 1.0 - d;
for (int jj = 0 ; jj < 5 ; jj++) {
float j = j0 + float (jj) - 2.0 ;
float cy = j * 0.5 ;
if (cy < bestY - 0.01 ) {
float ox = mod (j, 2.0 ) * (SQ3 * 0.5 );
float i0 = floor ((q.x - ox) / SQ3 + 0.5 );
for (int ii = 0 ; ii < 3 ; ii++) {
vec2 c = vec2 ((i0 + float (ii) - 1.0 ) * SQ3 + ox, cy);
bd = min (bd, length (q - c) - 1.0 );
}
}
}
float rd = abs (fract (d * rings + 0.5 ) - 0.5 ) / rings;
float ld = min (rd, bd);
float e = min (PI * rings * pq * 1.5 , 1.0 );
return vec3 (stroke (ld, w * SQ3, pq), stroke (ld, w * SQ3 * 3.0 , pq * 2.5 ),
bands (d * rings, e));
}
vec3 asanoha (vec2 p, float px, float w) {
vec2 s = vec2 (1.0 , SQ3);
vec2 a = mod (p, s) - s * 0.5 ;
vec2 b = mod (p - s * 0.5 , s) - s * 0.5 ;
vec2 g = (dot (a, a) < dot (b, b)) ? a : b;
float th = atan (g.y, g.x);
float f = mod (th + PI / 12.0 , PI / 6.0 ) - PI / 12.0 ;
float sd = length (g) * abs (sin (f));
vec2 n2 = vec2 ( 0.5 , 0.8660254 );
vec2 n3 = vec2 (-0.5 , 0.8660254 );
float hx = max (abs (g.x), max (abs (dot (g, n2)), abs (dot (g, n3))));
float wall = abs (0.5 - hx) + (1.0 - clamp (fill * 3.0 , 0.0 , 1.0 )) * 9.0 ;
float ld = min (sd, wall);
float sect = floor (mod (th + PI / 12.0 + TAU, TAU) / (PI / 6.0 ));
return vec3 (stroke (ld, w, px), stroke (ld, w * 3.0 , px * 2.5 ), mod (sect, 2.0 ));
}
vec3 shippou (vec2 p, float px, float w) {
float R = 0.70710678 ;
vec2 id = floor (p + 0.5 );
float dmin = 1000.0 ;
float cnt = 0.0 ;
for (int j = 0 ; j < 3 ; j++) {
for (int i = 0 ; i < 3 ; i++) {
vec2 c = id + vec2 (float (i) - 1.0 , float (j) - 1.0 );
float dd = length (p - c);
dmin = min (dmin, abs (dd - R));
cnt += (dd < R) ? 1.0 : 0.0 ;
}
}
return vec3 (stroke (dmin, w, px), stroke (dmin, w * 3.0 , px * 2.5 ), mod (cnt, 2.0 ));
}
vec3 yagasuri (vec2 p, float px, float w) {
float n = 2.0 ;
float k = 1.2 ;
float id = floor (p.x + 0.5 );
float lx = p.x - id;
float dir = mod (id, 2.0 ) * 2.0 - 1.0 ;
float x = (p.y * dir + abs (lx) * k) * n;
float gm = n * sqrt (1.0 + k * k);
float sd = abs (fract (x + 0.5 ) - 0.5 ) / gm;
float cd = abs (abs (lx) - 0.5 );
float ld = min (sd, cd);
float e = min (PI * gm * px * 1.5 , 1.0 );
return vec3 (stroke (ld, w, px), stroke (ld, w * 3.0 , px * 2.5 ), bands (x, e));
}
void main () {
float sc = fract (scroll + TIME * flow * 0.35 );
float sp = fract (twist + TIME * spin * 0.05 );
float kick = clamp (hit, 0.0 , 1.0 );
float m = clamp (morph, 0.0 , 1.0 ) * 3.0 ;
vec2 uv = (gl_FragCoord .xy - 0.5 * RENDERSIZE .xy) / RENDERSIZE .y;
float cells = mix (3.0 , 13.0 , density) * (1.0 - 0.10 * kick);
vec2 p = rot2 (TAU * sp) * uv * cells;
float px = max (cells / RENDERSIZE .y, 0.00001 );
float w = max (mix (0.012 , 0.055 , weight), px * 1.15 );
float w0 = smoothstep (0.0 , 1.0 , clamp ((1.0 - abs (m )) * 2.5 - 0.75 , 0.0 , 1.0 ));
float w1 = smoothstep (0.0 , 1.0 , clamp ((1.0 - abs (m - 1.0 )) * 2.5 - 0.75 , 0.0 , 1.0 ));
float w2 = smoothstep (0.0 , 1.0 , clamp ((1.0 - abs (m - 2.0 )) * 2.5 - 0.75 , 0.0 , 1.0 ));
float w3 = smoothstep (0.0 , 1.0 , clamp ((1.0 - abs (m - 3.0 )) * 2.5 - 0.75 , 0.0 , 1.0 ));
const float KA = 0.60 ;
vec3 fld = vec3 (0.0 );
if (w0 > 0.002 ) fld += w0 * seigaiha (p + vec2 (0.0 , sc * 0.5773503 ), px, w);
if (w1 > 0.002 ) fld += w1 * asanoha (p * KA + vec2 (0.0 , sc * SQ3 ), px * KA, w * KA);
if (w2 > 0.002 ) fld += w2 * shippou (p + vec2 (0.0 , sc ), px, w);
if (w3 > 0.002 ) fld += w3 * yagasuri (p + vec2 (0.0 , sc * 0.5 ), px, w);
float cov = clamp (max (fld.x, fld.z * fill * 0.92 ), 0.0 , 1.0 );
float halo = fld.y;
float r = length (uv);
float th = atan (uv.y, uv.x) - TAU * sp * 2.0 ;
float aa = 1.5 / RENDERSIZE .y;
float rc = mix (0.10 , 0.42 , crestSize) * (1.0 + 0.06 * kick);
float petalR = rc * (1.0 + 0.30 * (0.5 + 0.5 * cos (16.0 * th)));
float ringM = smoothstep (rc * 0.99 + aa, rc * 0.99 - aa, r)
* smoothstep (rc * 0.86 - aa, rc * 0.86 + aa, r);
float petalM = smoothstep (petalR + aa, petalR - aa, r)
* smoothstep (rc * 0.99 - aa, rc * 0.99 + aa, r);
float seedM = smoothstep (rc * 0.14 + aa, rc * 0.14 - aa, r);
float discM = smoothstep (rc * 0.87 + aa, rc * 0.87 - aa, r);
float crestA = smoothstep (0.0 , 0.45 , crest);
cov = mix (cov, 1.0 - cov, discM * crestA);
vec3 inkC, paperC, accC;
if (palette == 0 ) {
inkC = vec3 (0.055 , 0.125 , 0.330 ); paperC = vec3 (0.930 , 0.910 , 0.850 ); accC = vec3 (0.860 , 0.720 , 0.360 );
} else if (palette == 1 ) {
inkC = vec3 (0.780 , 0.150 , 0.090 ); paperC = vec3 (0.960 , 0.930 , 0.860 ); accC = vec3 (0.930 , 0.780 , 0.300 );
} else if (palette == 2 ) {
inkC = vec3 (0.060 , 0.060 , 0.070 ); paperC = vec3 (0.900 , 0.870 , 0.800 ); accC = vec3 (0.650 , 0.160 , 0.120 );
} else {
inkC = vec3 (0.880 , 0.700 , 0.280 ); paperC = vec3 (0.045 , 0.035 , 0.050 ); accC = vec3 (0.960 , 0.900 , 0.720 );
}
vec3 nHue = hueRGB (hue);
inkC = mix (inkC, nHue, neon);
paperC = mix (paperC, nHue * 0.05 , neon);
accC = mix (accC, hueRGB (hue + 0.12 ), neon);
if (inkOnly) {
paperC = vec3 (0.0 );
inkC /= max (max (inkC.r, max (inkC.g, inkC.b)), 0.001 );
}
vec3 col = mix (paperC, inkC, cov);
col = mix (col, inkC, ringM * crestA);
col = mix (col, accC, max (petalM, seedM) * crestA);
float ground = dot (paperC, vec3 (0.299 , 0.587 , 0.114 ));
float dark = smoothstep (0.35 , 0.05 , ground);
col = mix (col, inkC, halo * glow * 0.30 * (1.0 - dark));
col += accC * halo * glow * 0.85 * dark;
float rad = (1.0 - kick) * 1.15 ;
float dsh = (r - rad) * 9.0 ;
float shock = exp (-dsh * dsh) * kick;
col = mix (col, accC, clamp (shock, 0.0 , 1.0 ) * 0.85 );
float punch = clamp (energy + kick, 0.0 , 1.0 );
col = mix (col, clamp ((col - 0.5 ) * (1.0 + 0.65 * punch) + 0.5 , 0.0 , 1.0 ), 0.85 );
col += accC * punch * 0.25 * dark;
col *= 1.0 - 0.28 * dot (uv, uv);
col = col / (1.0 + max (col - 1.0 , 0.0 ));
col = clamp (col, 0.0 , 1.0 );
float alpha = inkOnly ? clamp (max (cov, halo * glow), 0.0 , 1.0 ) : 1.0 ;
gl_FragColor = vec4 (col, alpha);
}