@pixerate/flair 0.16.0 → 0.18.0
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/CHANGELOG.md +22 -0
- package/README.md +38 -7
- package/dist/catalog/index.d.ts +8 -4
- package/dist/catalog/index.js +8 -2
- package/dist/{chunk-YLJWC4N2.js → chunk-HA6FIMH2.js} +108 -5
- package/dist/chunk-HA6FIMH2.js.map +1 -0
- package/dist/{chunk-UNLCGDCB.js → chunk-HP7CYHS5.js} +46 -11
- package/dist/chunk-HP7CYHS5.js.map +1 -0
- package/dist/{chunk-DVVQRZJ5.js → chunk-MILF5MRS.js} +11 -2
- package/dist/chunk-MILF5MRS.js.map +1 -0
- package/dist/{chunk-4RGHZWQC.js → chunk-RM3I6WZH.js} +2 -2
- package/dist/{chunk-4RGHZWQC.js.map → chunk-RM3I6WZH.js.map} +1 -1
- package/dist/{chunk-KWNFZ5NC.js → chunk-UI5X4D63.js} +292 -185
- package/dist/chunk-UI5X4D63.js.map +1 -0
- package/dist/{chunk-FIJOMGPG.js → chunk-UP6QQVRS.js} +2 -2
- package/dist/{chunk-WC3VADZC.js → chunk-VYOMXE6I.js} +46 -4
- package/dist/chunk-VYOMXE6I.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/{controls-Syr6drzO.d.ts → controls-Ec6P0Vpy.d.ts} +9 -2
- package/dist/editor/index.d.ts +3 -3
- package/dist/editor/index.js +20 -6
- package/dist/editor/index.js.map +1 -1
- package/dist/index.d.ts +19 -7
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/react/index.d.ts +14 -3
- package/dist/react/index.js +18 -9
- package/dist/react/index.js.map +1 -1
- package/dist/recorder-HKFFHQES.js +10 -0
- package/dist/{renderer-SNYZu__R.d.ts → renderer-Cn4_d5Qs.d.ts} +64 -8
- package/dist/svelte/index.d.ts +16 -5
- package/dist/svelte/index.js +16 -11
- package/dist/svelte/index.js.map +1 -1
- package/dist/{types-9J6NWaN3.d.ts → types-kAFjaq2N.d.ts} +28 -3
- package/dist/vector/index.d.ts +27 -1
- package/dist/vector/index.js +4 -2
- package/package.json +1 -1
- package/dist/chunk-DVVQRZJ5.js.map +0 -1
- package/dist/chunk-KWNFZ5NC.js.map +0 -1
- package/dist/chunk-UNLCGDCB.js.map +0 -1
- package/dist/chunk-WC3VADZC.js.map +0 -1
- package/dist/chunk-YLJWC4N2.js.map +0 -1
- package/dist/recorder-KEX3U35D.js +0 -10
- /package/dist/{chunk-FIJOMGPG.js.map → chunk-UP6QQVRS.js.map} +0 -0
- /package/dist/{recorder-KEX3U35D.js.map → recorder-HKFFHQES.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
hexToRgb,
|
|
13
13
|
parseControls,
|
|
14
14
|
rgbToHex
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-VYOMXE6I.js";
|
|
16
16
|
|
|
17
17
|
// src/catalog/glsl.ts
|
|
18
18
|
var HASH = `
|
|
@@ -390,6 +390,7 @@ var imageRipple = {
|
|
|
390
390
|
name: "Ripple",
|
|
391
391
|
description: "An image rippling as if seen through water, from the pointer or the centre.",
|
|
392
392
|
category: "image",
|
|
393
|
+
video: "filter",
|
|
393
394
|
tags: ["image", "water", "interactive", "distortion"],
|
|
394
395
|
source: glsl(
|
|
395
396
|
`// Ripple: an image rippling as if under water.
|
|
@@ -419,6 +420,7 @@ var imageGlitch = {
|
|
|
419
420
|
name: "Glitch",
|
|
420
421
|
description: "Digital glitch on an image: RGB split, slice displacement and blocky corruption in bursts.",
|
|
421
422
|
category: "image",
|
|
423
|
+
video: "filter",
|
|
422
424
|
tags: ["image", "glitch", "cyber", "transition"],
|
|
423
425
|
source: glsl(
|
|
424
426
|
`// Glitch: RGB split, slice displacement and blocky corruption in bursts.
|
|
@@ -456,6 +458,7 @@ var imageDuotone = {
|
|
|
456
458
|
name: "Duotone",
|
|
457
459
|
description: "An image mapped onto two colours, with a slow light sweep.",
|
|
458
460
|
category: "image",
|
|
461
|
+
video: "filter",
|
|
459
462
|
tags: ["image", "brand", "editorial", "colour"],
|
|
460
463
|
source: glsl(
|
|
461
464
|
`// Duotone: an image mapped onto two colours, with a light sweep.
|
|
@@ -487,6 +490,7 @@ var imagePixelate = {
|
|
|
487
490
|
name: "Pixel reveal",
|
|
488
491
|
description: "An image resolving from big blocks to full detail, then back, in a loop.",
|
|
489
492
|
category: "image",
|
|
493
|
+
video: "filter",
|
|
490
494
|
tags: ["image", "reveal", "transition", "8-bit"],
|
|
491
495
|
loop: 4,
|
|
492
496
|
source: glsl(
|
|
@@ -511,6 +515,7 @@ var imageHalftone = {
|
|
|
511
515
|
name: "Halftone",
|
|
512
516
|
description: "An image printed as rotated halftone dots, breathing slightly.",
|
|
513
517
|
category: "image",
|
|
518
|
+
video: "filter",
|
|
514
519
|
tags: ["image", "print", "comic", "pop-art"],
|
|
515
520
|
source: glsl(
|
|
516
521
|
`// Halftone: an image as rotated print dots.
|
|
@@ -542,6 +547,7 @@ var crt = {
|
|
|
542
547
|
name: "CRT screen",
|
|
543
548
|
description: "An image on a curved CRT: scanlines, shadow mask, bloom and flicker.",
|
|
544
549
|
category: "image",
|
|
550
|
+
video: "filter",
|
|
545
551
|
tags: ["image", "retro", "screen", "arcade"],
|
|
546
552
|
source: glsl(
|
|
547
553
|
`// CRT screen: an image on a curved tube with scanlines and a shadow mask.
|
|
@@ -580,6 +586,7 @@ var filmGrain = {
|
|
|
580
586
|
name: "Film look",
|
|
581
587
|
description: "An image graded like film: grain, gate weave, halation and vignette.",
|
|
582
588
|
category: "image",
|
|
589
|
+
video: "filter",
|
|
583
590
|
tags: ["image", "cinematic", "grain", "vintage"],
|
|
584
591
|
source: glsl(
|
|
585
592
|
`// Film look: grain, gate weave, halation and vignette.
|
|
@@ -626,6 +633,7 @@ var transitions = TRANSITIONS.map(({ type, id, name, description }) => ({
|
|
|
626
633
|
name,
|
|
627
634
|
description: `${description} Loops back and forth; or turn Animate off and set Progress.`,
|
|
628
635
|
category: "transition",
|
|
636
|
+
video: "transition",
|
|
629
637
|
tags: ["transition", "image", "slideshow"],
|
|
630
638
|
loop: 4,
|
|
631
639
|
source: glsl(
|
|
@@ -1748,9 +1756,9 @@ var checkFlash = (at2, back) => [
|
|
|
1748
1756
|
{ id: "check", step: 1, attrs: { opacity: [1, 0] }, delay: back, ms: 160 },
|
|
1749
1757
|
{ id: "check", step: 1, draw: [0, 0], delay: back + 200, ms: 0 }
|
|
1750
1758
|
];
|
|
1751
|
-
var buttonLabels = (a, b,
|
|
1759
|
+
var buttonLabels = (a, b, room2, max) => {
|
|
1752
1760
|
const ems = [a, b].map((t) => Math.max(0.6, textWidthEm(String(t))));
|
|
1753
|
-
const size = Math.min(max,
|
|
1761
|
+
const size = Math.min(max, room2 / Math.max(...ems));
|
|
1754
1762
|
return { size: r1(size), base: r1(50 + size * 0.35), labelLen: r1(ems[0] * size), doneLen: r1(ems[1] * size) };
|
|
1755
1763
|
};
|
|
1756
1764
|
var labelTexts = (x) => `<text id="label" x="${x}" y="{{base}}" textLength="{{labelLen}}" lengthAdjust="spacingAndGlyphs" transform="translate(0 0)" font-family="${SANS}" font-size="{{size}}" font-weight="600" fill="{{ink}}">{{label}}</text><text id="done" x="${x}" y="{{base}}" textLength="{{doneLen}}" lengthAdjust="spacingAndGlyphs" transform="translate(0 10)" opacity="0" font-family="${SANS}" font-size="{{size}}" font-weight="600" fill="{{ink}}">{{doneText}}</text>`;
|
|
@@ -2452,6 +2460,7 @@ var image8bit = {
|
|
|
2452
2460
|
name: "8-bit",
|
|
2453
2461
|
description: "An image on a chunky pixel grid, reduced to a classic console or computer palette with ordered Bayer dithering.",
|
|
2454
2462
|
category: "retro",
|
|
2463
|
+
video: "filter",
|
|
2455
2464
|
tags: ["pixel", "retro", "image", "8-bit", "dither", "palette", "game boy", "pico-8"],
|
|
2456
2465
|
source: glsl(
|
|
2457
2466
|
`// 8-bit: an image on a chunky pixel grid in a classic palette, Bayer-dithered.
|
|
@@ -2527,6 +2536,7 @@ var gameboyScreen = {
|
|
|
2527
2536
|
name: "Game Boy screen",
|
|
2528
2537
|
description: "An image on a handheld's green dot-matrix LCD: four shades, a visible pixel grid and smeary ghosting, inset in an olive bezel.",
|
|
2529
2538
|
category: "retro",
|
|
2539
|
+
video: "filter",
|
|
2530
2540
|
tags: ["pixel", "retro", "image", "game boy", "lcd", "handheld", "screen"],
|
|
2531
2541
|
source: glsl(
|
|
2532
2542
|
`// Game Boy screen: an image on a 4-shade green LCD with a pixel grid, ghosting and a bezel.
|
|
@@ -2969,6 +2979,7 @@ var rasterBars = {
|
|
|
2969
2979
|
name: "Raster bars",
|
|
2970
2980
|
description: "Demoscene copper bars bouncing on sine paths behind a sine-scrolling greeting, all in chunky pixels.",
|
|
2971
2981
|
category: "retro",
|
|
2982
|
+
video: "none",
|
|
2972
2983
|
tags: ["pixel", "retro", "demoscene", "amiga", "c64", "scroller", "text", "copper"],
|
|
2973
2984
|
source: glsl(
|
|
2974
2985
|
`// Raster bars: copper bars on sine paths behind a sine scroller.
|
|
@@ -3154,6 +3165,7 @@ var pixelDissolve = {
|
|
|
3154
3165
|
name: "Pixel dissolve",
|
|
3155
3166
|
description: "The picture pixelates up to big blocks, the blocks swap to the next image in a random order, then it resolves into the new picture. Loops back and forth; or turn Animate off and set Progress.",
|
|
3156
3167
|
category: "transition",
|
|
3168
|
+
video: "transition",
|
|
3157
3169
|
tags: ["transition", "pixel", "image", "retro", "8-bit", "slideshow"],
|
|
3158
3170
|
loop: 4,
|
|
3159
3171
|
source: glsl(
|
|
@@ -4215,6 +4227,7 @@ var hoverLiquid = {
|
|
|
4215
4227
|
name: "Liquid hover",
|
|
4216
4228
|
description: "An image that swells and ripples like liquid around the pointer while it hovers.",
|
|
4217
4229
|
category: "interaction",
|
|
4230
|
+
video: "interactive",
|
|
4218
4231
|
tags: ["interactive", "hover", "image", "liquid", "distortion"],
|
|
4219
4232
|
source: glsl(
|
|
4220
4233
|
`// Liquid hover: an image bulging and rippling around the pointer, as strongly as it is hovered.
|
|
@@ -4261,6 +4274,7 @@ var hoverReveal = {
|
|
|
4261
4274
|
name: "X-ray reveal",
|
|
4262
4275
|
description: "A second image showing through a soft lens around the pointer that grows as it hovers and pulses on click.",
|
|
4263
4276
|
category: "interaction",
|
|
4277
|
+
video: "interactive",
|
|
4264
4278
|
tags: ["interactive", "hover", "click", "image", "reveal", "x-ray"],
|
|
4265
4279
|
source: glsl(
|
|
4266
4280
|
`// X-ray reveal: a second image seen through a soft lens at the pointer.
|
|
@@ -4312,6 +4326,7 @@ var magnifier = {
|
|
|
4312
4326
|
name: "Magnifier",
|
|
4313
4327
|
description: "A round magnifying glass over an image at the pointer, with a bright rim and a fringe of colour at its edge.",
|
|
4314
4328
|
category: "interaction",
|
|
4329
|
+
video: "interactive",
|
|
4315
4330
|
tags: ["interactive", "hover", "image", "lens", "zoom"],
|
|
4316
4331
|
source: glsl(
|
|
4317
4332
|
`// Magnifier: a round lens over an image at the pointer, showing while hovered.
|
|
@@ -4366,6 +4381,7 @@ var holoCard = {
|
|
|
4366
4381
|
name: "Holo card",
|
|
4367
4382
|
description: "A holographic foil trading card whose rainbow sheen and glare shift as the pointer tilts it.",
|
|
4368
4383
|
category: "interaction",
|
|
4384
|
+
video: "interactive",
|
|
4369
4385
|
tags: ["interactive", "hover", "card", "holographic", "foil", "iridescent"],
|
|
4370
4386
|
transparent: true,
|
|
4371
4387
|
source: glsl(
|
|
@@ -4520,6 +4536,7 @@ var hoverSwap = {
|
|
|
4520
4536
|
name: "Hover swap",
|
|
4521
4537
|
description: "One image burning away into another from the pointer as it hovers, along a glowing ragged edge.",
|
|
4522
4538
|
category: "interaction",
|
|
4539
|
+
video: "interactive",
|
|
4523
4540
|
tags: ["interactive", "hover", "image", "dissolve", "transition"],
|
|
4524
4541
|
source: glsl(
|
|
4525
4542
|
`// Hover swap: image A dissolves into image B as hover goes 0 \u2192 1, spreading from the pointer.
|
|
@@ -5044,6 +5061,7 @@ var electricText = {
|
|
|
5044
5061
|
name: "Electric text",
|
|
5045
5062
|
description: "A word with electricity crawling over its outlines and arcs leaping between its letters, flickering on a dark background.",
|
|
5046
5063
|
category: "electric",
|
|
5064
|
+
video: "none",
|
|
5047
5065
|
tags: ["electric", "text", "title", "glow", "sci-fi"],
|
|
5048
5066
|
source: glsl(
|
|
5049
5067
|
`// Electric text: electricity crawling along the letters' outlines, arcs jumping between them.
|
|
@@ -5306,6 +5324,7 @@ var powerSurge = {
|
|
|
5306
5324
|
name: "Power surge",
|
|
5307
5325
|
description: "A picture jolted by a power surge: a flash, an arc tearing across, scanlines and colour split, then a brownout before it settles.",
|
|
5308
5326
|
category: "electric",
|
|
5327
|
+
video: "filter",
|
|
5309
5328
|
tags: ["electric", "image", "glitch", "surge", "flash"],
|
|
5310
5329
|
source: glsl(
|
|
5311
5330
|
`// Power surge: an image jolted by a surge, then settling, on a schedule.
|
|
@@ -5487,6 +5506,7 @@ var dripMelt = {
|
|
|
5487
5506
|
name: "Drip melt",
|
|
5488
5507
|
description: "An image melting from the top edge down: columns slump, thick glossy drips run down and pool in a puddle, then it all reforms.",
|
|
5489
5508
|
category: "melt",
|
|
5509
|
+
video: "filter",
|
|
5490
5510
|
tags: ["melt", "image", "drip", "liquid", "glossy", "loop"],
|
|
5491
5511
|
loop: 8,
|
|
5492
5512
|
source: glsl(
|
|
@@ -5595,6 +5615,7 @@ var heatHaze = {
|
|
|
5595
5615
|
name: "Heat haze",
|
|
5596
5616
|
description: "A mirage shimmer rising off a hot image: wavering refraction strongest near the ground, with a warm tint and a faint reflection.",
|
|
5597
5617
|
category: "melt",
|
|
5618
|
+
video: "filter",
|
|
5598
5619
|
tags: ["melt", "image", "heat", "mirage", "shimmer", "desert", "distortion"],
|
|
5599
5620
|
source: glsl(
|
|
5600
5621
|
`// Heat haze: rising, wavering refraction over a picture, strongest near the bottom.
|
|
@@ -5654,6 +5675,7 @@ var waxMelt = {
|
|
|
5654
5675
|
name: "Wax melt",
|
|
5655
5676
|
description: "A silhouette softening like warm wax: its edges round off, its top sags and it slumps into a glossy puddle, then sets again.",
|
|
5656
5677
|
category: "melt",
|
|
5678
|
+
video: "none",
|
|
5657
5679
|
tags: ["melt", "wax", "text", "silhouette", "glossy", "loop"],
|
|
5658
5680
|
loop: 8,
|
|
5659
5681
|
source: glsl(
|
|
@@ -5754,6 +5776,7 @@ var meltingText = {
|
|
|
5754
5776
|
name: "Melting text",
|
|
5755
5777
|
description: "Letters sagging and stretching downwards as long glossy drips run from their bottoms and droplets break off and fall.",
|
|
5756
5778
|
category: "melt",
|
|
5779
|
+
video: "none",
|
|
5757
5780
|
tags: ["melt", "text", "title", "drip", "liquid", "glossy", "loop"],
|
|
5758
5781
|
loop: 8,
|
|
5759
5782
|
transparent: true,
|
|
@@ -5871,6 +5894,7 @@ var liquify = {
|
|
|
5871
5894
|
name: "Liquify",
|
|
5872
5895
|
description: "An image pushed and smeared like wet paint by a moving brush (or the pointer), the smears slowly relaxing back.",
|
|
5873
5896
|
category: "melt",
|
|
5897
|
+
video: "filter",
|
|
5874
5898
|
tags: ["melt", "image", "liquify", "smear", "paint", "interactive", "hover"],
|
|
5875
5899
|
source: glsl(
|
|
5876
5900
|
`// Liquify: a brush pushes the picture around; its recent path leaves smears that relax over time.
|
|
@@ -6946,6 +6970,7 @@ var timeEcho = {
|
|
|
6946
6970
|
name: "Time echo",
|
|
6947
6971
|
description: "A swaying picture trailed by fading, tinted ghost echoes of where it just was.",
|
|
6948
6972
|
category: "timewarp",
|
|
6973
|
+
video: "stills",
|
|
6949
6974
|
tags: ["time", "image", "echo", "trail", "ghost"],
|
|
6950
6975
|
loop: 8,
|
|
6951
6976
|
source: glsl(
|
|
@@ -6993,6 +7018,7 @@ var chronoSplit = {
|
|
|
6993
7018
|
name: "Chrono split",
|
|
6994
7019
|
description: "Red, green and blue each lagging a little further behind in time, so movement leaves colour fringes.",
|
|
6995
7020
|
category: "timewarp",
|
|
7021
|
+
video: "stills",
|
|
6996
7022
|
tags: ["time", "image", "rgb", "chromatic", "echo"],
|
|
6997
7023
|
loop: 8,
|
|
6998
7024
|
source: glsl(
|
|
@@ -7026,6 +7052,7 @@ var timeSlice = {
|
|
|
7026
7052
|
name: "Time slice",
|
|
7027
7053
|
description: "Bands of a moving picture each showing a different moment, staggered like a time-displacement.",
|
|
7028
7054
|
category: "timewarp",
|
|
7055
|
+
video: "stills",
|
|
7029
7056
|
tags: ["time", "image", "slices", "stagger", "displacement"],
|
|
7030
7057
|
loop: 8,
|
|
7031
7058
|
source: glsl(
|
|
@@ -7090,6 +7117,7 @@ var rewind = {
|
|
|
7090
7117
|
name: "VHS rewind",
|
|
7091
7118
|
description: "A tape playing, then rewinding fast with tracking noise, jittering lines, colour bleed and a \u25C0\u25C0 display.",
|
|
7092
7119
|
category: "timewarp",
|
|
7120
|
+
video: "stills",
|
|
7093
7121
|
tags: ["time", "image", "vhs", "retro", "rewind", "tape"],
|
|
7094
7122
|
loop: 6,
|
|
7095
7123
|
source: glsl(
|
|
@@ -7196,6 +7224,7 @@ var bulletTime = {
|
|
|
7196
7224
|
name: "Bullet time",
|
|
7197
7225
|
description: "A shockwave sweeping out from the centre or a click, freezing the picture grey and zoomed behind it while the rest moves on.",
|
|
7198
7226
|
category: "timewarp",
|
|
7227
|
+
video: "stills",
|
|
7199
7228
|
tags: ["time", "image", "freeze", "shockwave", "click", "cinematic"],
|
|
7200
7229
|
loop: 8,
|
|
7201
7230
|
source: glsl(
|
|
@@ -7255,6 +7284,7 @@ var timeTunnel = {
|
|
|
7255
7284
|
name: "Time tunnel",
|
|
7256
7285
|
description: "A picture wrapped round a spiralling tunnel rushing at the viewer, with light streaks and a blazing core.",
|
|
7257
7286
|
category: "timewarp",
|
|
7287
|
+
video: "filter",
|
|
7258
7288
|
tags: ["time", "image", "tunnel", "vortex", "sci-fi", "warp"],
|
|
7259
7289
|
loop: 8,
|
|
7260
7290
|
source: glsl(
|
|
@@ -7313,6 +7343,7 @@ var speedRamp = {
|
|
|
7313
7343
|
name: "Speed ramp",
|
|
7314
7344
|
description: "A panning picture lurching from a crawl to a blur and back, motion-blurred in proportion to its speed.",
|
|
7315
7345
|
category: "timewarp",
|
|
7346
|
+
video: "stills",
|
|
7316
7347
|
tags: ["time", "image", "speed", "motion blur", "cinematic"],
|
|
7317
7348
|
loop: 4,
|
|
7318
7349
|
source: glsl(
|
|
@@ -7360,6 +7391,7 @@ var stutterFreeze = {
|
|
|
7360
7391
|
name: "Stutter freeze",
|
|
7361
7392
|
description: "A moving picture that catches in irregular bursts, holding or stuttering frames with a flash on each freeze.",
|
|
7362
7393
|
category: "timewarp",
|
|
7394
|
+
video: "stills",
|
|
7363
7395
|
tags: ["time", "image", "freeze", "stutter", "glitch"],
|
|
7364
7396
|
source: glsl(
|
|
7365
7397
|
`// Stutter freeze: some moments end in a hold (or a skipping stutter) before cutting back to live.
|
|
@@ -7445,6 +7477,7 @@ var featureMorph = {
|
|
|
7445
7477
|
name: "Feature morph",
|
|
7446
7478
|
description: "The classic face morph: two pictures warp so five matching points (eyes, mouth, chin, hairline) meet while they cross-fade.",
|
|
7447
7479
|
category: "morph",
|
|
7480
|
+
video: "stills",
|
|
7448
7481
|
tags: ["morph", "face", "warp", "image", "transition"],
|
|
7449
7482
|
loop: 4,
|
|
7450
7483
|
source: glsl(
|
|
@@ -7543,6 +7576,7 @@ var silhouetteMorph = {
|
|
|
7543
7576
|
name: "Silhouette morph",
|
|
7544
7577
|
description: "One silhouette or logo flowing into another as a gooey blob, its colour blending from the first shape's to the second's.",
|
|
7545
7578
|
category: "morph",
|
|
7579
|
+
video: "stills",
|
|
7546
7580
|
tags: ["morph", "shape", "logo", "goo", "blob", "text"],
|
|
7547
7581
|
loop: 4,
|
|
7548
7582
|
source: glsl(
|
|
@@ -7623,6 +7657,7 @@ var transitionLiquidMorph = {
|
|
|
7623
7657
|
name: "Liquid morph",
|
|
7624
7658
|
description: "Both images swept along a flowing, swirling current that peaks half way, dissolving one into the other like ink in water.",
|
|
7625
7659
|
category: "transition",
|
|
7660
|
+
video: "transition",
|
|
7626
7661
|
tags: ["transition", "morph", "liquid", "image", "flow"],
|
|
7627
7662
|
loop: 4,
|
|
7628
7663
|
source: glsl(
|
|
@@ -7664,6 +7699,7 @@ var transitionDisplacement = {
|
|
|
7664
7699
|
name: "Displacement",
|
|
7665
7700
|
description: "Each image's brightness pushes it out in one direction as the next slides in, warped by its own light and dark.",
|
|
7666
7701
|
category: "transition",
|
|
7702
|
+
video: "transition",
|
|
7667
7703
|
tags: ["transition", "morph", "displacement", "image", "warp"],
|
|
7668
7704
|
loop: 4,
|
|
7669
7705
|
source: glsl(
|
|
@@ -7696,6 +7732,7 @@ var transitionLuma = {
|
|
|
7696
7732
|
name: "Luma fade",
|
|
7697
7733
|
description: "Pixels switch to the next image in order of brightness, shadows first or highlights first, along a soft edge.",
|
|
7698
7734
|
category: "transition",
|
|
7735
|
+
video: "transition",
|
|
7699
7736
|
tags: ["transition", "morph", "luma", "image", "dissolve"],
|
|
7700
7737
|
loop: 4,
|
|
7701
7738
|
source: glsl(
|
|
@@ -7730,6 +7767,7 @@ var transitionParticleSwap = {
|
|
|
7730
7767
|
name: "Particle swap",
|
|
7731
7768
|
description: "The image breaks into square particles that tumble along curved, staggered paths and land as the next image.",
|
|
7732
7769
|
category: "transition",
|
|
7770
|
+
video: "transition",
|
|
7733
7771
|
tags: ["transition", "morph", "particles", "image", "mosaic"],
|
|
7734
7772
|
loop: 4,
|
|
7735
7773
|
source: glsl(
|
|
@@ -7813,6 +7851,7 @@ var transitionInkBleed = {
|
|
|
7813
7851
|
name: "Ink bleed",
|
|
7814
7852
|
description: "The next image bleeds through the first like wet ink on paper, spreading from a few seeds with dark, pooled edges.",
|
|
7815
7853
|
category: "transition",
|
|
7854
|
+
video: "transition",
|
|
7816
7855
|
tags: ["transition", "morph", "ink", "watercolour", "image", "organic"],
|
|
7817
7856
|
loop: 4,
|
|
7818
7857
|
source: glsl(
|
|
@@ -8498,6 +8537,7 @@ var shaderText = {
|
|
|
8498
8537
|
name: "Shader text",
|
|
8499
8538
|
description: "A title filled with a living texture (plasma, fire, caustics or liquid chrome), with a soft glow and outline.",
|
|
8500
8539
|
category: "text",
|
|
8540
|
+
video: "none",
|
|
8501
8541
|
tags: ["text", "title", "plasma", "fire", "chrome", "glow"],
|
|
8502
8542
|
source: glsl(
|
|
8503
8543
|
`// Shader text: the letters of a text image filled with an animated pattern.
|
|
@@ -8601,6 +8641,7 @@ var imageKenBurns = {
|
|
|
8601
8641
|
name: "Ken Burns",
|
|
8602
8642
|
description: "A slow documentary-style pan and zoom across an image, easing in and out and back again.",
|
|
8603
8643
|
category: "image",
|
|
8644
|
+
video: "filter",
|
|
8604
8645
|
tags: ["image", "camera", "documentary", "slideshow"],
|
|
8605
8646
|
loop: 12,
|
|
8606
8647
|
source: glsl(
|
|
@@ -8641,6 +8682,7 @@ var imageAscii = {
|
|
|
8641
8682
|
name: "ASCII art",
|
|
8642
8683
|
description: "An image drawn as text characters picked by brightness, in one ink or the picture's own colours.",
|
|
8643
8684
|
category: "image",
|
|
8685
|
+
video: "filter",
|
|
8644
8686
|
tags: ["image", "ascii", "text", "terminal", "retro"],
|
|
8645
8687
|
source: glsl(
|
|
8646
8688
|
`// ASCII art: each cell of the image becomes a character, denser for brighter cells.
|
|
@@ -8700,6 +8742,7 @@ var imageShatter = {
|
|
|
8700
8742
|
name: "Shatter",
|
|
8701
8743
|
description: "An image breaking into glass-like shards that fly apart, spin and reassemble in a loop.",
|
|
8702
8744
|
category: "image",
|
|
8745
|
+
video: "filter",
|
|
8703
8746
|
tags: ["image", "shatter", "transition", "voronoi", "explode"],
|
|
8704
8747
|
loop: 5,
|
|
8705
8748
|
source: glsl(
|
|
@@ -8783,6 +8826,7 @@ var imageMelt = {
|
|
|
8783
8826
|
name: "Melt",
|
|
8784
8827
|
description: "An image melting and dripping downwards in slow, noisy runs.",
|
|
8785
8828
|
category: "image",
|
|
8829
|
+
video: "filter",
|
|
8786
8830
|
tags: ["image", "melt", "drip", "psychedelic", "distortion"],
|
|
8787
8831
|
source: glsl(
|
|
8788
8832
|
`// Melt: noise-driven runs drag the image downwards.
|
|
@@ -8821,6 +8865,7 @@ var imageRisograph = {
|
|
|
8821
8865
|
name: "Risograph",
|
|
8822
8866
|
description: "An image printed in two posterized, slightly misregistered inks on grainy paper.",
|
|
8823
8867
|
category: "image",
|
|
8868
|
+
video: "filter",
|
|
8824
8869
|
tags: ["image", "print", "riso", "editorial", "poster"],
|
|
8825
8870
|
source: glsl(
|
|
8826
8871
|
`// Risograph: two posterized ink layers, out of register, on grainy paper.
|
|
@@ -8871,6 +8916,7 @@ var imageThermal = {
|
|
|
8871
8916
|
name: "Thermal",
|
|
8872
8917
|
description: "An image seen through a heat camera or night-vision goggles.",
|
|
8873
8918
|
category: "image",
|
|
8919
|
+
video: "filter",
|
|
8874
8920
|
tags: ["image", "thermal", "night-vision", "surveillance", "colour"],
|
|
8875
8921
|
source: glsl(
|
|
8876
8922
|
`// Thermal: brightness mapped to a heat palette, or to green night-vision phosphor.
|
|
@@ -8924,6 +8970,7 @@ var imageEdgeGlow = {
|
|
|
8924
8970
|
name: "Edge glow",
|
|
8925
8971
|
description: "An image's edges traced as glowing neon lines over a dimmed picture, with a travelling pulse.",
|
|
8926
8972
|
category: "image",
|
|
8973
|
+
video: "filter",
|
|
8927
8974
|
tags: ["image", "neon", "edges", "outline", "cyber"],
|
|
8928
8975
|
loop: 2,
|
|
8929
8976
|
source: glsl(
|
|
@@ -8984,6 +9031,7 @@ var imageTiltShift = {
|
|
|
8984
9031
|
name: "Tilt-shift",
|
|
8985
9032
|
description: "An image blurred outside a sharp horizontal band, with punchy colour, so it looks like a miniature.",
|
|
8986
9033
|
category: "image",
|
|
9034
|
+
video: "filter",
|
|
8987
9035
|
tags: ["image", "blur", "miniature", "photography", "depth"],
|
|
8988
9036
|
source: glsl(
|
|
8989
9037
|
`// Tilt-shift: blur away from a focus band, plus saturation, for the miniature look.
|
|
@@ -9026,6 +9074,7 @@ var imageSlitScan = {
|
|
|
9026
9074
|
name: "Slit-scan",
|
|
9027
9075
|
description: "An image smeared into time-stretched streaks, like a slit-scan photograph.",
|
|
9028
9076
|
category: "image",
|
|
9077
|
+
video: "stills",
|
|
9029
9078
|
tags: ["image", "slit-scan", "smear", "experimental", "distortion"],
|
|
9030
9079
|
source: glsl(
|
|
9031
9080
|
`// Slit-scan: rows (or columns) squeeze towards a moving slit and smear into streaks.
|
|
@@ -9070,6 +9119,7 @@ var imageMosaic = {
|
|
|
9070
9119
|
name: "Mosaic flip",
|
|
9071
9120
|
description: "Hexagonal or triangular tiles flipping over from the left to reveal an image, then back.",
|
|
9072
9121
|
category: "image",
|
|
9122
|
+
video: "filter",
|
|
9073
9123
|
tags: ["image", "reveal", "transition", "tiles", "hexagon"],
|
|
9074
9124
|
loop: 6,
|
|
9075
9125
|
source: glsl(
|
|
@@ -9155,6 +9205,7 @@ var imageChromaticLens = {
|
|
|
9155
9205
|
name: "Chromatic lens",
|
|
9156
9206
|
description: "An image through a cheap wide lens: barrel distortion and colour fringes growing towards the edges.",
|
|
9157
9207
|
category: "image",
|
|
9208
|
+
video: "filter",
|
|
9158
9209
|
tags: ["image", "lens", "aberration", "distortion", "vintage"],
|
|
9159
9210
|
source: glsl(
|
|
9160
9211
|
`// Chromatic lens: barrel distortion with red, green and blue bent by different amounts.
|
|
@@ -9195,6 +9246,7 @@ var imageOilPaint = {
|
|
|
9195
9246
|
name: "Oil paint",
|
|
9196
9247
|
description: "An image repainted in flat, edge-keeping brush dabs, like an oil painting.",
|
|
9197
9248
|
category: "image",
|
|
9249
|
+
video: "filter",
|
|
9198
9250
|
tags: ["image", "painterly", "artistic", "kuwahara", "filter"],
|
|
9199
9251
|
source: glsl(
|
|
9200
9252
|
`// Oil paint: a four-sector Kuwahara filter, each pixel takes the calmest neighbourhood's colour.
|
|
@@ -9265,6 +9317,139 @@ var imageTreatments = [
|
|
|
9265
9317
|
imageOilPaint
|
|
9266
9318
|
];
|
|
9267
9319
|
|
|
9320
|
+
// src/catalog/types.ts
|
|
9321
|
+
var EFFECT_CATEGORIES = [
|
|
9322
|
+
"gradient",
|
|
9323
|
+
"organic",
|
|
9324
|
+
"pattern",
|
|
9325
|
+
"light",
|
|
9326
|
+
"space",
|
|
9327
|
+
"retro",
|
|
9328
|
+
"image",
|
|
9329
|
+
"overlay",
|
|
9330
|
+
"text",
|
|
9331
|
+
"morph",
|
|
9332
|
+
"interaction",
|
|
9333
|
+
"pyrotechnics",
|
|
9334
|
+
"timewarp",
|
|
9335
|
+
"melt",
|
|
9336
|
+
"electric",
|
|
9337
|
+
"transition",
|
|
9338
|
+
"loader",
|
|
9339
|
+
"data",
|
|
9340
|
+
"icon"
|
|
9341
|
+
];
|
|
9342
|
+
var VIDEO_USES = ["filter", "transition", "interactive", "stills", "none"];
|
|
9343
|
+
var VECTOR_CONTROL_TYPES = ["float", "int", "bool", "color", "text"];
|
|
9344
|
+
var PLACEHOLDER = /\{\{\s*([A-Za-z_]\w*)\s*(?::\s*([A-Za-z0-9]*)([^}]*))?\}\}/g;
|
|
9345
|
+
function motionStrings(motion) {
|
|
9346
|
+
const out = [];
|
|
9347
|
+
const walk = (v) => {
|
|
9348
|
+
if (typeof v === "string") out.push(v);
|
|
9349
|
+
else if (Array.isArray(v)) v.forEach(walk);
|
|
9350
|
+
else if (v && typeof v === "object") Object.values(v).forEach(walk);
|
|
9351
|
+
};
|
|
9352
|
+
walk(motion);
|
|
9353
|
+
return out;
|
|
9354
|
+
}
|
|
9355
|
+
function vectorControls(motion) {
|
|
9356
|
+
const controls = [];
|
|
9357
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9358
|
+
for (const text of motionStrings(motion)) {
|
|
9359
|
+
for (const [, name, type, attributes] of text.matchAll(PLACEHOLDER)) {
|
|
9360
|
+
if (type === void 0 || seen.has(name) || !VECTOR_CONTROL_TYPES.includes(type)) continue;
|
|
9361
|
+
seen.add(name);
|
|
9362
|
+
const colour = type === "color";
|
|
9363
|
+
controls.push(controlFromDeclaration(name, colour ? "vec3" : type, `${attributes}${colour ? " color" : ""}`, controls.length + 1));
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
9366
|
+
return controls;
|
|
9367
|
+
}
|
|
9368
|
+
function vectorEffectControls(effect) {
|
|
9369
|
+
const declared = vectorControls(effect.motion);
|
|
9370
|
+
const names = new Set(declared.map((c) => c.name));
|
|
9371
|
+
const listed = (effect.controls ?? []).filter((c) => !names.has(c.name));
|
|
9372
|
+
return [...declared, ...listed.map((c, i) => vectorControlDef(c, declared.length + i + 1))];
|
|
9373
|
+
}
|
|
9374
|
+
function vectorControlIssues(motion) {
|
|
9375
|
+
const issues = [];
|
|
9376
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
9377
|
+
for (const text of motionStrings(motion)) {
|
|
9378
|
+
for (const [whole, name, type] of text.matchAll(PLACEHOLDER)) {
|
|
9379
|
+
if (type === void 0) continue;
|
|
9380
|
+
if (!VECTOR_CONTROL_TYPES.includes(type))
|
|
9381
|
+
issues.push(`${whole}: a control's type is one of ${VECTOR_CONTROL_TYPES.join(", ")}`);
|
|
9382
|
+
else if (declarations.has(name) && declarations.get(name) !== whole)
|
|
9383
|
+
issues.push(`"${name}" is declared twice; declare it once and write {{${name}}} everywhere else`);
|
|
9384
|
+
else declarations.set(name, whole);
|
|
9385
|
+
}
|
|
9386
|
+
}
|
|
9387
|
+
return issues;
|
|
9388
|
+
}
|
|
9389
|
+
function written(control, value) {
|
|
9390
|
+
if (control.color && Array.isArray(value)) return rgbToHex(value);
|
|
9391
|
+
if (Array.isArray(value)) return value.join(" ");
|
|
9392
|
+
return value;
|
|
9393
|
+
}
|
|
9394
|
+
var escapeMarkup = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
9395
|
+
function vectorControlDef(control, line = 0) {
|
|
9396
|
+
const min = control.min ?? 0;
|
|
9397
|
+
return {
|
|
9398
|
+
name: control.name,
|
|
9399
|
+
type: control.type,
|
|
9400
|
+
label: control.label ?? control.name,
|
|
9401
|
+
color: control.color ?? false,
|
|
9402
|
+
min,
|
|
9403
|
+
max: control.max ?? Math.max(min + 1, 1),
|
|
9404
|
+
step: control.step ?? (control.type === "int" ? 1 : 0.01),
|
|
9405
|
+
default: control.default,
|
|
9406
|
+
line
|
|
9407
|
+
};
|
|
9408
|
+
}
|
|
9409
|
+
var CURRENT_COLOR = "currentColor";
|
|
9410
|
+
function isCurrentColor(value) {
|
|
9411
|
+
return typeof value === "string" && value.trim().toLowerCase() === "currentcolor";
|
|
9412
|
+
}
|
|
9413
|
+
function renderVectorEffect(effect, values = {}) {
|
|
9414
|
+
const filled = {};
|
|
9415
|
+
const placeholders = /* @__PURE__ */ new Map();
|
|
9416
|
+
for (const control of vectorEffectControls(effect)) {
|
|
9417
|
+
const given = values[control.name];
|
|
9418
|
+
if (control.color && isCurrentColor(given)) {
|
|
9419
|
+
filled[control.name] = CURRENT_COLOR;
|
|
9420
|
+
placeholders.set(control.name, CURRENT_COLOR);
|
|
9421
|
+
continue;
|
|
9422
|
+
}
|
|
9423
|
+
const check = given === void 0 ? void 0 : checkControlValue(control, given);
|
|
9424
|
+
filled[control.name] = check?.ok ? check.value : control.default;
|
|
9425
|
+
placeholders.set(control.name, written(control, filled[control.name]));
|
|
9426
|
+
}
|
|
9427
|
+
for (const [name, value] of Object.entries(effect.derived?.(filled) ?? {})) placeholders.set(name, value);
|
|
9428
|
+
const fill = (text, markup) => {
|
|
9429
|
+
const whole = /^\{\{\s*([A-Za-z_]\w*)\s*(?::[^}]*)?\}\}$/.exec(text);
|
|
9430
|
+
if (!markup && whole && placeholders.has(whole[1])) return placeholders.get(whole[1]);
|
|
9431
|
+
return text.replace(PLACEHOLDER, (match, name) => {
|
|
9432
|
+
if (!placeholders.has(name)) return match;
|
|
9433
|
+
const value = String(placeholders.get(name));
|
|
9434
|
+
return markup ? escapeMarkup(value) : value;
|
|
9435
|
+
});
|
|
9436
|
+
};
|
|
9437
|
+
const walk = (v) => {
|
|
9438
|
+
if (typeof v === "string") return fill(v, false);
|
|
9439
|
+
if (Array.isArray(v)) return v.map(walk);
|
|
9440
|
+
if (v && typeof v === "object") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));
|
|
9441
|
+
return v;
|
|
9442
|
+
};
|
|
9443
|
+
const { svg, ...rest } = effect.motion;
|
|
9444
|
+
return { svg: fill(svg.replace(/<!--[\s\S]*?-->/g, ""), true), ...walk(rest) };
|
|
9445
|
+
}
|
|
9446
|
+
function colorControl(name, hex, label) {
|
|
9447
|
+
return { name, type: "vec3", color: true, default: hexToRgb(hex) ?? [1, 1, 1], label: label ?? name };
|
|
9448
|
+
}
|
|
9449
|
+
function numberControl(name, value, min, max, label, step) {
|
|
9450
|
+
return { name, type: "float", default: value, min, max, label: label ?? name, step };
|
|
9451
|
+
}
|
|
9452
|
+
|
|
9268
9453
|
// src/catalog/text.ts
|
|
9269
9454
|
var r14 = (n5) => Math.round(n5 * 10) / 10;
|
|
9270
9455
|
function fit2(text, width, max, ems = textWidthEm(text)) {
|
|
@@ -9274,6 +9459,10 @@ function fit2(text, width, max, ems = textWidthEm(text)) {
|
|
|
9274
9459
|
}
|
|
9275
9460
|
var lettersOf = (text) => Array.from(String(text));
|
|
9276
9461
|
var mixHex2 = (a, b, t) => {
|
|
9462
|
+
if (isCurrentColor(a) || isCurrentColor(b)) {
|
|
9463
|
+
const css = (c) => isCurrentColor(c) ? CURRENT_COLOR : rgbToHex(Array.isArray(c) ? c : [1, 1, 1]);
|
|
9464
|
+
return `color-mix(in srgb, ${css(a)}, ${css(b)} ${Math.round(t * 100)}%)`;
|
|
9465
|
+
}
|
|
9277
9466
|
const x = Array.isArray(a) ? a : [1, 1, 1];
|
|
9278
9467
|
const y = Array.isArray(b) ? b : [1, 1, 1];
|
|
9279
9468
|
return rgbToHex([0, 1, 2].map((i) => x[i] + (y[i] - x[i]) * t));
|
|
@@ -9284,6 +9473,16 @@ var MONO = `ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospa
|
|
|
9284
9473
|
var MONO_EM = 0.6;
|
|
9285
9474
|
var HEAVY = `'Arial Black', 'Helvetica Neue', Impact, system-ui, sans-serif`;
|
|
9286
9475
|
var SANS3 = `system-ui, 'Helvetica Neue', Arial, sans-serif`;
|
|
9476
|
+
var SCRIPT = `'Pacifico', 'Brush Script MT', 'Segoe Script', 'Snell Roundhand', cursive`;
|
|
9477
|
+
var CAP = 0.72;
|
|
9478
|
+
var typeface = (font, weight) => `{{font: text default="${font}" label='Font'}} {{weight: int min=100 max=900 default=${weight} step=100 label='Weight'}} {{inline: bool default=false label='Inline'}}`;
|
|
9479
|
+
function frame(v, left, width, base, size, overhang = [0.05, 0, DESCENT, 0]) {
|
|
9480
|
+
const spill = overhang.map((e) => Math.round(Math.max(0, e) * 100) / 100).join(" ");
|
|
9481
|
+
return v.inline ? { viewBox: `${r14(left)} ${r14(base - size * CAP)} ${r14(width)} ${r14(size * CAP)}`, overflow: "visible", backdrop: 0, overhang: spill } : { viewBox: "0 0 400 200", overflow: "hidden", backdrop: 1, overhang: spill };
|
|
9482
|
+
}
|
|
9483
|
+
var DESCENT = 0.25;
|
|
9484
|
+
var glowing = (overhang, by) => overhang.map((e) => e + by);
|
|
9485
|
+
var room = (v, width) => v.inline ? Infinity : width;
|
|
9287
9486
|
var BLINKS = 7;
|
|
9288
9487
|
var typewriter = {
|
|
9289
9488
|
kind: "vector",
|
|
@@ -9300,20 +9499,22 @@ var typewriter = {
|
|
|
9300
9499
|
// Monospace, so the caret lands after the last letter however long the text is.
|
|
9301
9500
|
derived: (v) => {
|
|
9302
9501
|
const count = Math.max(1, lettersOf(v.text).length);
|
|
9303
|
-
const size = r14(Math.min(44, 340 / ((count + 1) * MONO_EM)));
|
|
9502
|
+
const size = r14(Math.min(44, room(v, 340) / ((count + 1) * MONO_EM)));
|
|
9304
9503
|
const left = r14(200 - (count + 1) * MONO_EM * size / 2);
|
|
9305
9504
|
const typing = Math.round(count * Number(v.pace));
|
|
9505
|
+
const base = r14(100 + size * 0.35);
|
|
9306
9506
|
return {
|
|
9507
|
+
...frame(v, left, (count + 1) * MONO_EM * size, base, size, [0.08, 0, DESCENT, 0]),
|
|
9307
9508
|
size,
|
|
9308
9509
|
left,
|
|
9309
|
-
base
|
|
9510
|
+
base,
|
|
9310
9511
|
end: r14(left + count * MONO_EM * size),
|
|
9311
9512
|
typing,
|
|
9312
9513
|
...Object.fromEntries(Array.from({ length: BLINKS }, (_, k) => [`blink${k}`, typing + k * 500]))
|
|
9313
9514
|
};
|
|
9314
9515
|
},
|
|
9315
9516
|
motion: {
|
|
9316
|
-
svg: `<svg viewBox="
|
|
9517
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='Hello, world.' label='Text'}} {{paper: color default=#111827 label='Background'}} {{ink: color default=#F9FAFB label='Text colour'}} {{pace: float min=30 max=300 default=90 step=5 label='Ms per letter'}} ${typeface(MONO, 400)} --><rect width="400" height="200" fill="{{paper}}" opacity="{{backdrop}}"/><text id="typed" x="{{left}}" y="{{base}}" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}" xml:space="preserve">{{text}}</text><text id="caret" x="{{end}}" y="{{base}}" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}" opacity="0">\u258C</text></svg>`,
|
|
9317
9518
|
animate: [
|
|
9318
9519
|
{ id: "typed", write: "{{text}}", caret: "\u258C", ms: n4("typing"), ease: "linear" },
|
|
9319
9520
|
// Hidden while the writer shows its own caret, then blinking where it stopped.
|
|
@@ -9335,13 +9536,13 @@ var scrambleText = {
|
|
|
9335
9536
|
],
|
|
9336
9537
|
derived: (v) => {
|
|
9337
9538
|
const count = Math.max(1, lettersOf(v.text).length);
|
|
9338
|
-
const size = r14(Math.min(60, 360 / (count * MONO_EM)));
|
|
9539
|
+
const size = r14(Math.min(60, room(v, 360) / (count * MONO_EM)));
|
|
9339
9540
|
const width = r14(count * MONO_EM * size);
|
|
9340
9541
|
const base = r14(100 + size * 0.35);
|
|
9341
|
-
return { size, base, barX: r14(200 - width / 2), barY: r14(base + size * 0.3), barW: width, decode: Math.round(count * Number(v.pace)), glowWide: Number(v.glow) * 2 };
|
|
9542
|
+
return { size, base, barX: r14(200 - width / 2), barY: r14(base + size * 0.3), barW: width, decode: Math.round(count * Number(v.pace)), glowWide: Number(v.glow) * 2, ...frame(v, 200 - width / 2, width, base, size, glowing([0.08, 0, Math.max(DESCENT, 0.3 + 3 / size), 0], Number(v.glow) * 4 / size)) };
|
|
9342
9543
|
},
|
|
9343
9544
|
motion: {
|
|
9344
|
-
svg: `<svg viewBox="
|
|
9545
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='ACCESS GRANTED' label='Text'}} {{glyphs: text default='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&@$*+' label='Scramble glyphs'}} {{background: color default=#05070D label='Background'}} {{ink: color default=#E2E8F0 label='Text colour'}} {{accent: color default=#22D3EE label='Accent'}} {{pace: float min=20 max=250 default=70 step=5 label='Ms per letter'}} {{glow: float min=0 max=6 default=2 step=0.5 label='Glow'}} ${typeface(MONO, 700)} --><defs><filter id="glow" x="-20%" y="-50%" width="140%" height="200%"><feGaussianBlur stdDeviation="{{glowWide}}" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><text id="word" x="200" y="{{base}}" text-anchor="middle" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}" filter="url(#glow)" xml:space="preserve">{{text}}</text><rect id="bar" x="{{barX}}" y="{{barY}}" width="0" height="3" fill="{{accent}}"/></svg>`,
|
|
9345
9546
|
animate: [
|
|
9346
9547
|
// Pure noise for a moment (the scramble runs before the change starts), then it decodes.
|
|
9347
9548
|
{ id: "word", write: "{{text}}", scramble: "{{glyphs}}", delay: 500, ms: n4("decode"), ease: "linear" },
|
|
@@ -9367,10 +9568,11 @@ var kineticStagger = {
|
|
|
9367
9568
|
const letters = lettersOf(v.text).slice(0, SLOTS2);
|
|
9368
9569
|
const widths = letters.map((c) => textWidthEm(c));
|
|
9369
9570
|
const ems = Math.max(0.6, widths.reduce((a, b) => a + b, 0));
|
|
9370
|
-
const size = Math.min(92, 370 / ems);
|
|
9571
|
+
const size = Math.min(92, room(v, 370) / ems);
|
|
9371
9572
|
const base = 100 + size * 0.35;
|
|
9372
9573
|
const stagger = Number(v.stagger);
|
|
9373
9574
|
const out = {
|
|
9575
|
+
...frame(v, 200 - ems * size / 2, ems * size, base, size, [0.15, 0, Math.max(DESCENT, 0.2 + 6 / size), 0]),
|
|
9374
9576
|
size: r14(size),
|
|
9375
9577
|
base: r14(base),
|
|
9376
9578
|
rise: r14(base - size * 0.1),
|
|
@@ -9392,9 +9594,9 @@ var kineticStagger = {
|
|
|
9392
9594
|
return out;
|
|
9393
9595
|
},
|
|
9394
9596
|
motion: {
|
|
9395
|
-
svg: `<svg viewBox="
|
|
9597
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='Kinetic' label='Text'}} {{background: color default=#F8FAFC label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#F43F5E label='Underline'}} {{stagger: float min=20 max=200 default=55 step=5 label='Ms between letters'}} ${typeface(HEAVY, 900)} --><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/>${Array.from(
|
|
9396
9598
|
{ length: SLOTS2 },
|
|
9397
|
-
(_, i) => `<text id="l${i}" text-anchor="middle" transform="translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)" opacity="0" font-family="
|
|
9599
|
+
(_, i) => `<text id="l${i}" text-anchor="middle" transform="translate({{x${i}}} {{drop}}) rotate(-28) scale(0.3)" opacity="0" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}">{{c${i}}}</text>`
|
|
9398
9600
|
).join("")}<rect id="line" x="{{lineX}}" y="{{lineY}}" width="0" height="6" rx="3" fill="{{accent}}"/></svg>`,
|
|
9399
9601
|
animate: [
|
|
9400
9602
|
...Array.from({ length: SLOTS2 }, (_, i) => [
|
|
@@ -9428,8 +9630,10 @@ var neonSign = {
|
|
|
9428
9630
|
derived: (v) => {
|
|
9429
9631
|
const letters = lettersOf(v.text);
|
|
9430
9632
|
const k = Math.min(Math.max(0, Math.round(Number(v.faulty)) - 1), Math.max(0, letters.length - 1));
|
|
9431
|
-
const { size, length } = fit2(String(v.text), 340, 84);
|
|
9633
|
+
const { size, length, left } = fit2(String(v.text), room(v, 340), 84);
|
|
9432
9634
|
return {
|
|
9635
|
+
...frame(v, left, length, 100 + size * 0.3, size, glowing([0.1, 0, DESCENT, 0], Number(v.glow) * 6 / size)),
|
|
9636
|
+
hazeX: r14(Math.max(170, length / 2 + 30)),
|
|
9433
9637
|
head: letters.slice(0, k).join(""),
|
|
9434
9638
|
mid: letters[k] ?? "",
|
|
9435
9639
|
tail: letters.slice(k + 1).join(""),
|
|
@@ -9441,12 +9645,12 @@ var neonSign = {
|
|
|
9441
9645
|
};
|
|
9442
9646
|
},
|
|
9443
9647
|
motion: (() => {
|
|
9444
|
-
const word = `x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="
|
|
9648
|
+
const word = `x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}"`;
|
|
9445
9649
|
const runs = (id) => `<tspan>{{head}}</tspan><tspan id="${id}">{{mid}}</tspan><tspan>{{tail}}</tspan>`;
|
|
9446
9650
|
const startUp = [[0, 0], [150, 0.85], [210, 0], [330, 1], [390, 0.15], [450, 1], [620, 0.35], [680, 1]];
|
|
9447
9651
|
const buzz = [[0, 1], [1300, 0.15], [1350, 1], [1420, 0.2], [1520, 1], [2100, 0.1], [2160, 1], [2230, 0.25], [2280, 1]];
|
|
9448
9652
|
return {
|
|
9449
|
-
svg: `<svg viewBox="
|
|
9653
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='Open late' label='Text'}} {{tube: color default=#FF3DA5 label='Tube'}} {{wall: color default=#120612 label='Wall'}} {{glow: float min=0.5 max=8 default=3.5 step=0.5 label='Glow'}} {{faulty: int min=1 max=24 default=6 label='Buzzing letter'}} ${typeface(SCRIPT, 400)} --><defs><filter id="neon" x="-30%" y="-80%" width="160%" height="260%"><feGaussianBlur in="SourceGraphic" stdDeviation="{{glow}}" result="near"/><feGaussianBlur in="SourceGraphic" stdDeviation="{{far}}" result="far"/><feMerge><feMergeNode in="far"/><feMergeNode in="far"/><feMergeNode in="near"/><feMergeNode in="SourceGraphic"/></feMerge></filter><filter id="haze" x="-50%" y="-100%" width="200%" height="300%"><feGaussianBlur stdDeviation="30"/></filter></defs><rect width="400" height="200" fill="{{wall}}" opacity="{{backdrop}}"/><g id="sign" opacity="0"><ellipse cx="200" cy="100" rx="{{hazeX}}" ry="55" fill="{{tube}}" opacity="0.18" filter="url(#haze)"/><text ${word} fill="{{tube}}" stroke="{{tube}}" stroke-width="1.5" filter="url(#neon)">${runs("buzzGlow")}</text><text ${word} fill="{{core}}">${runs("buzzCore")}</text></g></svg>`,
|
|
9450
9654
|
animate: [
|
|
9451
9655
|
...holds("sign", "opacity", startUp),
|
|
9452
9656
|
// fill-opacity rather than opacity: browsers ignore opacity on a <tspan>.
|
|
@@ -9469,11 +9673,12 @@ var strokeDrawText = {
|
|
|
9469
9673
|
],
|
|
9470
9674
|
// <text> takes no pathLength, so `draw` cannot measure it: the dash grows instead, longer than any letter's outline.
|
|
9471
9675
|
derived: (v) => {
|
|
9472
|
-
const { size, length } = fit2(String(v.text), 360, 100);
|
|
9473
|
-
|
|
9676
|
+
const { size, length, left } = fit2(String(v.text), room(v, 360), 100);
|
|
9677
|
+
const edge = Number(v.width) / 2 / size;
|
|
9678
|
+
return { size, length, base: r14(100 + size * 0.35), dash: Math.round(size * 6), ...frame(v, left, length, 100 + size * 0.35, size, glowing([0.05, 0, DESCENT, 0], edge)) };
|
|
9474
9679
|
},
|
|
9475
9680
|
motion: {
|
|
9476
|
-
svg: `<svg viewBox="
|
|
9681
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='Draw' label='Text'}} {{background: color default=#FFFBF5 label='Background'}} {{outline: color default=#1E293B label='Outline'}} {{fill: color default=#F97316 label='Fill'}} {{width: float min=0.5 max=6 default=2 step=0.5 label='Outline width'}} {{fillOpacity: float min=0 max=1 default=1 label='Fill opacity'}} ${typeface(HEAVY, 900)} --><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><text id="word" x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{fill}}" fill-opacity="0" stroke="{{outline}}" stroke-width="{{width}}" stroke-linejoin="round" stroke-dasharray="0 {{dash}}">{{text}}</text></svg>`,
|
|
9477
9682
|
animate: [
|
|
9478
9683
|
{ id: "word", attrs: { "stroke-dasharray": ["0 {{dash}}", "{{dash}} 0"] }, ms: 2e3, ease: "in-out" },
|
|
9479
9684
|
{ id: "word", attrs: { "fill-opacity": [0, n4("fillOpacity")] }, delay: 1500, ms: 700, ease: "out" }
|
|
@@ -9493,8 +9698,9 @@ var splitReveal = {
|
|
|
9493
9698
|
{ name: "Gold on black", values: { background: [0.02, 0.02, 0.02], ink: [0.96, 0.84, 0.55], line: [0.96, 0.84, 0.55] } }
|
|
9494
9699
|
],
|
|
9495
9700
|
derived: (v) => {
|
|
9496
|
-
const { size, length, left } = fit2(String(v.text), 360, 88);
|
|
9701
|
+
const { size, length, left } = fit2(String(v.text), room(v, 360), 88);
|
|
9497
9702
|
return {
|
|
9703
|
+
...frame(v, left, length, 100 + size * 0.36, size, [0.05, 10 / size, Math.max(DESCENT, 34 / size), 10 / size]),
|
|
9498
9704
|
size,
|
|
9499
9705
|
length,
|
|
9500
9706
|
base: r14(100 + size * 0.36),
|
|
@@ -9505,9 +9711,9 @@ var splitReveal = {
|
|
|
9505
9711
|
};
|
|
9506
9712
|
},
|
|
9507
9713
|
motion: (() => {
|
|
9508
|
-
const word = `<text x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="
|
|
9714
|
+
const word = `<text x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}">{{text}}</text>`;
|
|
9509
9715
|
return {
|
|
9510
|
-
svg: `<svg viewBox="
|
|
9716
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='Chapter One' label='Text'}} {{caption: text default='The beginning' label='Caption'}} {{background: color default=#0F172A label='Background'}} {{ink: color default=#F8FAFC label='Text colour'}} {{line: color default=#38BDF8 label='Line'}} ${typeface(SANS3, 800)} --><defs><clipPath id="above"><rect x="-5000" y="-5000" width="10400" height="5100"/></clipPath><clipPath id="below"><rect x="-5000" y="100" width="10400" height="5100"/></clipPath></defs><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><g clip-path="url(#above)"><g id="top" transform="translate(0 {{shift}})">${word}</g></g><g clip-path="url(#below)"><g id="bottom" transform="translate(0 -{{shift}})">${word}</g></g><path id="line" d="M{{lineX1}} 100 H{{lineX2}}" stroke="{{line}}" stroke-width="2.5" stroke-linecap="round"/><text id="caption" x="200" y="{{captionY}}" text-anchor="middle" font-family="{{font}}" font-size="13" letter-spacing="3" fill="{{ink}}" opacity="0">{{caption}}</text></svg>`,
|
|
9511
9717
|
animate: [
|
|
9512
9718
|
{ id: "line", draw: true, ms: 600, ease: "in-out" },
|
|
9513
9719
|
{ id: "top", attrs: { transform: ["translate(0 {{shift}})", "translate(0 0)"] }, delay: 450, ms: 800, ease: "out" },
|
|
@@ -9533,12 +9739,13 @@ var highlighter = {
|
|
|
9533
9739
|
],
|
|
9534
9740
|
// The swipe runs a little past the phrase at both ends, across its lower half, with a ragged second pass.
|
|
9535
9741
|
derived: (v) => {
|
|
9536
|
-
const { size, length, left } = fit2(String(v.text), 330, 56);
|
|
9742
|
+
const { size, length, left } = fit2(String(v.text), room(v, 330), 56);
|
|
9537
9743
|
const base = 100 + size * 0.35;
|
|
9538
9744
|
const x0 = left - size * 0.25;
|
|
9539
9745
|
const x1 = 400 - left + size * 0.2;
|
|
9540
9746
|
const y = base - size * 0.3;
|
|
9541
9747
|
return {
|
|
9748
|
+
...frame(v, left, length, base, size, [0.05, 0.2, DESCENT, 0.25]),
|
|
9542
9749
|
size,
|
|
9543
9750
|
length,
|
|
9544
9751
|
base: r14(base),
|
|
@@ -9549,7 +9756,7 @@ var highlighter = {
|
|
|
9549
9756
|
};
|
|
9550
9757
|
},
|
|
9551
9758
|
motion: {
|
|
9552
|
-
svg: `<svg viewBox="
|
|
9759
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='Ship it faster' label='Phrase'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#111827 label='Text colour'}} {{marker: color default=#FDE047 label='Marker'}} ${typeface(SANS3, 700)} --><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><g transform="rotate(-1.2 200 100)" opacity="0.9"><path id="swipe" d="{{swipe}}" fill="none" stroke="{{marker}}" stroke-width="{{thick}}"/><path id="ragged" d="{{ragged}}" fill="none" stroke="{{marker}}" stroke-width="{{thin}}" stroke-linecap="round"/></g><text id="phrase" x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}" opacity="0">{{text}}</text></svg>`,
|
|
9553
9760
|
animate: [
|
|
9554
9761
|
{ id: "phrase", attrs: { opacity: [0, 1] }, ms: 300, ease: "out" },
|
|
9555
9762
|
{ id: "swipe", draw: true, delay: 350, ms: 650, ease: "in-out" },
|
|
@@ -9578,12 +9785,14 @@ var wordCycle = {
|
|
|
9578
9785
|
const lead = textWidthEm(String(v.prefix));
|
|
9579
9786
|
const ems = words.map((w) => Math.max(0.6, textWidthEm(w)));
|
|
9580
9787
|
const total = lead + 0.3 + Math.max(...ems);
|
|
9581
|
-
const size = Math.min(52, 370 / total);
|
|
9788
|
+
const size = Math.min(52, room(v, 370) / total);
|
|
9582
9789
|
const left = 200 - total * size / 2;
|
|
9583
9790
|
const base = 100 + size * 0.35;
|
|
9584
9791
|
const step = size * 1.3;
|
|
9585
9792
|
const wx = left + (lead + 0.3) * size;
|
|
9586
9793
|
return {
|
|
9794
|
+
...frame(v, left, total * size, base, size, [0.08, 0, Math.max(DESCENT, 0.18 + 4 / size), 0]),
|
|
9795
|
+
bold: Math.min(900, Number(v.weight) + 100),
|
|
9587
9796
|
size: r14(size),
|
|
9588
9797
|
base: r14(base),
|
|
9589
9798
|
px: r14(left),
|
|
@@ -9605,9 +9814,9 @@ var wordCycle = {
|
|
|
9605
9814
|
};
|
|
9606
9815
|
},
|
|
9607
9816
|
motion: {
|
|
9608
|
-
svg: `<svg viewBox="
|
|
9817
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{prefix: text default='We build' label='Lead-in'}} {{word1: text default=apps label='Word 1'}} {{word2: text default=brands label='Word 2'}} {{word3: text default=websites label='Word 3'}} {{word4: text default=games label='Word 4'}} {{background: color default=#FFFFFF label='Background'}} {{ink: color default=#0F172A label='Text colour'}} {{accent: color default=#6366F1 label='Accent'}} ${typeface(SANS3, 700)} --><defs><clipPath id="window"><rect x="{{clipX}}" y="{{clipY}}" width="{{clipW}}" height="{{clipH}}"/></clipPath></defs><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><text x="{{px}}" y="{{base}}" textLength="{{plen}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" fill="{{ink}}">{{prefix}}</text><g clip-path="url(#window)"><g id="reel" transform="translate(0 -0)">${Array.from(
|
|
9609
9818
|
{ length: CYCLE_WORDS + 1 },
|
|
9610
|
-
(_, k) => `<text x="{{wx}}" y="{{y${k}}}" textLength="{{len${k}}}" lengthAdjust="spacingAndGlyphs" font-family="
|
|
9819
|
+
(_, k) => `<text x="{{wx}}" y="{{y${k}}}" textLength="{{len${k}}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{bold}}" fill="{{accent}}">{{w${k % CYCLE_WORDS}}}</text>`
|
|
9611
9820
|
).join("")}</g></g><rect id="under" x="{{wx}}" y="{{underY}}" width="{{len0}}" height="4" rx="2" fill="{{accent}}"/></svg>`,
|
|
9612
9821
|
animate: Array.from({ length: CYCLE_WORDS }, (_, i) => {
|
|
9613
9822
|
const at2 = { delay: (i + 1) * SHOW_MS + i * ROLL_MS, ms: ROLL_MS, ease: "in-out" };
|
|
@@ -9618,7 +9827,7 @@ var wordCycle = {
|
|
|
9618
9827
|
}).flat()
|
|
9619
9828
|
}
|
|
9620
9829
|
};
|
|
9621
|
-
var WAVE = `M-
|
|
9830
|
+
var WAVE = `M-2000 0${" q25 -8 50 0 t50 0".repeat(46)} V320 H-2000Z`;
|
|
9622
9831
|
var liquidFill = {
|
|
9623
9832
|
kind: "vector",
|
|
9624
9833
|
id: "liquid-fill",
|
|
@@ -9634,14 +9843,14 @@ var liquidFill = {
|
|
|
9634
9843
|
],
|
|
9635
9844
|
// The surface starts under the letters and ends above their caps.
|
|
9636
9845
|
derived: (v) => {
|
|
9637
|
-
const { size, length } = fit2(String(v.text), 360, 110);
|
|
9846
|
+
const { size, length, left } = fit2(String(v.text), room(v, 360), 110);
|
|
9638
9847
|
const base = 100 + size * 0.36;
|
|
9639
|
-
return { size, length, base: r14(base), low: r14(base + 12), high: r14(base - size * 0.82 - 12) };
|
|
9848
|
+
return { ...frame(v, left, length, base, size), size, length, base: r14(base), low: r14(base + 12), high: r14(base - size * 0.82 - 12) };
|
|
9640
9849
|
},
|
|
9641
9850
|
motion: (() => {
|
|
9642
|
-
const word = `x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="
|
|
9851
|
+
const word = `x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}"`;
|
|
9643
9852
|
return {
|
|
9644
|
-
svg: `<svg viewBox="
|
|
9853
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='FILL' label='Text'}} {{background: color default=#FFFFFF label='Background'}} {{empty: color default=#E0F2FE label='Empty'}} {{liquid: color default=#0284C7 label='Liquid'}} {{liquid2: color default=#38BDF8 label='Liquid sweep'}} ${typeface(HEAVY, 900)} --><defs><clipPath id="letters"><text ${word}>{{text}}</text></clipPath><linearGradient id="liq" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="400" y2="0" spreadMethod="repeat"><stop offset="0" stop-color="{{liquid}}"/><stop offset="0.5" stop-color="{{liquid2}}"/><stop offset="1" stop-color="{{liquid}}"/></linearGradient></defs><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><text ${word} fill="{{empty}}" stroke="{{liquid}}" stroke-width="1.5" stroke-opacity="0.5">{{text}}</text><g clip-path="url(#letters)"><g id="level" transform="translate(0 {{low}})"><path id="back" d="${WAVE}" fill="{{liquid}}" opacity="0.45" transform="translate(-50 -5)"/><path id="wave" d="${WAVE}" fill="url(#liq)" transform="translate(0 0)"/></g></g></svg>`,
|
|
9645
9854
|
animate: [
|
|
9646
9855
|
{ id: "level", attrs: { transform: ["translate(0 {{low}})", "translate(0 {{high}})"] }, ms: 2800, ease: "out" },
|
|
9647
9856
|
{ id: "wave", attrs: { transform: ["translate(0 0)", "translate(-200 0)"] }, ms: 3e3, ease: "linear" },
|
|
@@ -9683,13 +9892,15 @@ var glitchText = {
|
|
|
9683
9892
|
{ name: "Vapor", values: { left: [1, 0.3, 0.85], right: [0.4, 0.6, 1], background: [0.08, 0.02, 0.12], amount: 1.4 } }
|
|
9684
9893
|
],
|
|
9685
9894
|
derived: (v) => {
|
|
9686
|
-
const { size, length } = fit2(String(v.text), 340, 100);
|
|
9895
|
+
const { size, length, left } = fit2(String(v.text), room(v, 340), 100);
|
|
9896
|
+
const a = Number(v.amount);
|
|
9687
9897
|
const base = 100 + size * 0.36;
|
|
9688
9898
|
const top = base - size * 0.78;
|
|
9689
|
-
const cuts = [
|
|
9899
|
+
const cuts = [-1e3, ...BANDS.map((f) => r14(top + f * (base - top))), 1200];
|
|
9690
9900
|
const unit = size * Number(v.amount);
|
|
9691
9901
|
const shift = ([x, y]) => `translate(${r14(x * unit)} ${r14(y * unit)})`;
|
|
9692
9902
|
return {
|
|
9903
|
+
...frame(v, left, length, base, size, [0.05 + 0.04 * a, 0.25 * a, DESCENT + 0.04 * a, 0.25 * a]),
|
|
9693
9904
|
size,
|
|
9694
9905
|
length,
|
|
9695
9906
|
base: r14(base),
|
|
@@ -9704,10 +9915,10 @@ var glitchText = {
|
|
|
9704
9915
|
};
|
|
9705
9916
|
},
|
|
9706
9917
|
motion: (() => {
|
|
9707
|
-
const word = (paint) => `<text x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="
|
|
9918
|
+
const word = (paint) => `<text x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" ${paint}>{{text}}</text>`;
|
|
9708
9919
|
const jumps = (id, value) => GLITCH.map((key, k) => ({ id, attrs: { transform: [value(k), value(k)] }, delay: key.at, ms: 0 }));
|
|
9709
9920
|
return {
|
|
9710
|
-
svg: `<svg viewBox="
|
|
9921
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='GLITCH' label='Text'}} {{background: color default=#07070B label='Background'}} {{ink: color default=#F5F5F5 label='Text colour'}} {{left: color default=#FF0040 label='Red copy'}} {{right: color default=#00F0FF label='Cyan copy'}} {{amount: float min=0 max=3 default=1 step=0.1 label='Intensity'}} ${typeface(HEAVY, 900)} --><defs>${[0, 1, 2, 3].map((b) => `<clipPath id="slice${b}"><rect x="-5000" y="{{cut${b}}}" width="10400" height="{{band${b}}}"/></clipPath>`).join("")}</defs><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/><g id="red" style="mix-blend-mode:screen">${word(`fill="{{left}}"`)}</g><g id="cyan" style="mix-blend-mode:screen">${word(`fill="{{right}}"`)}</g>${[0, 1, 2, 3].map((b) => `<g clip-path="url(#slice${b})"><g id="s${b}">${word(`fill="{{ink}}"`)}</g></g>`).join("")}</svg>`,
|
|
9711
9922
|
animate: [
|
|
9712
9923
|
...jumps("red", (k) => `{{red${k}}}`),
|
|
9713
9924
|
...jumps("cyan", (k) => `{{cyan${k}}}`),
|
|
@@ -9733,13 +9944,15 @@ var extrudedText = {
|
|
|
9733
9944
|
],
|
|
9734
9945
|
// Each layer sits a step further back along the extrude direction, shaded from the side colour to the shadow.
|
|
9735
9946
|
derived: (v) => {
|
|
9736
|
-
const { size, length } = fit2(String(v.text), 320, 96);
|
|
9947
|
+
const { size, length, left } = fit2(String(v.text), room(v, 320), 96);
|
|
9948
|
+
const d = 0.36 * Number(v.depth);
|
|
9737
9949
|
const step = size * 0.03 * Number(v.depth);
|
|
9738
9950
|
const at2 = (deg, i) => {
|
|
9739
9951
|
const a = deg * Math.PI / 180;
|
|
9740
9952
|
return `translate(${r14(Math.cos(a) * step * i)} ${r14(Math.sin(a) * step * i)})`;
|
|
9741
9953
|
};
|
|
9742
9954
|
return {
|
|
9955
|
+
...frame(v, left, length, 92 + size * 0.35, size, [0.05, 0.77 * d, DESCENT + d, 0.77 * d]),
|
|
9743
9956
|
size,
|
|
9744
9957
|
length,
|
|
9745
9958
|
base: r14(92 + size * 0.35),
|
|
@@ -9756,10 +9969,10 @@ var extrudedText = {
|
|
|
9756
9969
|
};
|
|
9757
9970
|
},
|
|
9758
9971
|
motion: (() => {
|
|
9759
|
-
const word = (paint) => `x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="
|
|
9972
|
+
const word = (paint) => `x="200" y="{{base}}" text-anchor="middle" textLength="{{length}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="{{size}}" font-weight="{{weight}}" stroke-linejoin="round" ${paint}`;
|
|
9760
9973
|
const layers = Array.from({ length: LAYERS }, (_, k) => LAYERS - k);
|
|
9761
9974
|
return {
|
|
9762
|
-
svg: `<svg viewBox="
|
|
9975
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{text: text default='RETRO' label='Text'}} {{background: color default=#FFE8C2 label='Background'}} {{face: color default=#FFD23F label='Face'}} {{outline: color default=#1A1423 label='Outline'}} {{side: color default=#EE4266 label='Extrude'}} {{shade: color default=#3B1F2B label='Shadow'}} {{depth: float min=0.2 max=2 default=1 step=0.1 label='Depth'}} ${typeface(HEAVY, 900)} --><rect width="400" height="200" fill="{{background}}" opacity="{{backdrop}}"/>${layers.map((i) => `<text id="e${i}" transform="translate(0 0)" ${word(`fill="{{fill${i}}}" stroke="{{fill${i}}}" stroke-width="2"`)}>{{text}}</text>`).join("")}<text ${word(`fill="{{face}}" stroke="{{outline}}" stroke-width="2.5" paint-order="stroke"`)}>{{text}}</text></svg>`,
|
|
9763
9976
|
animate: layers.flatMap((i) => [
|
|
9764
9977
|
{ id: `e${i}`, attrs: { transform: ["translate(0 0)", `{{a${i}}}`] }, ms: 700, ease: "out" },
|
|
9765
9978
|
{ id: `e${i}`, attrs: { transform: [`{{a${i}}}`, `{{b${i}}}`] }, delay: 1200, ms: 1500, ease: "in-out" },
|
|
@@ -9782,129 +9995,6 @@ var textEffects = [
|
|
|
9782
9995
|
extrudedText
|
|
9783
9996
|
];
|
|
9784
9997
|
|
|
9785
|
-
// src/catalog/types.ts
|
|
9786
|
-
var EFFECT_CATEGORIES = [
|
|
9787
|
-
"gradient",
|
|
9788
|
-
"organic",
|
|
9789
|
-
"pattern",
|
|
9790
|
-
"light",
|
|
9791
|
-
"space",
|
|
9792
|
-
"retro",
|
|
9793
|
-
"image",
|
|
9794
|
-
"overlay",
|
|
9795
|
-
"text",
|
|
9796
|
-
"morph",
|
|
9797
|
-
"interaction",
|
|
9798
|
-
"pyrotechnics",
|
|
9799
|
-
"timewarp",
|
|
9800
|
-
"melt",
|
|
9801
|
-
"electric",
|
|
9802
|
-
"transition",
|
|
9803
|
-
"loader",
|
|
9804
|
-
"data",
|
|
9805
|
-
"icon"
|
|
9806
|
-
];
|
|
9807
|
-
var VECTOR_CONTROL_TYPES = ["float", "int", "bool", "color", "text"];
|
|
9808
|
-
var PLACEHOLDER = /\{\{\s*([A-Za-z_]\w*)\s*(?::\s*([A-Za-z0-9]*)([^}]*))?\}\}/g;
|
|
9809
|
-
function motionStrings(motion) {
|
|
9810
|
-
const out = [];
|
|
9811
|
-
const walk = (v) => {
|
|
9812
|
-
if (typeof v === "string") out.push(v);
|
|
9813
|
-
else if (Array.isArray(v)) v.forEach(walk);
|
|
9814
|
-
else if (v && typeof v === "object") Object.values(v).forEach(walk);
|
|
9815
|
-
};
|
|
9816
|
-
walk(motion);
|
|
9817
|
-
return out;
|
|
9818
|
-
}
|
|
9819
|
-
function vectorControls(motion) {
|
|
9820
|
-
const controls = [];
|
|
9821
|
-
const seen = /* @__PURE__ */ new Set();
|
|
9822
|
-
for (const text of motionStrings(motion)) {
|
|
9823
|
-
for (const [, name, type, attributes] of text.matchAll(PLACEHOLDER)) {
|
|
9824
|
-
if (type === void 0 || seen.has(name) || !VECTOR_CONTROL_TYPES.includes(type)) continue;
|
|
9825
|
-
seen.add(name);
|
|
9826
|
-
const colour = type === "color";
|
|
9827
|
-
controls.push(controlFromDeclaration(name, colour ? "vec3" : type, `${attributes}${colour ? " color" : ""}`, controls.length + 1));
|
|
9828
|
-
}
|
|
9829
|
-
}
|
|
9830
|
-
return controls;
|
|
9831
|
-
}
|
|
9832
|
-
function vectorEffectControls(effect) {
|
|
9833
|
-
const declared = vectorControls(effect.motion);
|
|
9834
|
-
const names = new Set(declared.map((c) => c.name));
|
|
9835
|
-
const listed = (effect.controls ?? []).filter((c) => !names.has(c.name));
|
|
9836
|
-
return [...declared, ...listed.map((c, i) => vectorControlDef(c, declared.length + i + 1))];
|
|
9837
|
-
}
|
|
9838
|
-
function vectorControlIssues(motion) {
|
|
9839
|
-
const issues = [];
|
|
9840
|
-
const declarations = /* @__PURE__ */ new Map();
|
|
9841
|
-
for (const text of motionStrings(motion)) {
|
|
9842
|
-
for (const [whole, name, type] of text.matchAll(PLACEHOLDER)) {
|
|
9843
|
-
if (type === void 0) continue;
|
|
9844
|
-
if (!VECTOR_CONTROL_TYPES.includes(type))
|
|
9845
|
-
issues.push(`${whole}: a control's type is one of ${VECTOR_CONTROL_TYPES.join(", ")}`);
|
|
9846
|
-
else if (declarations.has(name) && declarations.get(name) !== whole)
|
|
9847
|
-
issues.push(`"${name}" is declared twice; declare it once and write {{${name}}} everywhere else`);
|
|
9848
|
-
else declarations.set(name, whole);
|
|
9849
|
-
}
|
|
9850
|
-
}
|
|
9851
|
-
return issues;
|
|
9852
|
-
}
|
|
9853
|
-
function written(control, value) {
|
|
9854
|
-
if (control.color && Array.isArray(value)) return rgbToHex(value);
|
|
9855
|
-
if (Array.isArray(value)) return value.join(" ");
|
|
9856
|
-
return value;
|
|
9857
|
-
}
|
|
9858
|
-
var escapeMarkup = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
9859
|
-
function vectorControlDef(control, line = 0) {
|
|
9860
|
-
const min = control.min ?? 0;
|
|
9861
|
-
return {
|
|
9862
|
-
name: control.name,
|
|
9863
|
-
type: control.type,
|
|
9864
|
-
label: control.label ?? control.name,
|
|
9865
|
-
color: control.color ?? false,
|
|
9866
|
-
min,
|
|
9867
|
-
max: control.max ?? Math.max(min + 1, 1),
|
|
9868
|
-
step: control.step ?? (control.type === "int" ? 1 : 0.01),
|
|
9869
|
-
default: control.default,
|
|
9870
|
-
line
|
|
9871
|
-
};
|
|
9872
|
-
}
|
|
9873
|
-
function renderVectorEffect(effect, values = {}) {
|
|
9874
|
-
const filled = {};
|
|
9875
|
-
const placeholders = /* @__PURE__ */ new Map();
|
|
9876
|
-
for (const control of vectorEffectControls(effect)) {
|
|
9877
|
-
const given = values[control.name];
|
|
9878
|
-
const check = given === void 0 ? void 0 : checkControlValue(control, given);
|
|
9879
|
-
filled[control.name] = check?.ok ? check.value : control.default;
|
|
9880
|
-
placeholders.set(control.name, written(control, filled[control.name]));
|
|
9881
|
-
}
|
|
9882
|
-
for (const [name, value] of Object.entries(effect.derived?.(filled) ?? {})) placeholders.set(name, value);
|
|
9883
|
-
const fill = (text, markup) => {
|
|
9884
|
-
const whole = /^\{\{\s*([A-Za-z_]\w*)\s*(?::[^}]*)?\}\}$/.exec(text);
|
|
9885
|
-
if (!markup && whole && placeholders.has(whole[1])) return placeholders.get(whole[1]);
|
|
9886
|
-
return text.replace(PLACEHOLDER, (match, name) => {
|
|
9887
|
-
if (!placeholders.has(name)) return match;
|
|
9888
|
-
const value = String(placeholders.get(name));
|
|
9889
|
-
return markup ? escapeMarkup(value) : value;
|
|
9890
|
-
});
|
|
9891
|
-
};
|
|
9892
|
-
const walk = (v) => {
|
|
9893
|
-
if (typeof v === "string") return fill(v, false);
|
|
9894
|
-
if (Array.isArray(v)) return v.map(walk);
|
|
9895
|
-
if (v && typeof v === "object") return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, walk(x)]));
|
|
9896
|
-
return v;
|
|
9897
|
-
};
|
|
9898
|
-
const { svg, ...rest } = effect.motion;
|
|
9899
|
-
return { svg: fill(svg.replace(/<!--[\s\S]*?-->/g, ""), true), ...walk(rest) };
|
|
9900
|
-
}
|
|
9901
|
-
function colorControl(name, hex, label) {
|
|
9902
|
-
return { name, type: "vec3", color: true, default: hexToRgb(hex) ?? [1, 1, 1], label: label ?? name };
|
|
9903
|
-
}
|
|
9904
|
-
function numberControl(name, value, min, max, label, step) {
|
|
9905
|
-
return { name, type: "float", default: value, min, max, label: label ?? name, step };
|
|
9906
|
-
}
|
|
9907
|
-
|
|
9908
9998
|
// src/catalog/vector.ts
|
|
9909
9999
|
var spinner = {
|
|
9910
10000
|
kind: "vector",
|
|
@@ -10317,6 +10407,7 @@ var flowNetwork = {
|
|
|
10317
10407
|
}
|
|
10318
10408
|
};
|
|
10319
10409
|
var DRIP_BASELINE = 120;
|
|
10410
|
+
var DRIP_SIZE = 104;
|
|
10320
10411
|
var DRIP_CAP = 75;
|
|
10321
10412
|
var DRIP_TOP = 106;
|
|
10322
10413
|
var DRIPS2 = [
|
|
@@ -10328,6 +10419,9 @@ var DRIPS2 = [
|
|
|
10328
10419
|
{ at: 0.693, width: 12, length: 42, delay: 60, ms: 1700 },
|
|
10329
10420
|
{ at: 0.793, width: 11, length: 32, delay: 300, ms: 1500 }
|
|
10330
10421
|
];
|
|
10422
|
+
var DRIP_RUN = 300;
|
|
10423
|
+
var DRIP_RUNS = 8;
|
|
10424
|
+
var DRIP_SLOTS = Array.from({ length: DRIP_RUNS }, (_, run) => DRIPS2.map((d, k) => ({ ...d, i: run * DRIPS2.length + k, run, delay: d.delay + run * 90 }))).flat();
|
|
10331
10425
|
var dripText = {
|
|
10332
10426
|
kind: "vector",
|
|
10333
10427
|
id: "drip-text",
|
|
@@ -10340,55 +10434,63 @@ var dripText = {
|
|
|
10340
10434
|
{ name: "Slime", values: { fill: [0.55, 0.93, 0.25], outline: [0.06, 0.2, 0.04], shine: [0.85, 1, 0.7] } },
|
|
10341
10435
|
{ name: "Molten gold", values: { fill: [1, 0.78, 0.2], outline: [0.35, 0.16, 0], shine: [1, 0.96, 0.75], drip: 1.5 } }
|
|
10342
10436
|
],
|
|
10343
|
-
// The word is
|
|
10437
|
+
// The word is drawn at its own width (textLength from its estimated width), so the drips land under its letters in any font.
|
|
10344
10438
|
derived: (v) => {
|
|
10345
|
-
const
|
|
10346
|
-
const width = Math.min(380, letters * 75);
|
|
10439
|
+
const width = Math.round(Math.max(0.6, textWidthEm(String(v.word).trim())) * DRIP_SIZE);
|
|
10347
10440
|
const left = 200 - width / 2;
|
|
10441
|
+
const runs = Math.min(DRIP_RUNS, Math.max(1, Math.round(width / DRIP_RUN)));
|
|
10442
|
+
const run = width / runs;
|
|
10443
|
+
const r15 = (n5) => Math.round(n5 * 10) / 10;
|
|
10444
|
+
const edge = Number(v.stroke) / 2 / DRIP_SIZE;
|
|
10445
|
+
const tip = (DRIP_TOP + Math.max(...DRIPS2.map((d) => d.length)) * Number(v.drip) + 13 * 0.72 - DRIP_BASELINE) / DRIP_SIZE;
|
|
10446
|
+
const overhang = [edge, edge, Math.max(0.05, tip) + edge, edge].map((e) => Math.round(e * 100) / 100).join(" ");
|
|
10348
10447
|
return {
|
|
10349
10448
|
width,
|
|
10449
|
+
fit: v.inline ? 1 : Math.round(Math.min(1, 380 / width) * 1e3) / 1e3,
|
|
10350
10450
|
// Inline, the picture frames just the word's capitals, from cap height to baseline, so it sits on
|
|
10351
10451
|
// the line like a letter would; the pop, outline and drips spill out over the text around it.
|
|
10352
10452
|
viewBox: v.inline ? `${left} ${DRIP_BASELINE - DRIP_CAP} ${width} ${DRIP_CAP}` : "0 0 400 200",
|
|
10353
10453
|
overflow: v.inline ? "visible" : "hidden",
|
|
10454
|
+
overhang,
|
|
10354
10455
|
...Object.fromEntries(
|
|
10355
|
-
|
|
10356
|
-
const x =
|
|
10357
|
-
const length =
|
|
10456
|
+
DRIP_SLOTS.flatMap((d) => {
|
|
10457
|
+
const x = r15(left + (d.run + d.at) * run);
|
|
10458
|
+
const length = r15(d.length * Number(v.drip));
|
|
10358
10459
|
return [
|
|
10359
|
-
[`
|
|
10360
|
-
[`
|
|
10361
|
-
[`
|
|
10362
|
-
[`
|
|
10363
|
-
[`
|
|
10460
|
+
[`show${d.i}`, d.run < runs ? "inline" : "none"],
|
|
10461
|
+
[`x${d.i}`, x],
|
|
10462
|
+
[`left${d.i}`, r15(x - d.width / 2)],
|
|
10463
|
+
[`shine${d.i}`, r15(x - d.width * 0.25)],
|
|
10464
|
+
[`len${d.i}`, length],
|
|
10465
|
+
[`tip${d.i}`, r15(DRIP_TOP + length)]
|
|
10364
10466
|
];
|
|
10365
10467
|
})
|
|
10366
10468
|
)
|
|
10367
10469
|
};
|
|
10368
10470
|
},
|
|
10369
10471
|
motion: (() => {
|
|
10370
|
-
const word = `<text x="200" y="${DRIP_BASELINE}" text-anchor="middle" textLength="{{width}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="
|
|
10371
|
-
const drips = (layer, paint) =>
|
|
10372
|
-
(d
|
|
10472
|
+
const word = `<text x="200" y="${DRIP_BASELINE}" text-anchor="middle" textLength="{{width}}" lengthAdjust="spacingAndGlyphs" font-family="{{font}}" font-size="${DRIP_SIZE}" font-weight="{{weight}}" stroke-linejoin="round"`;
|
|
10473
|
+
const drips = (layer, paint) => DRIP_SLOTS.map(
|
|
10474
|
+
(d) => `<g display="{{show${d.i}}}"><rect id="${layer}r${d.i}" x="{{left${d.i}}}" y="${DRIP_TOP}" width="${d.width}" height="0" rx="${d.width / 2}" ${paint}/><circle id="${layer}c${d.i}" cx="{{x${d.i}}}" cy="${DRIP_TOP}" r="${d.width * 0.72}" ${paint}/></g>`
|
|
10373
10475
|
).join("");
|
|
10374
10476
|
const outline = `fill="{{outline}}" stroke="{{outline}}" stroke-width="{{stroke}}"`;
|
|
10375
10477
|
const pop = (from, to) => [`translate(200 100) scale(${from}) translate(-200 -100)`, `translate(200 100) scale(${to}) translate(-200 -100)`];
|
|
10376
10478
|
return {
|
|
10377
|
-
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}"><!-- {{word: text default=SLOP label='Word'}} {{font: text default='Arial Black, Impact, system-ui, sans-serif' label='Font'}} {{weight: int min=100 max=900 default=900 step=100 label='Weight'}} {{fill: color default=#FF7EB6 label='Fill'}} {{outline: color default=#3A0A2C label='Outline'}} {{shine: color default=#FFD1E6 label='Shine'}} {{drip: float min=0.2 max=2 default=1 label='Drip length'}} {{stroke: float min=0 max=14 default=7 step=0.5 label='Outline width'}} {{inline: bool default=false label='Inline'}} --><g id="word" transform="${pop(0.6, 1)[0]}" opacity="0">${drips("o", outline)}${word} fill="none" stroke="{{outline}}" stroke-width="{{stroke}}">{{word}}</text>${drips("f", `fill="{{fill}}"`)}${word} fill="{{fill}}">{{word}}</text>${
|
|
10378
|
-
(d
|
|
10379
|
-
).join("")}</g></svg>`,
|
|
10479
|
+
svg: `<svg viewBox="{{viewBox}}" overflow="{{overflow}}" data-overhang="{{overhang}}"><!-- {{word: text default=SLOP label='Word'}} {{font: text default='Arial Black, Impact, system-ui, sans-serif' label='Font'}} {{weight: int min=100 max=900 default=900 step=100 label='Weight'}} {{fill: color default=#FF7EB6 label='Fill'}} {{outline: color default=#3A0A2C label='Outline'}} {{shine: color default=#FFD1E6 label='Shine'}} {{drip: float min=0.2 max=2 default=1 label='Drip length'}} {{stroke: float min=0 max=14 default=7 step=0.5 label='Outline width'}} {{inline: bool default=false label='Inline'}} --><g transform="translate(200 100) scale({{fit}}) translate(-200 -100)"><g id="word" transform="${pop(0.6, 1)[0]}" opacity="0">${drips("o", outline)}${word} fill="none" stroke="{{outline}}" stroke-width="{{stroke}}">{{word}}</text>${drips("f", `fill="{{fill}}"`)}${word} fill="{{fill}}">{{word}}</text>${DRIP_SLOTS.map(
|
|
10480
|
+
(d) => `<circle id="s${d.i}" display="{{show${d.i}}}" cx="{{shine${d.i}}}" cy="${DRIP_TOP}" r="${d.width * 0.2}" fill="{{shine}}" opacity="0"/>`
|
|
10481
|
+
).join("")}</g></g></svg>`,
|
|
10380
10482
|
animate: [
|
|
10381
10483
|
{ id: "word", attrs: { transform: pop(0.6, 1.08), opacity: [0, 1] }, ms: 260, ease: "out" },
|
|
10382
10484
|
{ id: "word", attrs: { transform: pop(1.08, 1) }, delay: 260, ms: 200, ease: "in-out" },
|
|
10383
|
-
...
|
|
10485
|
+
...DRIP_SLOTS.flatMap((d) => {
|
|
10384
10486
|
const at2 = { delay: 400 + d.delay, ms: d.ms, ease: "in-out" };
|
|
10385
|
-
const tip = `{{tip${i}}}`;
|
|
10487
|
+
const tip = `{{tip${d.i}}}`;
|
|
10386
10488
|
return [
|
|
10387
10489
|
...["o", "f"].flatMap((layer) => [
|
|
10388
|
-
{ id: `${layer}r${i}`, attrs: { height: [0, `{{len${i}}}`] }, ...at2 },
|
|
10389
|
-
{ id: `${layer}c${i}`, attrs: { cy: [DRIP_TOP, tip] }, ...at2 }
|
|
10490
|
+
{ id: `${layer}r${d.i}`, attrs: { height: [0, `{{len${d.i}}}`] }, ...at2 },
|
|
10491
|
+
{ id: `${layer}c${d.i}`, attrs: { cy: [DRIP_TOP, tip] }, ...at2 }
|
|
10390
10492
|
]),
|
|
10391
|
-
{ id: `s${i}`, attrs: { cy: [DRIP_TOP, tip], opacity: [0, 0.9] }, ...at2 }
|
|
10493
|
+
{ id: `s${d.i}`, attrs: { cy: [DRIP_TOP, tip], opacity: [0, 0.9] }, ...at2 }
|
|
10392
10494
|
];
|
|
10393
10495
|
})
|
|
10394
10496
|
]
|
|
@@ -10508,6 +10610,7 @@ function findEffects(query = {}) {
|
|
|
10508
10610
|
if (query.category && e.category !== query.category) return false;
|
|
10509
10611
|
if (query.kind && e.kind !== query.kind) return false;
|
|
10510
10612
|
if (query.tags && !query.tags.every((t) => e.tags.includes(t))) return false;
|
|
10613
|
+
if (query.video && !(e.kind === "shader" && e.video && query.video.includes(e.video))) return false;
|
|
10511
10614
|
const haystack = [e.id, e.name, e.description, e.category, ...e.tags].join(" ").toLowerCase();
|
|
10512
10615
|
return words.every((w) => haystack.includes(w));
|
|
10513
10616
|
});
|
|
@@ -10518,7 +10621,8 @@ function effectControls(effect) {
|
|
|
10518
10621
|
function effectDefaults(effect, options = {}) {
|
|
10519
10622
|
const preset = options.preset ? effect.presets?.find((p) => p.name === options.preset)?.values : void 0;
|
|
10520
10623
|
const merged = { ...preset, ...options.values };
|
|
10521
|
-
|
|
10624
|
+
const keep = (c) => effect.kind === "vector" && c.color && isCurrentColor(merged[c.name]);
|
|
10625
|
+
return Object.fromEntries(effectControls(effect).map((c) => [c.name, keep(c) ? CURRENT_COLOR : controlValue(c, merged)]));
|
|
10522
10626
|
}
|
|
10523
10627
|
|
|
10524
10628
|
export {
|
|
@@ -10533,11 +10637,14 @@ export {
|
|
|
10533
10637
|
SAMPLE_IMAGES,
|
|
10534
10638
|
textImage,
|
|
10535
10639
|
EFFECT_CATEGORIES,
|
|
10640
|
+
VIDEO_USES,
|
|
10536
10641
|
VECTOR_CONTROL_TYPES,
|
|
10537
10642
|
vectorControls,
|
|
10538
10643
|
vectorEffectControls,
|
|
10539
10644
|
vectorControlIssues,
|
|
10540
10645
|
vectorControlDef,
|
|
10646
|
+
CURRENT_COLOR,
|
|
10647
|
+
isCurrentColor,
|
|
10541
10648
|
renderVectorEffect,
|
|
10542
10649
|
colorControl,
|
|
10543
10650
|
numberControl,
|
|
@@ -10548,4 +10655,4 @@ export {
|
|
|
10548
10655
|
effectControls,
|
|
10549
10656
|
effectDefaults
|
|
10550
10657
|
};
|
|
10551
|
-
//# sourceMappingURL=chunk-
|
|
10658
|
+
//# sourceMappingURL=chunk-UI5X4D63.js.map
|