shadertown 0.7.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/registry.js CHANGED
@@ -91,7 +91,7 @@ export const shaderRegistry = {
91
91
  aurora: {
92
92
  name: "Aurora",
93
93
  tagline: "Layered curtains of light over a night sky",
94
- description: "Three domain-warped noise curtains at different depths, drawn over a star field that thins out behind the brightest ribbons. The warp control decides whether it reads as a calm glow or a solar storm.",
94
+ description: "Green and violet curtains of light hang over a dark sky and drift sideways, brightest along their lower edge and fading out before they reach the top of the frame. Stars show through the gaps and thin out behind the strongest ribbons. Low warp reads as a calm glow, high warp as a solar storm.",
95
95
  family: "organic",
96
96
  tags: ["ambient", "hero", "dark"],
97
97
  cost: "medium",
@@ -139,7 +139,7 @@ export const shaderRegistry = {
139
139
  caustics: {
140
140
  name: "Caustics",
141
141
  tagline: "Light focused through a moving water surface",
142
- description: "Three counter-rotating wave fields are stacked and sharpened into the bright web you see on the floor of a pool, with the three colour channels focusing at slightly different depths. Sharpness is the difference between a glow and a caustic.",
142
+ description: "The bright, moving web of light that water throws on the floor of a pool. The lines cross, pull apart and flare where the light focuses, with faint colour fringes along the sharpest ones. Low sharpness is a soft glow; high sharpness is hard caustic line work.",
143
143
  family: "organic",
144
144
  tags: ["water", "light", "pool"],
145
145
  cost: "medium",
@@ -187,8 +187,8 @@ export const shaderRegistry = {
187
187
  },
188
188
  swell: {
189
189
  name: "Swell",
190
- tagline: "Open ocean to the horizon, no marching at all",
191
- description: "The surface is an analytic plane; only its normal is waved, from choppy octaves whose crests are sharp and troughs round — the whole difference between water and moire. Fresnel decides how much sky the surface borrows, and the sun's glitter widens with distance until the far path is a single streak.",
190
+ tagline: "Open ocean to a bright, flat horizon",
191
+ description: "Open ocean to a bright horizon, choppy near the camera and flat glare far away. The crests are sharp and the troughs round, which is the whole difference between water and moire, and the water pales toward the horizon where it borrows the sky. The sun's glitter widens with distance until the far path is one streak.",
192
192
  family: "scene",
193
193
  tags: ["hero", "water", "3d", "pointer"],
194
194
  cost: "medium",
@@ -250,8 +250,8 @@ export const shaderRegistry = {
250
250
  },
251
251
  cumulus: {
252
252
  name: "Cumulus",
253
- tagline: "Fair-weather cloud, shaded by one cheat",
254
- description: "The clouds are warped fbm on a plane overhead; their lighting is a single extra sample toward the sun — density falling that way means a lit face, rising means its own shadow. God rays are the same field re-read a few times along the screen-space line to the sun. Nothing here is a volume, and it reads like one.",
253
+ tagline: "Fair-weather cloud on a summer sky",
254
+ description: "Fair-weather cloud on a blue sky, lit from one side with grey undersides and soft god rays reaching down from the sun. The clouds build and slide past overhead. It reads as a summer afternoon rather than as weather.",
255
255
  family: "scene",
256
256
  tags: ["hero", "sky", "soft", "pointer"],
257
257
  cost: "medium",
@@ -311,66 +311,81 @@ export const shaderRegistry = {
311
311
  { name: "Dusk", colorA: "#28306e", colorB: "#5a6494", colorC: "#ff9e6b" },
312
312
  ],
313
313
  },
314
- plasma: {
315
- name: "Plasma",
316
- tagline: "Stacked sine fields, the oldest trick in the demoscene",
317
- description: "Four interfering sine fields plus a rotating fifth, coloured through a cycling ramp and cut by iso-contours. Loud on purpose — it is the counterweight to the quiet gradients in this catalogue.",
318
- family: "geometric",
319
- tags: ["retro", "loud", "cycling"],
320
- cost: "light",
314
+ ferro: {
315
+ name: "Ferro",
316
+ tagline: "A pool of ferrofluid, and the pointer is the magnet",
317
+ description: "A dark pool of bright points at rest in a slow swell. Under the pointer a crown of spikes rises, the stiff hedgehog that real ferrofluid grows over a magnet, and rings ripple out from the same place. Move the pointer and the crown hands itself from spike to spike instead of sliding along as one shape.",
318
+ family: "particles",
319
+ tags: ["particles", "3d", "interactive", "pointer", "dark"],
320
+ cost: "heavy",
321
321
  controls: {
322
322
  ...base,
323
- speed: { ...base.speed, default: 0.7 },
324
- scale: { ...base.scale, default: 0.55, min: 0.1, max: 2 },
325
- vibrancy: { ...base.vibrancy, default: 1.25 },
326
- vignette: { ...base.vignette, default: 0.3 },
327
- radial: {
323
+ speed: { ...base.speed, default: 1, max: 2 },
324
+ scale: { ...base.scale, default: 1, min: 0.4, max: 2.5, hint: "Zoom of the resting swell. The crown keeps its own size." },
325
+ intensity: { ...base.intensity, default: 1 },
326
+ vibrancy: { ...base.vibrancy, default: 1.1 },
327
+ vignette: { ...base.vignette, default: 0.4 },
328
+ warp: {
329
+ ...warp,
330
+ label: "Swell",
331
+ min: 0,
332
+ max: 2,
333
+ default: 0.8,
334
+ hint: "The resting motion of the pool, far from the magnet.",
335
+ },
336
+ field: {
328
337
  slot: "a",
329
- label: "Radial",
338
+ label: "Field",
330
339
  min: 0,
331
- max: 3,
340
+ max: 2,
332
341
  step: 0.01,
333
342
  default: 1,
334
- hint: "Weight of the concentric ring field.",
343
+ hint: "The magnet's reach. Everything the pointer does happens inside it.",
335
344
  },
336
- swirl: {
345
+ spikes: {
337
346
  slot: "b",
338
- label: "Swirl",
347
+ label: "Spikes",
339
348
  min: 0,
340
- max: 3,
349
+ max: 2,
341
350
  step: 0.01,
342
351
  default: 1,
343
- hint: "Rotation rate of the secondary interference field.",
352
+ hint: "Density of the crown. High is needles, low is a few broad cones.",
344
353
  },
345
- interference: {
354
+ ripples: {
346
355
  slot: "c",
347
- label: "Interference",
356
+ label: "Ripples",
348
357
  min: 0,
349
358
  max: 2,
350
359
  step: 0.01,
351
- default: 0.8,
352
- hint: "How strongly the rotating field beats against the rest.",
360
+ default: 0.9,
361
+ hint: "The rings the disturbance sheds.",
353
362
  },
354
- cycles: {
363
+ pull: {
355
364
  slot: "d",
356
- label: "Colour cycles",
357
- min: 0.2,
358
- max: 4,
365
+ label: "Pull",
366
+ min: 0,
367
+ max: 2,
359
368
  step: 0.01,
360
369
  default: 1,
361
- hint: "Number of times the palette repeats across the field.",
370
+ hint: "How hard the magnet lifts the fluid.",
362
371
  },
363
372
  },
364
373
  colors: {
365
- colorA: color("Low", "#120458", "Darkest band of the ramp."),
366
- colorB: color("Mid", "#e0245e", "The dominant colour."),
367
- colorC: color("High", "#fdd835", "Peaks of the field."),
374
+ colorA: color("Fluid", "#0d1016", "The black pool at rest."),
375
+ colorB: color("Sheen", "#3d4d63", "The light on the fluid's flanks."),
376
+ colorC: color("Tips", "#b8e6ff", "The top of every spike in the crown."),
368
377
  },
378
+ presets: [
379
+ { name: "Laboratory", colorA: "#0d1016", colorB: "#3d4d63", colorC: "#b8e6ff" },
380
+ { name: "Oil", colorA: "#12100c", colorB: "#4d4436", colorC: "#ffe0a3" },
381
+ { name: "Plasma", colorA: "#130a1a", colorB: "#6d3aa8", colorC: "#ffb8f0" },
382
+ { name: "Mercury", colorA: "#101314", colorB: "#5d6a70", colorC: "#f0fbff" },
383
+ ],
369
384
  },
370
385
  archipelago: {
371
386
  name: "Archipelago",
372
387
  tagline: "A nautical chart on a slow drift",
373
- description: "Unbounded warped fbm thresholded at sea level, so the map scrolls forever without repeating. Contour lines keep their width from screen derivatives, every fifth is drawn heavier, water carries bathymetric tints and the old-map glow that hugs a coast, and the relief is shaded as if engraved.",
388
+ description: "A nautical chart on a slow drift: green land, pale blue water, and contour lines that hold their weight at any size. Every fifth line is drawn heavier, the shallows carry the soft glow an old map puts along a coast, and the relief looks engraved. The map scrolls forever without repeating.",
374
389
  family: "scene",
375
390
  tags: ["island", "map", "editorial", "calm"],
376
391
  cost: "medium",
@@ -432,7 +447,7 @@ export const shaderRegistry = {
432
447
  "pixel-isle": {
433
448
  name: "Pixel Isle",
434
449
  tagline: "A procedural island, one hard biome per cell",
435
- description: "Warped fbm minus a radial falloff makes the terrain; every cell then commits to a single biome from deep water up to snow, with the Bayer screen dithering each border the way hand-made maps do. Waves march against every coast and the tide wets the lowest sand. The seed decides the map: one big island, or an archipelago of two or three.",
450
+ description: "A pixel-art island on a deep blue sea, drawn in a handful of flat colours. Sand, grass and bare rock meet at hard dithered borders, waves march against every coast, and the tide wets the lowest sand. The seed decides the map: one big island, or an archipelago of two or three.",
436
451
  family: "pixel",
437
452
  tags: ["pixel", "retro", "island", "map"],
438
453
  cost: "medium",
@@ -494,7 +509,7 @@ export const shaderRegistry = {
494
509
  voronoi: {
495
510
  name: "Voronoi",
496
511
  tagline: "Animated cells with lit edges",
497
- description: "A jittered Voronoi diagram where every seed moves on its own circle. Cells are tinted by hash, shaded by distance to their seed, and separated by a controllable ridge — crystalline rather than organic.",
512
+ description: "Angular cells with lit edges, each tinted its own shade and darkest at its middle. The cells slide against each other as their seeds travel, so every border re-cuts continuously. Crystalline rather than organic.",
498
513
  family: "geometric",
499
514
  tags: ["cells", "crystal", "structured"],
500
515
  cost: "medium",
@@ -546,68 +561,81 @@ export const shaderRegistry = {
546
561
  colorC: color("Edge", "#9be7ff", "The ridge light."),
547
562
  },
548
563
  },
549
- "liquid-metal": {
550
- name: "Liquid Metal",
551
- tagline: "A warped height field lit like polished chrome",
552
- description: "Noise is warped into a height field, differentiated into a normal, then lit with a moving key light and a banded environment. The banding is what separates metal from plastic, so turn Polish up before you turn Strength up.",
553
- family: "organic",
554
- tags: ["chrome", "reflective", "premium"],
564
+ dunes: {
565
+ name: "Dunes",
566
+ tagline: "A sand sea crawling downwind, crests picked out in light",
567
+ description: "A sand sea drawn in points of light, crawling downwind. The crests are knife ridges that take the accent colour along their spines while the slip faces stay dark, and fine ripples ride over the much larger forms that carry them.",
568
+ family: "particles",
569
+ tags: ["particles", "3d", "hero", "landscape", "calm"],
555
570
  cost: "heavy",
556
571
  controls: {
557
572
  ...base,
558
- speed: { ...base.speed, default: 0.29, max: 2 },
559
- scale: { ...base.scale, default: 0.86 },
560
- intensity: { ...base.intensity, default: 2.05 },
561
- vibrancy: { ...base.vibrancy, default: 0.03 },
562
- vignette: { ...base.vignette, default: 0.87 },
563
- warp: { ...warp, default: 0.79, max: 2 },
564
- relief: {
573
+ speed: { ...base.speed, default: 1, max: 2 },
574
+ scale: { ...base.scale, default: 1, min: 0.4, max: 2.5, hint: "Dune size. Lower is bigger weather." },
575
+ intensity: { ...base.intensity, default: 1.35 },
576
+ vibrancy: { ...base.vibrancy, default: 1.05 },
577
+ vignette: { ...base.vignette, default: 0.4 },
578
+ warp: {
579
+ ...warp,
580
+ label: "Meander",
581
+ min: 0,
582
+ max: 2,
583
+ default: 0.7,
584
+ hint: "How much the dune belts snake instead of running in ruler lines.",
585
+ },
586
+ ridge: {
565
587
  slot: "a",
566
- label: "Relief",
567
- min: 0.05,
568
- max: 3,
588
+ label: "Ridge",
589
+ min: 0,
590
+ max: 1,
569
591
  step: 0.01,
570
- default: 2.57,
571
- hint: "Steepness of the surface. High values give a boiling, molten look.",
592
+ default: 0.7,
593
+ hint: "0 is soft hills, 1 is sharp slip faces.",
572
594
  },
573
- polish: {
595
+ wind: {
574
596
  slot: "b",
575
- label: "Polish",
576
- min: 0,
577
- max: 1,
597
+ label: "Wind",
598
+ min: -2,
599
+ max: 2,
578
600
  step: 0.01,
579
- default: 0.31,
580
- hint: "Tightness of the specular highlight.",
601
+ default: 0.6,
602
+ hint: "Drift of the whole sand sea. Negative reverses it.",
581
603
  },
582
- body: {
604
+ crest: {
583
605
  slot: "c",
584
- label: "Body",
606
+ label: "Crest glow",
585
607
  min: 0,
586
608
  max: 2,
587
609
  step: 0.01,
588
- default: 1.18,
589
- hint: "Weight of the environment reflection under the highlight.",
610
+ default: 1,
611
+ hint: "The accent colour along the ridge spines.",
590
612
  },
591
- rim: {
613
+ ripples: {
592
614
  slot: "d",
593
- label: "Rim",
615
+ label: "Ripples",
594
616
  min: 0,
595
617
  max: 2,
596
618
  step: 0.01,
597
- default: 1.21,
598
- hint: "Fresnel glow at grazing angles.",
619
+ default: 0.8,
620
+ hint: "The fine wind ripples riding the dune faces.",
599
621
  },
600
622
  },
601
623
  colors: {
602
- colorA: color("Steel", "#8a3121", "The dark side of the environment."),
603
- colorB: color("Sheen", "#0f236b", "Mid reflection."),
604
- colorC: color("Hot", "#da41c6", "Brightest reflection and rim light."),
624
+ colorA: color("Night sand", "#1a1428", "The sand in shadow, and the dark between dots."),
625
+ colorB: color("Dune", "#8a5fb8", "The lit body of every dune."),
626
+ colorC: color("Crest", "#ffd9a8", "The spines the light catches."),
605
627
  },
628
+ presets: [
629
+ { name: "Moonlit", colorA: "#1a1428", colorB: "#8a5fb8", colorC: "#ffd9a8" },
630
+ { name: "Sahara", colorA: "#2b1a10", colorB: "#c98544", colorC: "#ffe8bd" },
631
+ { name: "Ash", colorA: "#131417", colorB: "#5d6672", colorC: "#e6ecf2" },
632
+ { name: "Mars", colorA: "#200c08", colorB: "#a83f22", colorC: "#ffb37a" },
633
+ ],
606
634
  },
607
635
  starfield: {
608
636
  name: "Starfield",
609
637
  tagline: "A warp corridor of depth-sorted stars",
610
- description: "Six depth slices of hashed star points, each scaled and faded by its distance, with radial motion blur that turns points into streaks. Push Streak and it goes from a calm night sky to a jump to lightspeed.",
638
+ description: "Stars in depth, streaked outward from the middle of the frame like a warp corridor. Near stars are large and bright, far ones are faint dust. Low streak is a calm night sky; high streak is a jump to lightspeed.",
611
639
  family: "spatial",
612
640
  tags: ["space", "motion", "dark"],
613
641
  cost: "medium",
@@ -664,7 +692,7 @@ export const shaderRegistry = {
664
692
  ripple: {
665
693
  name: "Ripple",
666
694
  tagline: "Interference between travelling circular waves",
667
- description: "Five wave sources orbit the frame; their sum is read as a height field and its slope is used to refract the palette, with a separate caustic term where the wavefronts focus. Genuinely physical, not a stack of sine stripes.",
695
+ description: "Circular waves from several travelling sources cross into a standing interference pattern, with bright ridges where the fronts meet and flares where they focus. The colour bends along the slope of the water, so it reads as a surface rather than as stacked stripes.",
668
696
  family: "organic",
669
697
  tags: ["water", "interference", "calm"],
670
698
  cost: "medium",
@@ -721,7 +749,7 @@ export const shaderRegistry = {
721
749
  "film-grain": {
722
750
  name: "Film Grain",
723
751
  tagline: "Stock grain, halation and scanlines over a slow wash",
724
- description: "A texture pass rather than a picture: a slow noise wash read through three chromatically offset channels, then buried in resolution-independent grain, scanlines and halation. Sits well behind text at low Strength.",
752
+ description: "A slow, almost featureless wash of colour buried in grain, with soft scanlines over it and a halo around anything bright. The colour separates a little at the edges, the way film stock does. At low strength it sits quietly behind text.",
725
753
  family: "texture",
726
754
  tags: ["analog", "overlay", "noise"],
727
755
  cost: "light",
@@ -778,7 +806,7 @@ export const shaderRegistry = {
778
806
  truchet: {
779
807
  name: "Truchet",
780
808
  tagline: "Quarter-arc tiles that flip in place",
781
- description: "A Truchet tiling where each tile decides its own orientation on its own clock, so the maze continuously rewires itself while the whole field pans and rotates. Hard-edged line art with no noise wash anywhere.",
809
+ description: "Quarter-circle arcs on a black ground, joining tile to tile into one continuous maze. Each tile flips on its own clock, so the maze rewires itself while the whole field pans and turns. Hard-edged line art with no soft wash anywhere.",
782
810
  family: "geometric",
783
811
  tags: ["lines", "pattern", "graphic"],
784
812
  cost: "light",
@@ -834,7 +862,7 @@ export const shaderRegistry = {
834
862
  kaleidoscope: {
835
863
  name: "Kaleidoscope",
836
864
  tagline: "Polar mirror folding over a drifting field",
837
- description: "The angle around the centre is folded into one wedge and mirrored, then a warped noise field and a ring pattern are read through it. Segments is the control that changes the character entirely.",
865
+ description: "A radial rosette: one wedge of a drifting field mirrored around the centre into a symmetric flower of colour and rings. The pattern breathes and turns slowly. Segment count changes the character completely.",
838
866
  family: "geometric",
839
867
  tags: ["symmetry", "polar", "hypnotic"],
840
868
  cost: "medium",
@@ -890,7 +918,7 @@ export const shaderRegistry = {
890
918
  halftone: {
891
919
  name: "Halftone",
892
920
  tagline: "A duotone image reproduced as a rotated dot screen",
893
- description: "A continuous noise image is screened through a rotated grid of dots whose radius tracks local ink coverage — the way an actual halftone plate works. Screen angle and dot pitch matter more than any colour choice here.",
921
+ description: "A two-colour picture reproduced as a screen of dots on a rotated grid, dense in the shadows and open in the highlights, exactly as a printing plate lays ink down. Screen angle and dot pitch matter more here than any colour choice.",
894
922
  family: "texture",
895
923
  tags: ["print", "duotone", "editorial"],
896
924
  cost: "light",
@@ -944,8 +972,8 @@ export const shaderRegistry = {
944
972
  },
945
973
  tunnel: {
946
974
  name: "Tunnel",
947
- tagline: "A raymarched corridor with emissive rings",
948
- description: "A real sphere-traced scene: the camera flies down a curving corrugated tube, the wall is textured in tunnel space, and lit rings pass overhead at fixed intervals. The most expensive shader here, and the only one with actual depth.",
975
+ tagline: "A corridor flying past lit rings",
976
+ description: "A corrugated corridor seen from inside, curving away into the dark, with bright rings passing overhead at regular intervals. The camera flies forward continuously. The most expensive shader here, and the only one with real depth.",
949
977
  family: "spatial",
950
978
  tags: ["raymarching", "3d", "motion"],
951
979
  cost: "heavy",
@@ -999,8 +1027,8 @@ export const shaderRegistry = {
999
1027
  },
1000
1028
  julia: {
1001
1029
  name: "Julia",
1002
- tagline: "Escape-time fractal with orbit-trap colouring",
1003
- description: "A Julia set whose seed walks a circle near the cardioid edge, so the shape morphs between connected and dust-like without ever being static. Colour comes from a smoothed iteration count plus a distance-to-unit-circle orbit trap.",
1030
+ tagline: "A morphing fractal ringed with colour bands",
1031
+ description: "A fractal caught between a solid body and a cloud of dust, ringed by tight bands of colour that crowd toward its edge. The shape morphs continuously between the two states, so it is never static and never repeats.",
1004
1032
  family: "fractal",
1005
1033
  tags: ["mathematical", "detail", "zoom"],
1006
1034
  cost: "heavy",
@@ -1055,8 +1083,8 @@ export const shaderRegistry = {
1055
1083
  },
1056
1084
  silk: {
1057
1085
  name: "Silk",
1058
- tagline: "Anisotropic sheen across warped fibre lines",
1059
- description: "Two stages of domain warp fold the plane, then dense parallel fibres are bent along the folds and given a directional sheen. Creases darken, ridges catch the light — cloth rather than liquid.",
1086
+ tagline: "A sheen running across folded fibres",
1087
+ description: "Dense parallel fibres bent into wide folds, with a directional sheen that lights the ridges and darkens the creases. It reads as cloth catching the light rather than as liquid.",
1060
1088
  family: "organic",
1061
1089
  tags: ["fabric", "soft", "luxury"],
1062
1090
  cost: "medium",
@@ -1114,7 +1142,7 @@ export const shaderRegistry = {
1114
1142
  "neon-grid": {
1115
1143
  name: "Neon Grid",
1116
1144
  tagline: "Perspective floor, banded sun, horizon haze",
1117
- description: "A projected floor grid with analytic line width, a horizontal-banded sun sitting on the horizon, and a haze band welding the two together. Synthwave, executed straight rather than ironically.",
1145
+ description: "A cyan grid running back to a horizon under a banded sun, with a haze band welding the floor to the sky. Synthwave played straight rather than ironically.",
1118
1146
  family: "spatial",
1119
1147
  tags: ["synthwave", "retro", "horizon"],
1120
1148
  cost: "light",
@@ -1170,7 +1198,7 @@ export const shaderRegistry = {
1170
1198
  bokeh: {
1171
1199
  name: "Bokeh",
1172
1200
  tagline: "Out-of-focus lights drifting through depth",
1173
- description: "Four depth layers of hashed light points, each rendered as a disc with a bright rim — how a real lens renders a defocused highlight. Nearer layers are larger and brighter, so the field reads as depth rather than as flat circles.",
1201
+ description: "Out-of-focus lights drifting in depth, each a soft disc with a brighter rim, which is how a fast lens renders a highlight it cannot resolve. Near discs are large and bright, far ones small and dim, so the field reads as depth instead of as flat circles.",
1174
1202
  family: "spatial",
1175
1203
  tags: ["lights", "depth", "festive"],
1176
1204
  cost: "medium",
@@ -1224,8 +1252,8 @@ export const shaderRegistry = {
1224
1252
  },
1225
1253
  dither: {
1226
1254
  name: "Dither",
1227
- tagline: "A smooth field quantised through an 8×8 Bayer matrix",
1228
- description: "The source image is pixelated, offset by an ordered-dither threshold, then crushed to a handful of levels. Deliberately low-fi: flat colour, a visible pattern, and no antialiasing anywhere.",
1255
+ tagline: "Flat colour and a visible dot pattern",
1256
+ description: "The layer crushed down to a few flat colours and screened through a coarse, visible dot pattern, with chunky pixel steps and no smoothing anywhere. Deliberately low-fi.",
1229
1257
  family: "texture",
1230
1258
  tags: ["lofi", "pixel", "poster"],
1231
1259
  cost: "light",
@@ -1279,57 +1307,41 @@ export const shaderRegistry = {
1279
1307
  },
1280
1308
  "mesh-gradient": {
1281
1309
  name: "Mesh Gradient",
1282
- tagline: "Soft colour centres orbiting behind frosted glass",
1283
- description: "Four gaussian colour wells drift on independent orbits and blend by weight, with a gentle domain warp so the result never collapses into obvious radial gradients. The default for marketing surfaces and card backgrounds.",
1310
+ tagline: "Flowing colour spots under swirl and noise",
1311
+ description: "Four soft colour spots drift on slow orbits and melt into one another, with a swirl at the centre that fades toward the edges and a gentle bend over the whole frame. The midpoints stay vivid instead of greying out. The default for marketing surfaces and card backgrounds.",
1284
1312
  family: "gradient",
1285
1313
  tags: ["ambient", "background", "soft"],
1286
1314
  cost: "light",
1287
1315
  controls: {
1288
1316
  ...base,
1289
- speed: { ...base.speed, default: 1.23, max: 2 },
1290
- scale: { ...base.scale, default: 2.57 },
1291
- intensity: { ...base.intensity, default: 2.17 },
1292
- vibrancy: { ...base.vibrancy, default: 1.54 },
1293
- vignette: { ...base.vignette, default: 0.96 },
1294
- warp: { ...warp, default: 0.94, max: 1.5 },
1295
- softness: {
1296
- slot: "a",
1297
- label: "Softness",
1298
- min: 0.1,
1299
- max: 1.2,
1300
- step: 0.01,
1301
- default: 0.94,
1302
- hint: "Radius of each colour well. Larger means a flatter blend.",
1317
+ speed: { ...base.speed, max: 2 },
1318
+ vignette: { ...base.vignette, default: 0 },
1319
+ warp: {
1320
+ ...warp,
1321
+ label: "Distortion",
1322
+ max: 1.5,
1323
+ hint: "How far the simplex field bends the sampling domain.",
1303
1324
  },
1304
- spread: {
1305
- slot: "b",
1306
- label: "Spread",
1325
+ swirl: {
1326
+ slot: "a",
1327
+ label: "Swirl",
1307
1328
  min: 0,
1308
- max: 1,
1309
- step: 0.01,
1310
- default: 0.51,
1311
- hint: "How far the wells travel from the centre.",
1312
- },
1313
- coverage: {
1314
- slot: "c",
1315
- label: "Coverage",
1316
- min: 0.2,
1317
- max: 4,
1329
+ max: 2,
1318
1330
  step: 0.01,
1319
- default: 1.15,
1320
- hint: "How much of the dark backdrop the colour hides.",
1331
+ default: 0.7,
1332
+ hint: "Rotation of the domain around the centre; decays toward the edges.",
1321
1333
  },
1322
1334
  },
1323
1335
  colors: {
1324
- colorA: color("First", "#555810", "Warm anchor colour."),
1325
- colorB: color("Second", "#e7e94f", "Mid tone that bridges the other two."),
1326
- colorC: color("Third", "#55bc19", "Cool accent."),
1336
+ colorA: color("First", "#471c4e", "Deep anchor; the fourth spot wears it again."),
1337
+ colorB: color("Second", "#e7597c", "Bright mid tone."),
1338
+ colorC: color("Third", "#ffe0c2", "Pale highlight."),
1327
1339
  },
1328
1340
  },
1329
1341
  radiance: {
1330
1342
  name: "Radiance",
1331
1343
  tagline: "Lamps in a dark room, traced to whatever they light",
1332
- description: "Global illumination taken the short way round. There is no light pass and no probe grid to merge: the room is a handful of signed distances, so every pixel fans rays into it and marches each one back to its source. That buys a true shadow — hard where a lamp is small, soft where it is near, and cast by bars that turn every frame. The pointer is the brightest lamp in the room, so moving it moves every shadow.",
1344
+ description: "A dark room with a few small lamps in it, and everything they light. Shadows are hard beside a small lamp and soft beside a near one, and turning bars sweep shadow blades across the floor. The pointer is the brightest lamp in the room, so moving it moves every shadow.",
1333
1345
  family: "spatial",
1334
1346
  tags: ["light", "shadow", "dark", "pointer"],
1335
1347
  cost: "heavy",
@@ -1385,7 +1397,7 @@ export const shaderRegistry = {
1385
1397
  lumen: {
1386
1398
  name: "Lumen",
1387
1399
  tagline: "A lattice of dots, each one a lamp and a wall at once",
1388
- description: "Every dot gives light and blocks it, so the field shadows itself. The lattice is what makes that affordable: all the dots are the same size, so the nearest one to any point is simply the nearest lattice node and the distance to the whole field is exact rather than estimated. A ray crosses a dozen cells in a few steps, which is why the shadows run the width of the frame. A wave decides which dots are lit; the dark ones stay in the picture as grey, and keep casting.",
1400
+ description: "A lattice of glowing dots on a coloured ground, where every dot both gives light and blocks it, so shadows run the full width of the frame. A wave decides which dots are lit; the dark ones stay in the picture as grey and keep casting.",
1389
1401
  family: "geometric",
1390
1402
  tags: ["light", "grid", "loader", "dark"],
1391
1403
  cost: "heavy",
@@ -1441,7 +1453,7 @@ export const shaderRegistry = {
1441
1453
  beacon: {
1442
1454
  name: "Beacon",
1443
1455
  tagline: "A triangle of LEDs on a floor that catches what they throw",
1444
- description: "The glow is computed, never blurred. Each edge contributes an exponential falloff off the line itself and a second off the emitter nearest along it, both analytic, so the halo keeps its shape at any zoom and the LEDs stay round at any pixel density. The floor is the same light field read at the mirrored point, widened with depth — a reflection for the price of a second lookup. Give two edges different colours and the plate picks up both.",
1456
+ description: "A triangle of LED strip glowing in the dark, with the round emitters visible along each edge and a widening reflection on the floor below. The halo holds its shape at any size and the LEDs stay round at any pixel density. Give two edges different colours and the floor picks up both.",
1445
1457
  family: "geometric",
1446
1458
  tags: ["hero", "neon", "dark", "pointer"],
1447
1459
  cost: "light",
@@ -1497,7 +1509,7 @@ export const shaderRegistry = {
1497
1509
  orb: {
1498
1510
  name: "Orb",
1499
1511
  tagline: "A liquid blob suspended in a sphere of glass",
1500
- description: "The glass is analytic and the blob is marched, which is the only way this fits in one pass: a sphere is two roots of a quadratic, so entry, exit and both normals are exact and the ray only has to be stepped between them. The body inside is lobes melted together with a smooth minimum, which is what keeps it reading as one liquid thing rather than as balls in a bag. Nothing has a hard edge — the silhouette is antialiased off a field that stays smooth across the frame, and the blob off its own distance. The pointer turns the studio, so the highlights travel across the glass.",
1512
+ description: "A liquid blob suspended inside a glass sphere, lit like a studio object: highlights on the glass, refraction through it, and lobes melted into one soft body inside. Nothing has a hard edge. The pointer turns the studio, so the highlights travel across the glass.",
1501
1513
  family: "organic",
1502
1514
  tags: ["glass", "hero", "3d", "pointer"],
1503
1515
  cost: "heavy",
@@ -1561,7 +1573,7 @@ export const shaderRegistry = {
1561
1573
  eyes: {
1562
1574
  name: "Eyes",
1563
1575
  tagline: "A wall of eyes that look where the pointer goes",
1564
- description: "Each cell is one eye: an almond of sclera, an iris that travels toward the cursor, a lid that blinks on its own clock. The gaze is the interactive part — move the pointer and the whole wall follows it — but the idle frame carries itself: with no pointer the eyes wander, each on its own phase, so a card is never a grid of dead centres.",
1576
+ description: "A wall of eyes, each a pale almond of sclera around a coloured iris, blinking on its own clock. Move the pointer and every iris turns to follow it. With no pointer they wander, each on its own phase, so the frame is never a grid of dead centres.",
1565
1577
  family: "geometric",
1566
1578
  tags: ["interactive", "pointer", "playful"],
1567
1579
  cost: "light",
@@ -1616,7 +1628,7 @@ export const shaderRegistry = {
1616
1628
  tesla: {
1617
1629
  name: "Tesla",
1618
1630
  tagline: "A plasma globe whose filament reaches for your finger",
1619
- description: "The bolts are analytic: each one is a base angle plus a noise wiggle that grows with radius, so a pixel's distance to a filament is its angular error times its radius — no marching, no segments. Bolts re-roll their heading on a coarse clock, which is the jump that reads as electricity. One bolt always seeks the pointer, clamped to the inside of the glass, exactly what the real toy does when a hand touches the dome.",
1631
+ description: "A plasma globe: bright filaments branch from a core out to the inside of the glass, wandering and then snapping to new headings. One filament always reaches for the pointer and stops at the glass, exactly what the real toy does when a hand touches the dome.",
1620
1632
  family: "organic",
1621
1633
  tags: ["interactive", "pointer", "dark", "hero"],
1622
1634
  cost: "medium",
@@ -1679,7 +1691,7 @@ export const shaderRegistry = {
1679
1691
  magnet: {
1680
1692
  name: "Magnet",
1681
1693
  tagline: "Field lines of three charges, one riding the pointer",
1682
- description: "Nothing here is traced. The stream function of a point charge is its angle and its potential is the log of its distance, so field lines are level sets of one sum and equipotentials of the other — the whole plot is two sin() calls over closed forms, live at any resolution. The pointer carries the third charge; its slider steps by whole numbers because the picture's continuity across the branch cuts depends on the charges being integers.",
1694
+ description: "The field lines of three charges, drawn as smooth curves that fan out of each pole and loop into the next, over softly shaded equipotentials. The pointer carries the third charge, so dragging it re-routes every line on screen.",
1683
1695
  family: "geometric",
1684
1696
  tags: ["interactive", "pointer", "diagram"],
1685
1697
  cost: "light",
@@ -1725,7 +1737,7 @@ export const shaderRegistry = {
1725
1737
  torch: {
1726
1738
  name: "Torch",
1727
1739
  tagline: "A light in your hand, moving over rock in the dark",
1728
- description: "The wall is a heightfield and the lamp is the pointer, so the shading is honest: the fbm that draws the rock is differentiated for a normal, and crevices light up and go dark as the torch passes over them — which is what makes the surface read as carved rather than printed. The flame gutters on two noise rates, a slow breathe under a fast sputter, and dust motes drift through the beam because lit air is the only air you can see.",
1740
+ description: "Rough rock in the dark, with a light in your hand. Crevices light up and fall dark as the pointer passes over them, so the surface reads as carved rather than printed. The flame gutters on a slow breathe under a fast sputter, and dust drifts through the beam.",
1729
1741
  family: "spatial",
1730
1742
  tags: ["interactive", "pointer", "dark"],
1731
1743
  cost: "medium",
@@ -1788,7 +1800,7 @@ export const shaderRegistry = {
1788
1800
  parallax: {
1789
1801
  name: "Parallax",
1790
1802
  tagline: "Ridgelines in depth, and the pointer moves the camera",
1791
- description: "Five silhouettes, each a one-dimensional ridged fbm thresholded against the pixel's height. Depth is faked twice over: haze mixes each layer toward the sky, and the pointer pans each layer by its own factor — the near ridge slides furthest, which is the one cue that turns a flat stack into a landscape you are standing in. Time scrolls the world slowly on its own.",
1803
+ description: "Ridgelines stacked into the distance, each a flat silhouette paler than the one in front, under a low sun. Move the pointer and the near ridge slides furthest, which turns the flat stack into a landscape you are standing in. The world scrolls slowly on its own.",
1792
1804
  family: "organic",
1793
1805
  tags: ["interactive", "pointer", "hero", "calm"],
1794
1806
  cost: "medium",
@@ -1842,7 +1854,7 @@ export const shaderRegistry = {
1842
1854
  gravity: {
1843
1855
  name: "Gravity",
1844
1856
  tagline: "A starfield lensed by a mass that rides the pointer",
1845
- description: "The lens is the physics, simplified once: a point mass deflects light by the square of its Einstein radius over the impact distance, so every sample is just read from a pushed position. That one line produces everything the picture is known for — stars smeared into arcs, the ring at the Einstein radius, doubled images inside it — and dragging the pointer drags the distortion across the sky.",
1857
+ description: "A starfield behind a heavy mass: the stars smear into arcs around it, a bright ring stands at the lensing radius, and images double inside that ring. Dragging the pointer drags the whole distortion across the sky.",
1846
1858
  family: "spatial",
1847
1859
  tags: ["interactive", "pointer", "dark", "hero"],
1848
1860
  cost: "medium",
@@ -1897,7 +1909,7 @@ export const shaderRegistry = {
1897
1909
  particles: {
1898
1910
  name: "Particles",
1899
1911
  tagline: "A hundred thousand embers riding a wind you can bend",
1900
- description: "A real particle system, not a texture of dots: every ember integrates through a curl-noise wind on the GPU and deposits its passage into an exposure that never quite forgets. The curl is what keeps it alive — a divergence-free field has no sinks, so the streams braid and circulate instead of pooling. The picture is the long exposure, not the frame: trails are history, and colour is speed. The pointer is a vortex that gathers the swarm; push its charge below zero and it scatters instead.",
1912
+ description: "A hundred thousand embers riding a turbulent wind, drawn as a long exposure that never quite forgets — the trails are history and the colour is speed. The streams braid and circulate instead of pooling. The pointer is a vortex that gathers the swarm; push its charge below zero and it scatters instead.",
1901
1913
  family: "compute",
1902
1914
  tags: ["simulation", "interactive", "pointer", "hero", "dark"],
1903
1915
  cost: "medium",
@@ -1962,7 +1974,7 @@ export const shaderRegistry = {
1962
1974
  fluid: {
1963
1975
  name: "Fluid",
1964
1976
  tagline: "Ink in water that answers the pointer",
1965
- description: "The incompressible Navier–Stokes equations, solved for real every frame: velocity advects through itself, twenty pressure sweeps cancel the divergence, and vorticity confinement feeds back the small whirls a coarse grid keeps averaging away. The dye rides a grid four times finer than the velocity that carries it, so the physics stays cheap while the ink stays sharp. Drag the pointer to splat force and colour together; leave it alone and it breathes on its own.",
1977
+ description: "Ink in water. Drag the pointer and colour lays down in one unbroken stroke, then curls and frays into the whirls a real stroke leaves behind. Leave it alone and the surface breathes, throwing slow plumes of its own.",
1966
1978
  family: "compute",
1967
1979
  tags: ["simulation", "interactive", "pointer", "hero", "liquid"],
1968
1980
  cost: "heavy",
@@ -2025,7 +2037,7 @@ export const shaderRegistry = {
2025
2037
  cloth: {
2026
2038
  name: "Cloth",
2027
2039
  tagline: "A sheet of silk in a wind, and the pointer is a hand",
2028
- description: "Two and a half thousand points hold each other at fixed distances — structural, shear and bend — and relax in parallel ten times a frame, the way cloth solvers have worked since Jakobsen. The sheet hangs from its pins, billows on a two-speed wind, and drapes around an invisible sphere the pointer carries, so a slow hand presses a bulge into it and a fast one throws a fold across the whole width. With no vertex pipeline in sight, the cloth rasterises itself: each cell splats its patch of surface into an atomic depth buffer, and the shading is done back on the true sheet — smooth normals, a thread-direction sheen, a shadow on the wall behind.",
2040
+ description: "A sheet of silk hanging from its top edge, billowing on a two-speed wind, with soft folds and a sheen running along the thread. The pointer carries an invisible ball: a slow hand presses a bulge into the sheet, a fast one throws a fold across the whole width.",
2029
2041
  family: "compute",
2030
2042
  tags: ["simulation", "interactive", "pointer", "fabric", "3d"],
2031
2043
  cost: "heavy",
@@ -2078,10 +2090,337 @@ export const shaderRegistry = {
2078
2090
  colorC: color("Sheen", "#68ef6d", "The light along the threads."),
2079
2091
  },
2080
2092
  },
2093
+ chladni: {
2094
+ name: "Chladni",
2095
+ tagline: "A singing plate, mapped by the sand on its silent lines",
2096
+ description: "A square plate that sings, mapped by the bright points that gather on the lines which never move — the same way sand walks to the silence on a real vibrating plate. The figure ripples through zero as the plate rings, and sweeping the mode numbers re-solves one figure into the next instead of cutting.",
2097
+ family: "particles",
2098
+ tags: ["particles", "3d", "hero", "dark", "scientific"],
2099
+ cost: "heavy",
2100
+ controls: {
2101
+ ...base,
2102
+ speed: { ...base.speed, default: 0.9, max: 2 },
2103
+ scale: { ...base.scale, default: 1, min: 0.4, max: 2, hint: "Zoom of the plate in the frame." },
2104
+ intensity: { ...base.intensity, default: 1 },
2105
+ vibrancy: { ...base.vibrancy, default: 1.1 },
2106
+ vignette: { ...base.vignette, default: 0.35 },
2107
+ warp: {
2108
+ ...warp,
2109
+ label: "Ripple",
2110
+ min: 0,
2111
+ max: 2,
2112
+ default: 0.5,
2113
+ hint: "A travelling wave from the driver at the centre, on top of the figure.",
2114
+ },
2115
+ "mode-m": {
2116
+ slot: "a",
2117
+ label: "Mode m",
2118
+ min: 1,
2119
+ max: 9,
2120
+ step: 1,
2121
+ default: 3,
2122
+ hint: "First mode number. The pair decides which figure the plate sings.",
2123
+ },
2124
+ "mode-n": {
2125
+ slot: "b",
2126
+ label: "Mode n",
2127
+ min: 1,
2128
+ max: 9,
2129
+ step: 1,
2130
+ default: 5,
2131
+ hint: "Second mode number. Equal numbers cancel to a flat plate.",
2132
+ },
2133
+ sand: {
2134
+ slot: "c",
2135
+ label: "Sand",
2136
+ min: 0,
2137
+ max: 2,
2138
+ step: 0.01,
2139
+ default: 1.1,
2140
+ hint: "How brightly the nodal lines collect the accent colour.",
2141
+ },
2142
+ sweep: {
2143
+ slot: "d",
2144
+ label: "Sweep",
2145
+ min: 0,
2146
+ max: 2,
2147
+ step: 0.01,
2148
+ default: 0.6,
2149
+ hint: "Drifts both mode numbers, morphing one figure into the next. 0 holds still.",
2150
+ },
2151
+ },
2152
+ colors: {
2153
+ colorA: color("Plate", "#101b2e", "The dark metal under everything."),
2154
+ colorB: color("Wave", "#3f6fde", "The moving body of the figure."),
2155
+ colorC: color("Sand", "#f5e9c8", "The grains on the silent lines."),
2156
+ },
2157
+ presets: [
2158
+ { name: "Workshop", colorA: "#101b2e", colorB: "#3f6fde", colorC: "#f5e9c8" },
2159
+ { name: "Oscilloscope", colorA: "#04140c", colorB: "#1fbf6e", colorC: "#d8ffe9" },
2160
+ { name: "Rose", colorA: "#1d0f1e", colorB: "#b04a8f", colorC: "#ffd9e8" },
2161
+ { name: "Heat", colorA: "#1a0d08", colorB: "#c2521f", colorC: "#ffe3a3" },
2162
+ ],
2163
+ },
2164
+ "liquid-metal": {
2165
+ name: "Liquid Metal",
2166
+ tagline: "Polished chrome, rippling",
2167
+ description: "Polished chrome, rippling. Banded reflections slide across the surface and a moving key light picks out the crests; the banding is what separates metal from plastic, so turn Polish up before you turn Strength up.",
2168
+ family: "organic",
2169
+ tags: ["chrome", "reflective", "premium"],
2170
+ cost: "heavy",
2171
+ controls: {
2172
+ ...base,
2173
+ speed: { ...base.speed, default: 0.29, max: 2 },
2174
+ scale: { ...base.scale, default: 0.86 },
2175
+ intensity: { ...base.intensity, default: 2.05 },
2176
+ vibrancy: { ...base.vibrancy, default: 0.03 },
2177
+ vignette: { ...base.vignette, default: 0.87 },
2178
+ warp: { ...warp, default: 0.79, max: 2 },
2179
+ relief: {
2180
+ slot: "a",
2181
+ label: "Relief",
2182
+ min: 0.05,
2183
+ max: 3,
2184
+ step: 0.01,
2185
+ default: 2.57,
2186
+ hint: "Steepness of the surface. High values give a boiling, molten look.",
2187
+ },
2188
+ polish: {
2189
+ slot: "b",
2190
+ label: "Polish",
2191
+ min: 0,
2192
+ max: 1,
2193
+ step: 0.01,
2194
+ default: 0.31,
2195
+ hint: "Tightness of the specular highlight.",
2196
+ },
2197
+ body: {
2198
+ slot: "c",
2199
+ label: "Body",
2200
+ min: 0,
2201
+ max: 2,
2202
+ step: 0.01,
2203
+ default: 1.18,
2204
+ hint: "Weight of the environment reflection under the highlight.",
2205
+ },
2206
+ rim: {
2207
+ slot: "d",
2208
+ label: "Rim",
2209
+ min: 0,
2210
+ max: 2,
2211
+ step: 0.01,
2212
+ default: 1.21,
2213
+ hint: "Fresnel glow at grazing angles.",
2214
+ },
2215
+ },
2216
+ colors: {
2217
+ colorA: color("Steel", "#8a3121", "The dark side of the environment."),
2218
+ colorB: color("Sheen", "#0f236b", "Mid reflection."),
2219
+ colorC: color("Hot", "#da41c6", "Brightest reflection and rim light."),
2220
+ },
2221
+ },
2222
+ maelstrom: {
2223
+ name: "Maelstrom",
2224
+ tagline: "A whirlpool of particles, wound into the drain",
2225
+ description: "A whirlpool of points seen from the rim, its arms winding tighter as they near a funnel at the centre. The dots visibly circle the drain rather than bob on a waving floor, and froth rides the forward face of each arm and thickens toward the eye.",
2226
+ family: "particles",
2227
+ tags: ["particles", "3d", "hero", "dark", "motion"],
2228
+ cost: "heavy",
2229
+ controls: {
2230
+ ...base,
2231
+ speed: { ...base.speed, default: 0.52, max: 2.5 },
2232
+ scale: { ...base.scale, default: 1.76, min: 0.4, max: 2, hint: "Zoom of the vortex in the frame." },
2233
+ intensity: { ...base.intensity, default: 0.43 },
2234
+ vibrancy: { ...base.vibrancy, default: 0.59 },
2235
+ vignette: { ...base.vignette, default: 0.76 },
2236
+ warp: {
2237
+ ...warp,
2238
+ label: "Wander",
2239
+ min: 0,
2240
+ max: 2,
2241
+ default: 1.54,
2242
+ hint: "How far the eye drifts from centre. 0 pins it like a screensaver.",
2243
+ },
2244
+ arms: {
2245
+ slot: "a",
2246
+ label: "Arms",
2247
+ min: 1,
2248
+ max: 8,
2249
+ step: 1,
2250
+ default: 5,
2251
+ hint: "Spiral arms wound into the funnel.",
2252
+ },
2253
+ twist: {
2254
+ slot: "b",
2255
+ label: "Twist",
2256
+ min: 0,
2257
+ max: 3,
2258
+ step: 0.01,
2259
+ default: 2.84,
2260
+ hint: "How tightly the arms wind. 0 makes straight spokes.",
2261
+ },
2262
+ churn: {
2263
+ slot: "c",
2264
+ label: "Churn",
2265
+ min: 0,
2266
+ max: 2,
2267
+ step: 0.01,
2268
+ default: 0.56,
2269
+ hint: "Broken water riding the arms, and the froth it feeds.",
2270
+ },
2271
+ depth: {
2272
+ slot: "d",
2273
+ label: "Depth",
2274
+ min: 0,
2275
+ max: 2,
2276
+ step: 0.01,
2277
+ default: 0.54,
2278
+ hint: "The funnel at the middle. 0 flattens the drain shut.",
2279
+ },
2280
+ },
2281
+ colors: {
2282
+ colorA: color("Deep", "#0a1a24", "The water the light does not reach."),
2283
+ colorB: color("Current", "#1e8f9e", "The turning body of the vortex."),
2284
+ colorC: color("Froth", "#dffbff", "The broken water on every arm."),
2285
+ },
2286
+ presets: [
2287
+ { name: "North sea", colorA: "#0a1a24", colorB: "#1e8f9e", colorC: "#dffbff" },
2288
+ { name: "Ink", colorA: "#0d0d16", colorB: "#4b3f9e", colorC: "#c9bfff" },
2289
+ { name: "Lava", colorA: "#170a06", colorB: "#b8461c", colorC: "#ffd9a0" },
2290
+ { name: "Lagoon", colorA: "#062621", colorB: "#17a884", colorC: "#e8fff2" },
2291
+ ],
2292
+ },
2293
+ plasma: {
2294
+ name: "Plasma",
2295
+ tagline: "Loud blobs of colour, cut by contour lines",
2296
+ description: "Big soft blobs of saturated colour, cut by thin contour lines and cycling continuously through the palette. Loud on purpose — the counterweight to the quiet gradients in this catalogue.",
2297
+ family: "geometric",
2298
+ tags: ["retro", "loud", "cycling"],
2299
+ cost: "light",
2300
+ controls: {
2301
+ ...base,
2302
+ speed: { ...base.speed, default: 0.7 },
2303
+ scale: { ...base.scale, default: 0.55, min: 0.1, max: 2 },
2304
+ vibrancy: { ...base.vibrancy, default: 1.25 },
2305
+ vignette: { ...base.vignette, default: 0.3 },
2306
+ radial: {
2307
+ slot: "a",
2308
+ label: "Radial",
2309
+ min: 0,
2310
+ max: 3,
2311
+ step: 0.01,
2312
+ default: 1,
2313
+ hint: "Weight of the concentric ring field.",
2314
+ },
2315
+ swirl: {
2316
+ slot: "b",
2317
+ label: "Swirl",
2318
+ min: 0,
2319
+ max: 3,
2320
+ step: 0.01,
2321
+ default: 1,
2322
+ hint: "Rotation rate of the secondary interference field.",
2323
+ },
2324
+ interference: {
2325
+ slot: "c",
2326
+ label: "Interference",
2327
+ min: 0,
2328
+ max: 2,
2329
+ step: 0.01,
2330
+ default: 0.8,
2331
+ hint: "How strongly the rotating field beats against the rest.",
2332
+ },
2333
+ cycles: {
2334
+ slot: "d",
2335
+ label: "Colour cycles",
2336
+ min: 0.2,
2337
+ max: 4,
2338
+ step: 0.01,
2339
+ default: 1,
2340
+ hint: "Number of times the palette repeats across the field.",
2341
+ },
2342
+ },
2343
+ colors: {
2344
+ colorA: color("Low", "#120458", "Darkest band of the ramp."),
2345
+ colorB: color("Mid", "#e0245e", "The dominant colour."),
2346
+ colorC: color("High", "#fdd835", "Peaks of the field."),
2347
+ },
2348
+ },
2349
+ pulsar: {
2350
+ name: "Pulsar",
2351
+ tagline: "A breathing globe of particles that leans toward your cursor",
2352
+ description: "A globe of bright points hanging in the dark, breathing, its surface boiling slowly with no seam anywhere while bands of light sweep its latitudes. The pointer is a gentle gravity: the globe drifts that way and stretches into a soft teardrop, brightest on the side being pulled.",
2353
+ family: "particles",
2354
+ tags: ["particles", "3d", "interactive", "pointer", "hero", "space"],
2355
+ cost: "heavy",
2356
+ controls: {
2357
+ ...base,
2358
+ speed: { ...base.speed, default: 0.66, max: 2 },
2359
+ scale: { ...base.scale, default: 0.92, min: 0.5, max: 1.6, hint: "Size of the globe in the frame." },
2360
+ intensity: { ...base.intensity, default: 0.7 },
2361
+ vibrancy: { ...base.vibrancy, default: 1.1 },
2362
+ vignette: { ...base.vignette, default: 0.48 },
2363
+ warp: {
2364
+ ...warp,
2365
+ label: "Pull",
2366
+ min: 0,
2367
+ max: 2,
2368
+ default: 0.37,
2369
+ hint: "How strongly the globe leans toward your cursor. 0 lets it rest.",
2370
+ },
2371
+ bands: {
2372
+ slot: "a",
2373
+ label: "Bands",
2374
+ min: 0,
2375
+ max: 2,
2376
+ step: 0.01,
2377
+ default: 0.45,
2378
+ hint: "How many streaks of light sweep the latitudes.",
2379
+ },
2380
+ relief: {
2381
+ slot: "b",
2382
+ label: "Relief",
2383
+ min: 0,
2384
+ max: 2,
2385
+ step: 0.01,
2386
+ default: 1.18,
2387
+ hint: "The boiling surface. 0 is a perfect sphere.",
2388
+ },
2389
+ breath: {
2390
+ slot: "c",
2391
+ label: "Breath",
2392
+ min: 0,
2393
+ max: 2,
2394
+ step: 0.01,
2395
+ default: 1.18,
2396
+ hint: "The swell and settle of the whole globe.",
2397
+ },
2398
+ spin: {
2399
+ slot: "d",
2400
+ label: "Spin",
2401
+ min: 0,
2402
+ max: 2,
2403
+ step: 0.01,
2404
+ default: 1.02,
2405
+ hint: "Rotation of the globe under the bands.",
2406
+ },
2407
+ },
2408
+ colors: {
2409
+ colorA: color("Void", "#08130c", "The dark the globe hangs in."),
2410
+ colorB: color("Surface", "#1e7a4a", "The body of the sphere."),
2411
+ colorC: color("Bands", "#d9ffe8", "The sweeping light, and the pulled side."),
2412
+ },
2413
+ presets: [
2414
+ { name: "Verdant", colorA: "#08130c", colorB: "#1e7a4a", colorC: "#d9ffe8" },
2415
+ { name: "Neutron", colorA: "#0b0d18", colorB: "#4a3d8f", colorC: "#c9e8ff" },
2416
+ { name: "Ember", colorA: "#160b08", colorB: "#8f3d1e", colorC: "#ffd9a3" },
2417
+ { name: "Signal", colorA: "#120812", colorB: "#8a2e7a", colorC: "#ffd0f5" },
2418
+ ],
2419
+ },
2081
2420
  glass: {
2082
2421
  name: "Glass",
2083
2422
  tagline: "A refracting, frosted sheet over the layer behind it",
2084
- description: "A drifting height field read as a surface: its slope bends the layer underneath, spreads the red and blue ends apart, and catches light along the steep ground. Frost blurs along an axis the height rotates, so the sheet grains up instead of banding. Point it at an image, a video, or another shadertown shader.",
2423
+ description: "A frosted, refracting sheet over whatever sits behind it. The layer bends along the slope of the glass, the red and blue ends pull apart, light catches along the steep ground, and the frost grains up instead of banding. Point it at an image, a video, or another shadertown shader.",
2085
2424
  family: "optical",
2086
2425
  tags: ["glass", "refraction", "overlay"],
2087
2426
  cost: "medium",
@@ -2139,7 +2478,7 @@ export const shaderRegistry = {
2139
2478
  lens: {
2140
2479
  name: "Lens",
2141
2480
  tagline: "Barrel distortion, colour fringing and soft corners",
2142
- description: "A camera lens rather than a filter: one radial distortion constant per colour channel, so straight lines bow outwards, the fringing is invisible in the middle and worst in the corners, and the corners lose both light and sharpness. Set distortion below zero for the pincushion a long lens gives you instead.",
2481
+ description: "What a real lens does to a picture: straight lines bow outwards, colour fringes appear in the corners and nowhere in the middle, and the corners lose both light and sharpness. Set distortion below zero for the pincushion a long lens gives you instead.",
2143
2482
  family: "optical",
2144
2483
  tags: ["camera", "distortion", "retro"],
2145
2484
  cost: "medium",
@@ -2201,7 +2540,7 @@ export const shaderRegistry = {
2201
2540
  bloom: {
2202
2541
  name: "Bloom",
2203
2542
  tagline: "Light bleeding out of the bright parts of the layer below",
2204
- description: "A threshold picks out what is already bright, and a wide spiral spreads it. Each tap is thresholded on its own rather than blurring first, so a dark neighbour never dims a highlight. Streak stretches the spiral sideways into the flare an anamorphic lens puts on every point of light.",
2543
+ description: "Light bleeding out of the bright parts of the layer below, spreading wide and keeping its colour, so a highlight glows rather than merely brightens. A dark neighbour never dims it. Streak stretches the glow sideways into the flare an anamorphic lens puts on every point of light.",
2205
2544
  family: "optical",
2206
2545
  tags: ["glow", "light", "hero"],
2207
2546
  cost: "heavy",
@@ -2263,7 +2602,7 @@ export const shaderRegistry = {
2263
2602
  shockwave: {
2264
2603
  name: "Shockwave",
2265
2604
  tagline: "Expanding rings that shove the layer aside as they pass",
2266
- description: "Three gaussian bands, staggered in phase and spending their force as they grow. The displacement is signed by which side of the crest a pixel is on, so the front compresses ahead of itself and rarefies behind — which is what makes it read as a wave rather than a glowing ring. Turn pointer tracking on and it starts wherever the cursor is.",
2605
+ description: "Rings expanding outward, shoving the layer aside as they pass and spending their force as they grow. The picture compresses ahead of each crest and pulls apart behind it, which is what makes it read as a wave rather than a glowing ring. Turn pointer tracking on and it starts wherever the cursor is.",
2267
2606
  family: "distortion",
2268
2607
  tags: ["impact", "pulse", "interactive"],
2269
2608
  cost: "medium",
@@ -2326,7 +2665,7 @@ export const shaderRegistry = {
2326
2665
  swirl: {
2327
2666
  name: "Swirl",
2328
2667
  tagline: "A vortex that winds the layer around a point",
2329
- description: "Rotation that falls off with distance, so the middle turns and the edges stay put. Falloff decides the whole character: near 1 it is a gentle whirlpool, near 4 a tight knot in still water. The colour channels wind by slightly different angles, which smears them along the direction of travel and sells the spin.",
2668
+ description: "A vortex that winds the layer around a point: the middle turns hard, the edges stay put. Near a falloff of one it is a gentle whirlpool, near four a tight knot in still water. The colours wind by slightly different angles, which smears them along the spin.",
2330
2669
  family: "distortion",
2331
2670
  tags: ["vortex", "twist", "interactive"],
2332
2671
  cost: "light",
@@ -2389,7 +2728,7 @@ export const shaderRegistry = {
2389
2728
  flow: {
2390
2729
  name: "Flow",
2391
2730
  tagline: "The layer pushed around by a slow, turbulent field",
2392
- description: "Two noise fields drive a displacement, then curl turns it from a drift into a circulation. Smearing runs along the flow rather than in a circle, so the result looks stirred instead of merely blurred. Turbulence trades broad lazy currents for stringy filaments.",
2731
+ description: "The layer stirred by a slow, turbulent current, smearing along the direction of travel rather than in place, so it looks mixed instead of merely blurred. Turbulence trades broad lazy currents for stringy filaments.",
2393
2732
  family: "distortion",
2394
2733
  tags: ["liquid", "organic", "ambient"],
2395
2734
  cost: "heavy",
@@ -2453,7 +2792,7 @@ export const shaderRegistry = {
2453
2792
  duotone: {
2454
2793
  name: "Duotone",
2455
2794
  tagline: "The layer's brightness read through your palette",
2456
- description: "Luminance is set between a black and a white point, then contrasted about the midpoint, then used to walk the three-stop palette. In that order: a hard contrast applied first would clip before the range is set. Keep colour mixes the original chroma back, for when a busy photograph should not become a flat poster.",
2795
+ description: "The layer's brightness read through your own palette: dark tones take the first colour, highlights the last, and the midtones walk between them. Keep colour mixes the original hues back in, for when a busy photograph should not become a flat poster.",
2457
2796
  family: "image",
2458
2797
  tags: ["colour", "poster", "brand"],
2459
2798
  cost: "light",
@@ -2507,7 +2846,7 @@ export const shaderRegistry = {
2507
2846
  edges: {
2508
2847
  name: "Edges",
2509
2848
  tagline: "The layer reduced to its outlines",
2510
- description: "A Sobel kernel over luminance, with the step widened past a single texel — a sub-texel step would just sample the same texel three times, and widening it is what turns a hairline into a drawn line. Fill decides how much of the original shows under the ink, from a clean line drawing to a traced photograph.",
2849
+ description: "The layer reduced to its outlines — drawn lines on a flat ground, thick enough to read at any size rather than hairlines that break up. Fill decides how much of the original shows under the ink, from a clean line drawing to a traced photograph.",
2511
2850
  family: "image",
2512
2851
  tags: ["outline", "line art", "technical"],
2513
2852
  cost: "medium",
@@ -2561,7 +2900,7 @@ export const shaderRegistry = {
2561
2900
  mosaic: {
2562
2901
  name: "Mosaic",
2563
2902
  tagline: "The layer rebuilt out of tiles",
2564
- description: "One tap at each tile's centre, not an average of it — the hard colour is the point, and averaging would only reinvent a blur. Posterising after sampling is what makes it look assembled from a limited set rather than merely coarse. Roundness grows a dot whose size follows the tile's brightness, the way a printed screen does.",
2903
+ description: "The layer rebuilt out of hard-edged tiles, each one a single flat colour from a cut-back palette, so it looks assembled from a limited set rather than merely coarse. Roundness turns the tiles into dots that grow with brightness, the way a printed screen does.",
2565
2904
  family: "image",
2566
2905
  tags: ["pixelate", "print", "retro"],
2567
2906
  cost: "light",
@@ -2615,7 +2954,7 @@ export const shaderRegistry = {
2615
2954
  reveal: {
2616
2955
  name: "Reveal",
2617
2956
  tagline: "The layer wiped in over a colour ground",
2618
- description: "A threshold cutting through a field: noise dissolves, a rotated ramp wipes, and shape slides between the two. At speed 0 the progress control is a scrubber you can drive from your own code — bind it to a scroll position or a load event. Above 0 it loops on its own, which is what makes it worth looking at on a card.",
2957
+ description: "The layer wiped in over a flat colour ground: noise dissolves it in speckles, a rotated ramp wipes it in a line, and shape slides between the two. At speed 0 the progress control is a scrubber you can drive from your own code; above 0 it loops on its own.",
2619
2958
  family: "transition",
2620
2959
  tags: ["wipe", "dissolve", "entrance"],
2621
2960
  cost: "light",
@@ -2679,7 +3018,7 @@ export const shaderRegistry = {
2679
3018
  "neon-sign": {
2680
3019
  name: "Neon Sign",
2681
3020
  tagline: "The layer's edges bent into glass tube and lit",
2682
- description: "The tube is the level set where the layer's luma crosses a threshold, which is why this works on anything but sings on text: a glyph's boundary is one clean crossing, and the band around it becomes the glass. The halo is the blurred luma itself rather than a blur of the tube, so the light lands where the ink is. Hand it `source={{ text: \"OPEN\" }}` and it is a sign.",
3021
+ description: "The layer's edges bent into glass tube and lit, with the halo landing where the ink is. It works on anything but sings on text, because a letter's boundary is one clean line and the band around it becomes the glass. Hand it `source={{ text: \"OPEN\" }}` and it is a sign.",
2683
3022
  family: "optical",
2684
3023
  tags: ["text", "neon", "dark", "sign"],
2685
3024
  cost: "heavy",
@@ -2743,7 +3082,7 @@ export const shaderRegistry = {
2743
3082
  ascii: {
2744
3083
  name: "ASCII",
2745
3084
  tagline: "The layer redrawn as a density ramp of glyphs",
2746
- description: "Ten 3×5 bitmaps packed into ten integers, ordered by how much ink they carry, so brightness picks the character the way the classic ramp does. The font ships inside the shader — a vendored copy runs with no assets at all. Colorize slides between pure phosphor and the source's own colour pushed through the glyphs; scan adds the monitor the font implies.",
3085
+ description: "The layer redrawn as a grid of glyphs, dense characters where the picture is bright and open ones where it is dark. The font travels inside the shader, so it runs with no assets at all. Colorize slides between pure phosphor and the source's own colour pushed through the glyphs; scan adds the monitor the font implies.",
2747
3086
  family: "image",
2748
3087
  tags: ["text", "retro", "terminal"],
2749
3088
  cost: "light",
@@ -2799,7 +3138,7 @@ export const shaderRegistry = {
2799
3138
  shatter: {
2800
3139
  name: "Shatter",
2801
3140
  tagline: "The layer breaks into shards that fly from the pointer",
2802
- description: "A voronoi partition where the shards hold still and their contents move: each cell samples the source from a position swung back toward the impact point, so the picture inside every shard slides and rotates away from the cursor while the crack pattern stays fixed. At speed 0 the progress slider is a scrubber, same contract as reveal — bind it to a scroll position and the break happens under the reader's thumb.",
3141
+ description: "The layer breaks into shards that fly away from the pointer. The crack pattern holds still while the picture inside each shard slides and turns outward. At speed 0 the progress slider is a scrubber, the same contract as reveal, so the break can happen under the reader's thumb.",
2803
3142
  family: "distortion",
2804
3143
  tags: ["interactive", "pointer", "text", "transition"],
2805
3144
  cost: "medium",
@@ -2863,7 +3202,7 @@ export const shaderRegistry = {
2863
3202
  melt: {
2864
3203
  name: "Melt",
2865
3204
  tagline: "The layer runs downhill, and the pointer is the heat",
2866
- description: "A melting pixel shows what used to be above it, so the whole effect is sampling the source at a smaller y. How much smaller is a column-coherent noise — coherent down each column, varied across them — which is what makes drips instead of fog. The streak pass keeps the brightest tap of the climb, the way a run of paint carries its highlight down with it. The pointer is a blowtorch: hold it on text and the text sags.",
3205
+ description: "The layer runs downhill in drips, each column dragging its own streak of colour down and carrying the highlight at the front of the run. The pointer is the heat: hold it on text and the text sags.",
2867
3206
  family: "distortion",
2868
3207
  tags: ["interactive", "pointer", "text"],
2869
3208
  cost: "medium",
@@ -2927,7 +3266,7 @@ export const shaderRegistry = {
2927
3266
  "pixel-sea": {
2928
3267
  name: "Pixel Sea",
2929
3268
  tagline: "A 16-bit sea: dithered sky, low sun, dashes of light",
2930
- description: "A proper seascape on a virtual pixel grid: horizon in the upper third, perspective rows that pack tighter as they recede, and the sun's reflection breaking into dashes on the swell. The clock ticks at a sprite-sheet rate, so nothing ever moves by less than a whole cell.",
3269
+ description: "A 16-bit seascape: a dithered sky over a low sun, rows of water packing tighter as they recede, and the sun's reflection breaking into dashes on the swell. Nothing ever moves by less than a whole pixel.",
2931
3270
  family: "pixel",
2932
3271
  tags: ["pixel", "retro", "water", "game"],
2933
3272
  cost: "light",
@@ -2988,7 +3327,7 @@ export const shaderRegistry = {
2988
3327
  "pixel-clouds": {
2989
3328
  name: "Pixel Clouds",
2990
3329
  tagline: "Sprite clouds on a flat blue sky",
2991
- description: "Each cloud is a drawn sprite, not a thresholded noise field: a flat-bottomed slab with hashed bumps stacked on top, the way a pixel artist builds one. Rows drift at their own whole-cell speeds, and one rule does the shading — open air below a cell means it takes the shade stop.",
3330
+ description: "Flat-bottomed pixel clouds drifting across a plain blue sky, each one a stack of round bumps of uneven size with a hard shade line underneath, the way a pixel artist builds one. The rows drift at their own speeds, a whole cell at a time.",
2992
3331
  family: "pixel",
2993
3332
  tags: ["pixel", "retro", "sky", "calm"],
2994
3333
  cost: "light",
@@ -3050,8 +3389,8 @@ export const shaderRegistry = {
3050
3389
  },
3051
3390
  "pixel-fire": {
3052
3391
  name: "Pixel Fire",
3053
- tagline: "The Doom fire, computed without its memory",
3054
- description: "The 1996 original was a feedback automaton; one pass has no history, so this reproduces its statistics instead: a heat ramp from the bottom edge, turbulence that grows with height so the slab shreds into tongues, and per-cell decay jitter re-rolled at a low frame rate — the flicker that made the automaton read as fire.",
3392
+ tagline: "The Doom fire, tongue by tongue",
3393
+ description: "The Doom fire: a bed of orange along the bottom edge shredding upward into tongues and sparks, and going black before the top. Every cell is one of a dozen flat colours, and the whole slab flickers on a low frame rate.",
3055
3394
  family: "pixel",
3056
3395
  tags: ["pixel", "retro", "fire", "dark"],
3057
3396
  cost: "medium",
@@ -3112,7 +3451,7 @@ export const shaderRegistry = {
3112
3451
  "pixel-rain": {
3113
3452
  name: "Pixel Rain",
3114
3453
  tagline: "Rain over a sleeping skyline, one lit window at a time",
3115
- description: "Two ranks of hashed buildings under three flat bands of night sky, a sparse lattice of windows whose lights toggle rarely, and per-column raindrops that fall by whole cells per tick onto a shimmering street. Nothing is blended; every pixel is one of a dozen stops.",
3454
+ description: "Rain over a sleeping pixel skyline: two ranks of buildings under flat bands of night sky and a moon, a sparse grid of windows whose lights toggle rarely, and drops falling a whole cell at a time onto a shimmering street. Nothing is blended; every pixel is one of a dozen stops.",
3116
3455
  family: "pixel",
3117
3456
  tags: ["pixel", "retro", "rain", "dark", "city"],
3118
3457
  cost: "light",
@@ -3172,7 +3511,7 @@ export const shaderRegistry = {
3172
3511
  lagoon: {
3173
3512
  name: "Lagoon",
3174
3513
  tagline: "An atoll from above: sand ring, shallows, the reef wall",
3175
- description: "Depth does the colouring, the way light actually dies in water: red first, so the shallows are sand seen through cyan and the open sea keeps only blue. The ring wobbles per angle and opens channels, surf stacks against the reef, and coral heads mottle the lagoon floor.",
3514
+ description: "An atoll from above: a sand ring around a pale turquoise lagoon, dropping to deep blue outside the reef. Depth does the colouring the way light actually dies in water, so the shallows read as sand seen through cyan and the open sea keeps only blue. Surf stacks against the reef and coral mottles the floor.",
3176
3515
  family: "scene",
3177
3516
  tags: ["island", "water", "tropical", "ambient"],
3178
3517
  cost: "medium",
@@ -3234,7 +3573,7 @@ export const shaderRegistry = {
3234
3573
  island: {
3235
3574
  name: "Island",
3236
3575
  tagline: "Sea to the horizon, a low sun, and land in the haze",
3237
- description: "No marching: the sea is a gradient, the island a one-dimensional ridge thresholded against height, and the sun's glitter an anisotropic sparkle — horizontally tight, vertically smeared, widening toward the camera — under a gaussian column below the sun. The pointer leans the whole view.",
3576
+ description: "Sea to the horizon under a low sun, a glitter path running toward the camera, and land sitting in the haze. The glitter is tight across and smeared down, and it widens as it comes nearer. The pointer leans the whole view.",
3238
3577
  family: "scene",
3239
3578
  tags: ["island", "hero", "horizon", "pointer"],
3240
3579
  cost: "light",
@@ -3295,7 +3634,7 @@ export const shaderRegistry = {
3295
3634
  shore: {
3296
3635
  name: "Shore",
3297
3636
  tagline: "The swash zone from above: run-up, foam, wet sand",
3298
- description: "One animated line drives everything: the waterline breathes on a cosine and is ragged from noise, wave fronts arrive as sharp crests with decaying wakes, and the wet sand is a second envelope lagging behind the water — darkest at the edge, drying to nothing — which is as close to memory as one pass gets.",
3637
+ description: "The swash zone from above: bands of turquoise water running up over pale sand, foam along each front, and wet sand that is darkest at the waterline and dries to nothing behind it. The waterline breathes in and out and stays ragged.",
3299
3638
  family: "scene",
3300
3639
  tags: ["island", "water", "calm", "ambient"],
3301
3640
  cost: "medium",
@@ -3357,7 +3696,7 @@ export const shaderRegistry = {
3357
3696
  caldera: {
3358
3697
  name: "Caldera",
3359
3698
  tagline: "A volcanic island at night, lit by its own veins",
3360
- description: "The island is fbm minus a falloff, but the light source is inside it: the valleys of a ridged field read as lava where they run downhill from the crater, the crater itself is a breathing pool, and everything else — basalt, sea, the drifting embers — is lit by that glow.",
3699
+ description: "A volcanic island at night, lit by its own lava. Glowing veins run downhill from a breathing crater pool, and the basalt, the sea and the drifting embers take their only light from that glow.",
3361
3700
  family: "scene",
3362
3701
  tags: ["island", "dark", "hero", "fire"],
3363
3702
  cost: "medium",
@@ -3420,8 +3759,8 @@ export const shaderRegistry = {
3420
3759
  },
3421
3760
  meadow: {
3422
3761
  name: "Meadow",
3423
- tagline: "A flower field in parallax layers, blurred like a lens",
3424
- description: "A silhouette field at golden hour: four rows of grass and flowers, each one flat tone against the glowing sky, the nearest nearly ink. Rows slide by their own parallax under the pointer, and rows off the focal plane widen their antialiasing band — which at header size reads as lens blur.",
3762
+ tagline: "A flower field in silhouette at golden hour",
3763
+ description: "A flower field at golden hour, drawn as flat silhouettes in rows — the nearest almost ink, the farthest almost sky. The rows slide past each other under the pointer, and the ones off the focal plane soften as if the lens missed them.",
3425
3764
  family: "scene",
3426
3765
  tags: ["hero", "flowers", "soft", "pointer"],
3427
3766
  cost: "medium",
@@ -3481,8 +3820,8 @@ export const shaderRegistry = {
3481
3820
  },
3482
3821
  blossom: {
3483
3822
  name: "Blossom",
3484
- tagline: "One flower, drawn large enough to be the header",
3485
- description: "Two rings of rose-curve petals, the inner rotated half a sector and darkened, around a true phyllotaxis seed head: florets at the golden angle, each given a domed normal so the head shades like geometry without a ray marched. The whole flower breathes and leans.",
3823
+ tagline: "One flower, drawn large",
3824
+ description: "One flower, drawn large: two rings of pale petals, the inner ring turned and darkened, around a dark seed head packed in the tight spiral a real flower grows. The whole flower breathes and leans.",
3486
3825
  family: "scene",
3487
3826
  tags: ["hero", "flowers", "centerpiece", "calm"],
3488
3827
  cost: "light",
@@ -3542,8 +3881,8 @@ export const shaderRegistry = {
3542
3881
  },
3543
3882
  hills: {
3544
3883
  name: "Hills",
3545
- tagline: "Rolling grassland marched as a heightfield",
3546
- description: "The march reads four octaves of terrain and the shading reads six — nobody can see the difference, and it halves the loop. Three lights do the rest: a wrapped sun, a hemispheric sky fill, and a warm bounce from the opposite side, with sun-tinted fog folding the far hills into the sky.",
3884
+ tagline: "Rolling grassland under a low sun",
3885
+ description: "Rolling green grassland under a wide sky, lit by a low sun with a cool fill from above and a warm bounce off the far side. Sun-tinted fog folds the distant hills into the sky.",
3547
3886
  family: "scene",
3548
3887
  tags: ["hero", "3d", "raymarching", "pointer"],
3549
3888
  cost: "heavy",