@atmo-dev/events-ui 0.1.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.
Files changed (113) hide show
  1. package/dist/DatePicker.svelte +231 -0
  2. package/dist/DatePicker.svelte.d.ts +11 -0
  3. package/dist/DateTimePicker.svelte +101 -0
  4. package/dist/DateTimePicker.svelte.d.ts +9 -0
  5. package/dist/EventAttendees.svelte +203 -0
  6. package/dist/EventAttendees.svelte.d.ts +13 -0
  7. package/dist/EventCard.svelte +131 -0
  8. package/dist/EventCard.svelte.d.ts +8 -0
  9. package/dist/EventComments.svelte +99 -0
  10. package/dist/EventComments.svelte.d.ts +6 -0
  11. package/dist/EventEditor.svelte +589 -0
  12. package/dist/EventEditor.svelte.d.ts +20 -0
  13. package/dist/EventRsvp.svelte +237 -0
  14. package/dist/EventRsvp.svelte.d.ts +17 -0
  15. package/dist/EventView.svelte +433 -0
  16. package/dist/EventView.svelte.d.ts +16 -0
  17. package/dist/ImageDropper.svelte +66 -0
  18. package/dist/ImageDropper.svelte.d.ts +7 -0
  19. package/dist/Map.svelte +27 -0
  20. package/dist/Map.svelte.d.ts +8 -0
  21. package/dist/PostToBlueskyModal.svelte +244 -0
  22. package/dist/PostToBlueskyModal.svelte.d.ts +22 -0
  23. package/dist/ShareModal.svelte +160 -0
  24. package/dist/ShareModal.svelte.d.ts +23 -0
  25. package/dist/ThemeApply.svelte +50 -0
  26. package/dist/ThemeApply.svelte.d.ts +7 -0
  27. package/dist/ThemeBackground.svelte +33 -0
  28. package/dist/ThemeBackground.svelte.d.ts +7 -0
  29. package/dist/ThemePicker.svelte +102 -0
  30. package/dist/ThemePicker.svelte.d.ts +7 -0
  31. package/dist/ThumbnailPresets.svelte +68 -0
  32. package/dist/ThumbnailPresets.svelte.d.ts +11 -0
  33. package/dist/TimePicker.svelte +188 -0
  34. package/dist/TimePicker.svelte.d.ts +9 -0
  35. package/dist/TimezonePicker.svelte +132 -0
  36. package/dist/TimezonePicker.svelte.d.ts +6 -0
  37. package/dist/VodPlayer.svelte +137 -0
  38. package/dist/VodPlayer.svelte.d.ts +14 -0
  39. package/dist/VodTranscript.svelte +72 -0
  40. package/dist/VodTranscript.svelte.d.ts +8 -0
  41. package/dist/atproto-helpers.d.ts +21 -0
  42. package/dist/atproto-helpers.js +61 -0
  43. package/dist/cal/helper.d.ts +1 -0
  44. package/dist/cal/helper.js +20 -0
  45. package/dist/cal/ical.d.ts +22 -0
  46. package/dist/cal/ical.js +188 -0
  47. package/dist/cal/sanitize.d.ts +3 -0
  48. package/dist/cal/sanitize.js +25 -0
  49. package/dist/contrail.d.ts +54 -0
  50. package/dist/contrail.js +22 -0
  51. package/dist/date-format.d.ts +22 -0
  52. package/dist/date-format.js +43 -0
  53. package/dist/editor/LinksSection.svelte +144 -0
  54. package/dist/editor/LinksSection.svelte.d.ts +10 -0
  55. package/dist/editor/LocationSection.svelte +215 -0
  56. package/dist/editor/LocationSection.svelte.d.ts +8 -0
  57. package/dist/editor/RecurringModal.svelte +270 -0
  58. package/dist/editor/RecurringModal.svelte.d.ts +30 -0
  59. package/dist/editor/ThemeSection.svelte +39 -0
  60. package/dist/editor/ThemeSection.svelte.d.ts +7 -0
  61. package/dist/editor/ThumbnailSection.svelte +219 -0
  62. package/dist/editor/ThumbnailSection.svelte.d.ts +13 -0
  63. package/dist/editor/adapter.d.ts +98 -0
  64. package/dist/editor/adapter.js +9 -0
  65. package/dist/editor/save.d.ts +42 -0
  66. package/dist/editor/save.js +154 -0
  67. package/dist/editor/types.d.ts +39 -0
  68. package/dist/editor/types.js +9 -0
  69. package/dist/event-types.d.ts +70 -0
  70. package/dist/event-types.js +11 -0
  71. package/dist/event-view/AddToCalendarButton.svelte +42 -0
  72. package/dist/event-view/AddToCalendarButton.svelte.d.ts +9 -0
  73. package/dist/event-view/EventBadges.svelte +20 -0
  74. package/dist/event-view/EventBadges.svelte.d.ts +7 -0
  75. package/dist/event-view/EventDateBlock.svelte +43 -0
  76. package/dist/event-view/EventDateBlock.svelte.d.ts +7 -0
  77. package/dist/event-view/EventHostedBy.svelte +63 -0
  78. package/dist/event-view/EventHostedBy.svelte.d.ts +16 -0
  79. package/dist/event-view/EventLinksList.svelte +37 -0
  80. package/dist/event-view/EventLinksList.svelte.d.ts +9 -0
  81. package/dist/event-view/EventLocationBlock.svelte +48 -0
  82. package/dist/event-view/EventLocationBlock.svelte.d.ts +7 -0
  83. package/dist/event-view/EventLocationMap.svelte +72 -0
  84. package/dist/event-view/EventLocationMap.svelte.d.ts +8 -0
  85. package/dist/event-view/ExternalRsvpNotice.svelte +44 -0
  86. package/dist/event-view/ExternalRsvpNotice.svelte.d.ts +6 -0
  87. package/dist/event-view/InviteShareFlow.svelte +177 -0
  88. package/dist/event-view/InviteShareFlow.svelte.d.ts +15 -0
  89. package/dist/event-view/StreamPlacePlayer.svelte +222 -0
  90. package/dist/event-view/StreamPlacePlayer.svelte.d.ts +8 -0
  91. package/dist/event-view/format.d.ts +26 -0
  92. package/dist/event-view/format.js +145 -0
  93. package/dist/index.d.ts +18 -0
  94. package/dist/index.js +18 -0
  95. package/dist/profile-url.d.ts +1 -0
  96. package/dist/profile-url.js +7 -0
  97. package/dist/theme.d.ts +9 -0
  98. package/dist/theme.js +22 -0
  99. package/dist/themes/Blobs.svelte +35 -0
  100. package/dist/themes/Blobs.svelte.d.ts +26 -0
  101. package/dist/themes/Butterflies.svelte +185 -0
  102. package/dist/themes/Butterflies.svelte.d.ts +3 -0
  103. package/dist/themes/Fireflies.svelte +134 -0
  104. package/dist/themes/Fireflies.svelte.d.ts +3 -0
  105. package/dist/themes/Kaleidoscope.svelte +177 -0
  106. package/dist/themes/Kaleidoscope.svelte.d.ts +3 -0
  107. package/dist/themes/Matrix.svelte +150 -0
  108. package/dist/themes/Matrix.svelte.d.ts +3 -0
  109. package/dist/themes/Stars.svelte +98 -0
  110. package/dist/themes/Stars.svelte.d.ts +3 -0
  111. package/dist/thumbnails/designs.d.ts +18 -0
  112. package/dist/thumbnails/designs.js +316 -0
  113. package/package.json +95 -0
@@ -0,0 +1,35 @@
1
+ <div class="pointer-events-none fixed inset-0 -z-10 overflow-hidden bg-base-50 dark:bg-base-900">
2
+ <div
3
+ class="blob-1 absolute rounded-full bg-accent-500 opacity-30 blur-3xl"
4
+ style="width: 40vw; height: 40vw; top: -10%; left: -5%;"
5
+ ></div>
6
+ <div
7
+ class="blob-2 absolute rounded-full bg-accent-500 opacity-20 blur-3xl"
8
+ style="width: 35vw; height: 35vw; bottom: -5%; right: -10%;"
9
+ ></div>
10
+ <div
11
+ class="blob-3 absolute rounded-full bg-accent-400 opacity-15 blur-3xl"
12
+ style="width: 25vw; height: 25vw; top: 40%; left: 50%;"
13
+ ></div>
14
+ </div>
15
+
16
+ <style>
17
+ @keyframes blob-float-1 {
18
+ 0%, 100% { transform: translate(0, 0) scale(1); }
19
+ 33% { transform: translate(5vw, 8vh) scale(1.1); }
20
+ 66% { transform: translate(-3vw, 4vh) scale(0.95); }
21
+ }
22
+ @keyframes blob-float-2 {
23
+ 0%, 100% { transform: translate(0, 0) scale(1); }
24
+ 33% { transform: translate(-6vw, -5vh) scale(1.05); }
25
+ 66% { transform: translate(4vw, -8vh) scale(1.1); }
26
+ }
27
+ @keyframes blob-float-3 {
28
+ 0%, 100% { transform: translate(0, 0) scale(1); }
29
+ 33% { transform: translate(8vw, -4vh) scale(1.15); }
30
+ 66% { transform: translate(-5vw, 6vh) scale(0.9); }
31
+ }
32
+ .blob-1 { animation: blob-float-1 20s ease-in-out infinite; }
33
+ .blob-2 { animation: blob-float-2 25s ease-in-out infinite; }
34
+ .blob-3 { animation: blob-float-3 22s ease-in-out infinite; }
35
+ </style>
@@ -0,0 +1,26 @@
1
+ export default Blobs;
2
+ type Blobs = SvelteComponent<{
3
+ [x: string]: never;
4
+ }, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {}> & {
7
+ $$bindings?: string | undefined;
8
+ };
9
+ declare const Blobs: $$__sveltets_2_IsomorphicComponent<{
10
+ [x: string]: never;
11
+ }, {
12
+ [evt: string]: CustomEvent<any>;
13
+ }, {}, {}, string>;
14
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
15
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
16
+ $$bindings?: Bindings;
17
+ } & Exports;
18
+ (internal: unknown, props: {
19
+ $$events?: Events;
20
+ $$slots?: Slots;
21
+ }): Exports & {
22
+ $set?: any;
23
+ $on?: any;
24
+ };
25
+ z_$$bindings?: Bindings;
26
+ }
@@ -0,0 +1,185 @@
1
+ <script lang="ts">
2
+ import { BROWSER as browser } from 'esm-env';
3
+
4
+ let canvas: HTMLCanvasElement | undefined = $state(undefined);
5
+
6
+ $effect(() => {
7
+ if (!canvas || !browser) return;
8
+
9
+ const ctx = canvas.getContext('2d')!;
10
+ let animId: number;
11
+
12
+ const COUNT = 22;
13
+ const DRIFT_SPEED = 45; // px/sec forward flight
14
+ const DART_RATE = 0.15; // darts per second per butterfly
15
+ const ROTATION_EASE = 4; // rad/sec — how fast body turns toward heading
16
+
17
+ interface Butterfly {
18
+ x: number;
19
+ y: number;
20
+ heading: number; // radians — current direction of travel
21
+ rotation: number; // body orientation, lags heading slightly
22
+ turnRate: number; // radians/sec of random-walk steering
23
+ flapPhase: number;
24
+ flapRate: number; // Hz-ish
25
+ depthPhase: number; // slow "closer/further" scaling
26
+ depthRate: number; // Hz of depth oscillation
27
+ size: number;
28
+ hueShift: number;
29
+ alpha: number;
30
+ }
31
+
32
+ let lastWidth = 0;
33
+ function resize() {
34
+ const w = window.innerWidth;
35
+ if (w === lastWidth) return;
36
+ lastWidth = w;
37
+ canvas!.width = w;
38
+ canvas!.height = window.screen.height;
39
+ }
40
+ resize();
41
+ window.addEventListener('resize', resize);
42
+
43
+ function spawn(): Butterfly {
44
+ const angle = Math.random() * Math.PI * 2;
45
+ return {
46
+ x: Math.random() * canvas!.width,
47
+ y: Math.random() * canvas!.height,
48
+ heading: angle,
49
+ rotation: angle,
50
+ turnRate: 0.8 + Math.random() * 1.2, // 0.8–2 rad/√s of wander
51
+ flapPhase: Math.random() * Math.PI * 2,
52
+ flapRate: 1.5 + Math.random() * 1.5, // 1.5–3 flaps/sec
53
+ depthPhase: Math.random() * Math.PI * 2,
54
+ depthRate: 0.08 + Math.random() * 0.08, // 1/12s to 1/6s — 6–12s period
55
+ size: 10 + Math.random() * 18,
56
+ hueShift: (Math.random() - 0.5) * 40,
57
+ alpha: 0.35 + Math.random() * 0.4
58
+ };
59
+ }
60
+
61
+ const butterflies: Butterfly[] = Array.from({ length: COUNT }, spawn);
62
+
63
+ const accentColor = getComputedStyle(document.documentElement)
64
+ .getPropertyValue('--color-accent-500')
65
+ .trim();
66
+
67
+ // Right wing: top + bottom lobe drawn as a single path so their overlap
68
+ // fills once (no alpha accumulation). Positioned so the inner edge sits
69
+ // at +x ≈ 0.05, keeping the two wings from bleeding into each other at
70
+ // the body axis.
71
+ function drawWing(s: number) {
72
+ ctx.beginPath();
73
+ ctx.ellipse(s * 0.65, -s * 0.3, s * 0.6, s * 0.5, -0.25, 0, Math.PI * 2);
74
+ ctx.ellipse(s * 0.55, s * 0.35, s * 0.5, s * 0.4, 0.2, 0, Math.PI * 2);
75
+ ctx.fill();
76
+ }
77
+
78
+ function drawButterfly(b: Butterfly) {
79
+ // Smooth 0→1 flap at the natural flapRate (Hz)
80
+ const flap = (Math.sin(b.flapPhase) + 1) / 2;
81
+ const wingScaleX = 0.45 + 0.55 * flap; // 0.45 (folded) → 1.0 (open)
82
+
83
+ // Combined scale: slow "depth" breathing (±25% over ~10s) plus a tiny
84
+ // bump synced to each wing flap so peak-open wings read as closer.
85
+ const depth = 1 + 0.25 * Math.sin(b.depthPhase);
86
+ const flapBump = 1 + 0.08 * flap;
87
+ const scale = depth * flapBump;
88
+
89
+ ctx.save();
90
+ ctx.translate(b.x, b.y);
91
+ ctx.scale(scale, scale);
92
+ ctx.rotate(b.rotation + Math.PI / 2); // body points along velocity
93
+
94
+ const fill = accentColor
95
+ ? `oklch(from ${accentColor} l c calc(h + ${b.hueShift}) / ${b.alpha})`
96
+ : `rgba(80, 140, 240, ${b.alpha})`;
97
+ ctx.fillStyle = fill;
98
+
99
+ // Right wing
100
+ ctx.save();
101
+ ctx.scale(wingScaleX, 1);
102
+ drawWing(b.size);
103
+ ctx.restore();
104
+
105
+ // Left wing (mirrored)
106
+ ctx.save();
107
+ ctx.scale(-wingScaleX, 1);
108
+ drawWing(b.size);
109
+ ctx.restore();
110
+
111
+ // Tiny body — slightly darker tint of the accent
112
+ ctx.fillStyle = accentColor
113
+ ? `oklch(from ${accentColor} calc(l * 0.55) c calc(h + ${b.hueShift}) / ${Math.min(1, b.alpha + 0.2)})`
114
+ : `rgba(30, 40, 80, ${Math.min(1, b.alpha + 0.2)})`;
115
+ ctx.beginPath();
116
+ ctx.ellipse(0, 0, b.size * 0.08, b.size * 0.55, 0, 0, Math.PI * 2);
117
+ ctx.fill();
118
+
119
+ ctx.restore();
120
+ }
121
+
122
+ let lastTime = performance.now();
123
+
124
+ function draw(now: number) {
125
+ const dt = Math.min((now - lastTime) / 1000, 0.1);
126
+ lastTime = now;
127
+
128
+ const w = canvas!.width;
129
+ const h = canvas!.height;
130
+
131
+ ctx.clearRect(0, 0, w, h);
132
+
133
+ // Framerate-independent turn-toward-heading easing factor.
134
+ const rotationBlend = 1 - Math.exp(-ROTATION_EASE * dt);
135
+ const sqrtDt = Math.sqrt(dt);
136
+
137
+ for (const b of butterflies) {
138
+ b.flapPhase += b.flapRate * 2 * Math.PI * dt;
139
+ b.depthPhase += b.depthRate * 2 * Math.PI * dt;
140
+
141
+ // Heading random walk — sqrt(dt) keeps the per-second angular
142
+ // variance constant regardless of framerate (Brownian scaling).
143
+ b.heading += (Math.random() - 0.5) * 2 * b.turnRate * sqrtDt;
144
+
145
+ // Occasional sharp dart, as a Poisson process at DART_RATE/sec.
146
+ if (Math.random() < DART_RATE * dt) {
147
+ b.heading += (Math.random() - 0.5) * Math.PI;
148
+ }
149
+
150
+ b.x += Math.cos(b.heading) * DRIFT_SPEED * dt;
151
+ b.y += Math.sin(b.heading) * DRIFT_SPEED * dt;
152
+
153
+ // Body orientation eases toward heading with constant time constant.
154
+ let delta = b.heading - b.rotation;
155
+ while (delta > Math.PI) delta -= Math.PI * 2;
156
+ while (delta < -Math.PI) delta += Math.PI * 2;
157
+ b.rotation += delta * rotationBlend;
158
+
159
+ const margin = b.size * 2;
160
+ if (b.x < -margin) b.x = w + margin;
161
+ if (b.x > w + margin) b.x = -margin;
162
+ if (b.y < -margin) b.y = h + margin;
163
+ if (b.y > h + margin) b.y = -margin;
164
+
165
+ drawButterfly(b);
166
+ }
167
+
168
+ animId = requestAnimationFrame(draw);
169
+ }
170
+
171
+ animId = requestAnimationFrame(draw);
172
+
173
+ return () => {
174
+ cancelAnimationFrame(animId);
175
+ window.removeEventListener('resize', resize);
176
+ };
177
+ });
178
+ </script>
179
+
180
+ <div class="bg-base-50 dark:bg-base-900 pointer-events-none fixed inset-0 -z-10">
181
+ <canvas
182
+ bind:this={canvas}
183
+ class="absolute inset-0 h-full w-full opacity-60 blur-[1.5px]"
184
+ ></canvas>
185
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const Butterflies: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Butterflies = ReturnType<typeof Butterflies>;
3
+ export default Butterflies;
@@ -0,0 +1,134 @@
1
+ <script lang="ts">
2
+ import { BROWSER as browser } from 'esm-env';
3
+
4
+ let canvas: HTMLCanvasElement | undefined = $state(undefined);
5
+
6
+ $effect(() => {
7
+ if (!canvas || !browser) return;
8
+
9
+ const ctx = canvas.getContext('2d')!;
10
+ let animId: number;
11
+
12
+ const COUNT = 50;
13
+ const DRIFT_SPEED = 15;
14
+ const PULSE_SPEED = 0.6;
15
+
16
+ interface Firefly {
17
+ x: number;
18
+ y: number;
19
+ vx: number;
20
+ vy: number;
21
+ phase: number;
22
+ pulseRate: number;
23
+ size: number;
24
+ hueShift: number;
25
+ }
26
+
27
+ let lastWidth = 0;
28
+ function resize() {
29
+ const w = window.innerWidth;
30
+ if (w === lastWidth) return;
31
+ lastWidth = w;
32
+ canvas!.width = w;
33
+ canvas!.height = window.screen.height;
34
+ }
35
+ resize();
36
+ window.addEventListener('resize', resize);
37
+
38
+ const flies: Firefly[] = Array.from({ length: COUNT }, () => ({
39
+ x: Math.random() * canvas!.width,
40
+ y: Math.random() * canvas!.height,
41
+ vx: (Math.random() - 0.5) * 2,
42
+ vy: (Math.random() - 0.5) * 2,
43
+ phase: Math.random() * Math.PI * 2,
44
+ pulseRate: PULSE_SPEED * (0.6 + Math.random() * 0.8),
45
+ size: 3 + Math.random() * 5,
46
+ hueShift: (Math.random() - 0.5) * 60 // -30 to +30 degrees
47
+ }));
48
+
49
+ const accentColor = getComputedStyle(document.documentElement)
50
+ .getPropertyValue('--color-accent-500')
51
+ .trim();
52
+
53
+ let lastTime = performance.now();
54
+
55
+ function draw(now: number) {
56
+ const dt = Math.min((now - lastTime) / 1000, 0.1);
57
+ lastTime = now;
58
+
59
+ const w = canvas!.width;
60
+ const h = canvas!.height;
61
+
62
+ ctx.clearRect(0, 0, w, h);
63
+
64
+ for (const fly of flies) {
65
+ fly.phase += fly.pulseRate * dt;
66
+ fly.x += fly.vx * DRIFT_SPEED * dt;
67
+ fly.y += fly.vy * DRIFT_SPEED * dt;
68
+
69
+ fly.vx += (Math.random() - 0.5) * 2 * dt;
70
+ fly.vy += (Math.random() - 0.5) * 2 * dt;
71
+ const len = Math.sqrt(fly.vx * fly.vx + fly.vy * fly.vy);
72
+ if (len > 1) {
73
+ fly.vx /= len;
74
+ fly.vy /= len;
75
+ }
76
+
77
+ if (fly.x < -40) fly.x = w + 40;
78
+ if (fly.x > w + 40) fly.x = -40;
79
+ if (fly.y < -40) fly.y = h + 40;
80
+ if (fly.y > h + 40) fly.y = -40;
81
+
82
+ const glow = (Math.sin(fly.phase) + 1) / 2;
83
+ const alpha = 0.05 + glow * 0.5;
84
+ const radius = fly.size * (0.5 + glow * 0.5);
85
+ const glowRadius = radius * 12;
86
+ const h_shift = fly.hueShift;
87
+
88
+ // Large soft glow
89
+ const gradient = ctx.createRadialGradient(fly.x, fly.y, 0, fly.x, fly.y, glowRadius);
90
+ gradient.addColorStop(
91
+ 0,
92
+ accentColor
93
+ ? `oklch(from ${accentColor} l c calc(h + ${h_shift}) / ${alpha * 0.4})`
94
+ : `rgba(255, 200, 50, ${alpha * 0.4})`
95
+ );
96
+ gradient.addColorStop(
97
+ 0.4,
98
+ accentColor
99
+ ? `oklch(from ${accentColor} l c calc(h + ${h_shift}) / ${alpha * 0.15})`
100
+ : `rgba(255, 200, 50, ${alpha * 0.15})`
101
+ );
102
+ gradient.addColorStop(
103
+ 1,
104
+ accentColor
105
+ ? `oklch(from ${accentColor} l c calc(h + ${h_shift}) / 0)`
106
+ : `rgba(255, 200, 50, 0)`
107
+ );
108
+ ctx.fillStyle = gradient;
109
+ ctx.fillRect(fly.x - glowRadius, fly.y - glowRadius, glowRadius * 2, glowRadius * 2);
110
+
111
+ // Bright core
112
+ ctx.beginPath();
113
+ ctx.arc(fly.x, fly.y, radius, 0, Math.PI * 2);
114
+ ctx.fillStyle = accentColor
115
+ ? `oklch(from ${accentColor} calc(l * 1.4) c calc(h + ${h_shift}) / ${alpha})`
116
+ : `rgba(255, 230, 100, ${alpha})`;
117
+ ctx.fill();
118
+ }
119
+
120
+ animId = requestAnimationFrame(draw);
121
+ }
122
+
123
+ animId = requestAnimationFrame(draw);
124
+
125
+ return () => {
126
+ cancelAnimationFrame(animId);
127
+ window.removeEventListener('resize', resize);
128
+ };
129
+ });
130
+ </script>
131
+
132
+ <div class="bg-base-50 dark:bg-base-900 pointer-events-none fixed inset-0 -z-10">
133
+ <canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-50"></canvas>
134
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const Fireflies: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Fireflies = ReturnType<typeof Fireflies>;
3
+ export default Fireflies;
@@ -0,0 +1,177 @@
1
+ <script lang="ts">
2
+ import { BROWSER as browser } from 'esm-env';
3
+
4
+ let canvas: HTMLCanvasElement | undefined = $state(undefined);
5
+
6
+ $effect(() => {
7
+ if (!canvas || !browser) return;
8
+
9
+ const ctx = canvas.getContext('2d')!;
10
+ let animId: number;
11
+
12
+ const SEGMENTS = 12;
13
+ const ROTATION_SPEED = 0.06;
14
+
15
+ let lastWidth = 0;
16
+ function resize() {
17
+ const w = window.innerWidth;
18
+ if (w === lastWidth) return;
19
+ lastWidth = w;
20
+ canvas!.width = w;
21
+ canvas!.height = window.screen.height;
22
+ }
23
+ resize();
24
+ window.addEventListener('resize', resize);
25
+
26
+ const accentColor = getComputedStyle(document.documentElement)
27
+ .getPropertyValue('--color-accent-500')
28
+ .trim();
29
+
30
+ // Animated blobs in normalized 0-1 space
31
+ const BLOB_COUNT = 20;
32
+ interface Blob {
33
+ x: number;
34
+ y: number;
35
+ vx: number;
36
+ vy: number;
37
+ size: number;
38
+ hueShift: number;
39
+ alpha: number;
40
+ }
41
+
42
+ const blobs: (Blob & { sharp?: boolean })[] = [
43
+ ...Array.from({ length: BLOB_COUNT }, (): Blob => ({
44
+ x: Math.random(),
45
+ y: Math.random() * 0.8,
46
+ vx: (Math.random() - 0.5) * 0.04,
47
+ vy: (Math.random() - 0.5) * 0.04,
48
+ size: 0.04 + Math.random() * 0.1,
49
+ hueShift: (Math.random() - 0.5) * 80,
50
+ alpha: 0.15 + Math.random() * 0.35
51
+ })),
52
+ // Small sharp dots
53
+ ...Array.from({ length: 10 }, () => ({
54
+ x: Math.random(),
55
+ y: Math.random() * 0.8,
56
+ vx: (Math.random() - 0.5) * 0.06,
57
+ vy: (Math.random() - 0.5) * 0.06,
58
+ size: 0.005 + Math.random() * 0.012,
59
+ hueShift: (Math.random() - 0.5) * 80,
60
+ alpha: 0.15 + Math.random() * 0.2,
61
+ sharp: true
62
+ }))
63
+ ];
64
+
65
+ // Offscreen canvas for one triangle slice
66
+ const sliceCanvas = document.createElement('canvas');
67
+ const sliceCtx = sliceCanvas.getContext('2d')!;
68
+
69
+ let lastTime = performance.now();
70
+ let globalRotation = 0;
71
+
72
+ function renderSlice(r: number, dt: number) {
73
+ const segAngle = Math.PI / SEGMENTS; // half of full segment
74
+ const sliceW = Math.ceil(r);
75
+ const sliceH = Math.ceil(Math.sin(segAngle) * r);
76
+
77
+ sliceCanvas.width = sliceW;
78
+ sliceCanvas.height = sliceH;
79
+ sliceCtx.clearRect(0, 0, sliceW, sliceH);
80
+
81
+ // Clip to the triangle
82
+ sliceCtx.save();
83
+ sliceCtx.beginPath();
84
+ sliceCtx.moveTo(0, 0);
85
+ sliceCtx.lineTo(sliceW, 0);
86
+ sliceCtx.lineTo(Math.cos(segAngle) * r, Math.sin(segAngle) * r);
87
+ sliceCtx.closePath();
88
+ sliceCtx.clip();
89
+
90
+ for (const b of blobs) {
91
+ b.x += b.vx * dt;
92
+ b.y += b.vy * dt;
93
+ if (b.x < 0 || b.x > 1) b.vx *= -1;
94
+ if (b.y < 0 || b.y > 1) b.vy *= -1;
95
+ b.x = Math.max(0, Math.min(1, b.x));
96
+ b.y = Math.max(0, Math.min(1, b.y));
97
+
98
+ const px = b.x * sliceW;
99
+ const py = b.y * sliceH;
100
+ const br = b.size * sliceW;
101
+
102
+ if (b.sharp) {
103
+ sliceCtx.fillStyle = accentColor
104
+ ? `oklch(from ${accentColor} calc(l * 1.4) c calc(h + ${b.hueShift}) / ${b.alpha})`
105
+ : `rgba(230, 210, 255, ${b.alpha})`;
106
+ sliceCtx.beginPath();
107
+ sliceCtx.arc(px, py, br, 0, Math.PI * 2);
108
+ sliceCtx.fill();
109
+ } else {
110
+ const g = sliceCtx.createRadialGradient(px, py, 0, px, py, br);
111
+ g.addColorStop(0, accentColor
112
+ ? `oklch(from ${accentColor} calc(l * 1.2) c calc(h + ${b.hueShift}) / ${b.alpha})`
113
+ : `rgba(200, 150, 255, ${b.alpha})`);
114
+ g.addColorStop(0.5, accentColor
115
+ ? `oklch(from ${accentColor} l c calc(h + ${b.hueShift}) / ${b.alpha * 0.3})`
116
+ : `rgba(200, 150, 255, ${b.alpha * 0.3})`);
117
+ g.addColorStop(1, 'transparent');
118
+ sliceCtx.fillStyle = g;
119
+ sliceCtx.fillRect(px - br, py - br, br * 2, br * 2);
120
+ }
121
+ }
122
+
123
+ sliceCtx.restore();
124
+ return { sliceW, sliceH };
125
+ }
126
+
127
+ function draw(now: number) {
128
+ const dt = Math.min((now - lastTime) / 1000, 0.1);
129
+ lastTime = now;
130
+
131
+ const w = canvas!.width;
132
+ const h = canvas!.height;
133
+ const cx = w / 2;
134
+ const cy = h / 2;
135
+ const maxR = Math.hypot(cx, cy);
136
+
137
+ globalRotation += ROTATION_SPEED * dt;
138
+
139
+ renderSlice(maxR, dt);
140
+
141
+ ctx.clearRect(0, 0, w, h);
142
+ ctx.save();
143
+ ctx.translate(cx, cy);
144
+ ctx.rotate(globalRotation);
145
+
146
+ const segAngle = (Math.PI * 2) / SEGMENTS;
147
+
148
+ for (let i = 0; i < SEGMENTS; i++) {
149
+ ctx.save();
150
+ ctx.rotate(segAngle * i);
151
+
152
+ // Normal slice
153
+ ctx.drawImage(sliceCanvas, 0, 0);
154
+
155
+ // Mirrored slice (flip along x-axis to fill the other half)
156
+ ctx.scale(1, -1);
157
+ ctx.drawImage(sliceCanvas, 0, 0);
158
+
159
+ ctx.restore();
160
+ }
161
+
162
+ ctx.restore();
163
+ animId = requestAnimationFrame(draw);
164
+ }
165
+
166
+ animId = requestAnimationFrame(draw);
167
+
168
+ return () => {
169
+ cancelAnimationFrame(animId);
170
+ window.removeEventListener('resize', resize);
171
+ };
172
+ });
173
+ </script>
174
+
175
+ <div class="pointer-events-none fixed inset-0 -z-10 bg-base-50 dark:bg-base-900">
176
+ <canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-50"></canvas>
177
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const Kaleidoscope: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Kaleidoscope = ReturnType<typeof Kaleidoscope>;
3
+ export default Kaleidoscope;