@atmo-dev/kit 0.4.0 → 0.5.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/README.md +35 -0
- package/dist/events/DatePicker.svelte +222 -0
- package/dist/events/DatePicker.svelte.d.ts +12 -0
- package/dist/events/DateTimePicker.svelte +112 -0
- package/dist/events/DateTimePicker.svelte.d.ts +10 -0
- package/dist/events/EventAttendees.svelte +199 -0
- package/dist/events/EventAttendees.svelte.d.ts +19 -0
- package/dist/events/EventCard.svelte +148 -0
- package/dist/events/EventCard.svelte.d.ts +8 -0
- package/dist/events/EventComments.svelte +98 -0
- package/dist/events/EventComments.svelte.d.ts +8 -0
- package/dist/events/EventEditor.svelte +540 -0
- package/dist/events/EventEditor.svelte.d.ts +18 -0
- package/dist/events/EventRsvp.svelte +178 -0
- package/dist/events/EventRsvp.svelte.d.ts +16 -0
- package/dist/events/EventView.svelte +488 -0
- package/dist/events/EventView.svelte.d.ts +23 -0
- package/dist/events/ImageDropper.svelte +66 -0
- package/dist/events/ImageDropper.svelte.d.ts +7 -0
- package/dist/events/Map.svelte +36 -0
- package/dist/events/Map.svelte.d.ts +8 -0
- package/dist/events/PostToBlueskyModal.svelte +246 -0
- package/dist/events/PostToBlueskyModal.svelte.d.ts +22 -0
- package/dist/events/ShareModal.svelte +174 -0
- package/dist/events/ShareModal.svelte.d.ts +23 -0
- package/dist/events/StarterPackButton.svelte +72 -0
- package/dist/events/StarterPackButton.svelte.d.ts +10 -0
- package/dist/events/ThemeApply.svelte +30 -0
- package/dist/events/ThemeApply.svelte.d.ts +7 -0
- package/dist/events/ThemeBackground.svelte +33 -0
- package/dist/events/ThemeBackground.svelte.d.ts +7 -0
- package/dist/events/ThemePicker.svelte +104 -0
- package/dist/events/ThemePicker.svelte.d.ts +7 -0
- package/dist/events/ThumbnailPresets.svelte +71 -0
- package/dist/events/ThumbnailPresets.svelte.d.ts +11 -0
- package/dist/events/TimePicker.svelte +117 -0
- package/dist/events/TimePicker.svelte.d.ts +10 -0
- package/dist/events/TimezonePicker.svelte +67 -0
- package/dist/events/TimezonePicker.svelte.d.ts +6 -0
- package/dist/events/VodPlayer.svelte +154 -0
- package/dist/events/VodPlayer.svelte.d.ts +14 -0
- package/dist/events/VodTranscript.svelte +75 -0
- package/dist/events/VodTranscript.svelte.d.ts +8 -0
- package/dist/events/atproto-helpers.d.ts +21 -0
- package/dist/events/atproto-helpers.js +61 -0
- package/dist/events/cal/helper.d.ts +1 -0
- package/dist/events/cal/helper.js +20 -0
- package/dist/events/cal/ical.d.ts +22 -0
- package/dist/events/cal/ical.js +188 -0
- package/dist/events/cal/sanitize.d.ts +3 -0
- package/dist/events/cal/sanitize.js +25 -0
- package/dist/events/conference.d.ts +65 -0
- package/dist/events/conference.js +61 -0
- package/dist/events/contrail.d.ts +49 -0
- package/dist/events/contrail.js +12 -0
- package/dist/events/date-format.d.ts +22 -0
- package/dist/events/date-format.js +43 -0
- package/dist/events/editor/LinkedRecordsPicker.svelte +104 -0
- package/dist/events/editor/LinkedRecordsPicker.svelte.d.ts +12 -0
- package/dist/events/editor/LinksSection.svelte +154 -0
- package/dist/events/editor/LinksSection.svelte.d.ts +13 -0
- package/dist/events/editor/LocationSection.svelte +163 -0
- package/dist/events/editor/LocationSection.svelte.d.ts +8 -0
- package/dist/events/editor/RecurringModal.svelte +313 -0
- package/dist/events/editor/RecurringModal.svelte.d.ts +30 -0
- package/dist/events/editor/ThemeSection.svelte +24 -0
- package/dist/events/editor/ThemeSection.svelte.d.ts +7 -0
- package/dist/events/editor/ThumbnailSection.svelte +181 -0
- package/dist/events/editor/ThumbnailSection.svelte.d.ts +13 -0
- package/dist/events/editor/adapter.d.ts +73 -0
- package/dist/events/editor/adapter.js +9 -0
- package/dist/events/editor/location.d.ts +16 -0
- package/dist/events/editor/location.js +50 -0
- package/dist/events/editor/save.d.ts +43 -0
- package/dist/events/editor/save.js +168 -0
- package/dist/events/editor/types.d.ts +39 -0
- package/dist/events/editor/types.js +9 -0
- package/dist/events/event-media.d.ts +4 -0
- package/dist/events/event-media.js +4 -0
- package/dist/events/event-types.d.ts +79 -0
- package/dist/events/event-types.js +11 -0
- package/dist/events/event-view/AddToCalendarButton.svelte +31 -0
- package/dist/events/event-view/AddToCalendarButton.svelte.d.ts +9 -0
- package/dist/events/event-view/EventBadges.svelte +20 -0
- package/dist/events/event-view/EventBadges.svelte.d.ts +7 -0
- package/dist/events/event-view/EventDateBlock.svelte +43 -0
- package/dist/events/event-view/EventDateBlock.svelte.d.ts +7 -0
- package/dist/events/event-view/EventHostedBy.svelte +61 -0
- package/dist/events/event-view/EventHostedBy.svelte.d.ts +16 -0
- package/dist/events/event-view/EventLinksList.svelte +24 -0
- package/dist/events/event-view/EventLinksList.svelte.d.ts +9 -0
- package/dist/events/event-view/EventLocationBlock.svelte +62 -0
- package/dist/events/event-view/EventLocationBlock.svelte.d.ts +7 -0
- package/dist/events/event-view/EventLocationMap.svelte +66 -0
- package/dist/events/event-view/EventLocationMap.svelte.d.ts +7 -0
- package/dist/events/event-view/ExternalRsvpNotice.svelte +34 -0
- package/dist/events/event-view/ExternalRsvpNotice.svelte.d.ts +6 -0
- package/dist/events/event-view/StreamPlacePlayer.svelte +209 -0
- package/dist/events/event-view/StreamPlacePlayer.svelte.d.ts +8 -0
- package/dist/events/event-view/format.d.ts +10 -0
- package/dist/events/event-view/format.js +112 -0
- package/dist/events/event-view/locations.d.ts +36 -0
- package/dist/events/event-view/locations.js +243 -0
- package/dist/events/event-view/plyr-icons.d.ts +3 -0
- package/dist/events/event-view/plyr-icons.js +46 -0
- package/dist/events/linked-records.d.ts +18 -0
- package/dist/events/linked-records.js +11 -0
- package/dist/events/profile-url.d.ts +3 -0
- package/dist/events/profile-url.js +11 -0
- package/dist/events/schedule/ConferenceTimetable.svelte +340 -0
- package/dist/events/schedule/ConferenceTimetable.svelte.d.ts +22 -0
- package/dist/events/schedule/DaySchedule.svelte +298 -0
- package/dist/events/schedule/DaySchedule.svelte.d.ts +26 -0
- package/dist/events/schedule/ScheduleEventCell.svelte +166 -0
- package/dist/events/schedule/ScheduleEventCell.svelte.d.ts +25 -0
- package/dist/events/schedule/schedule-utils.d.ts +44 -0
- package/dist/events/schedule/schedule-utils.js +166 -0
- package/dist/events/starter-pack-url.d.ts +3 -0
- package/dist/events/starter-pack-url.js +16 -0
- package/dist/events/theme.d.ts +9 -0
- package/dist/events/theme.js +36 -0
- package/dist/events/themes/Blobs.svelte +64 -0
- package/dist/events/themes/Blobs.svelte.d.ts +18 -0
- package/dist/events/themes/Butterflies.svelte +183 -0
- package/dist/events/themes/Butterflies.svelte.d.ts +3 -0
- package/dist/events/themes/Fireflies.svelte +134 -0
- package/dist/events/themes/Fireflies.svelte.d.ts +3 -0
- package/dist/events/themes/Kaleidoscope.svelte +183 -0
- package/dist/events/themes/Kaleidoscope.svelte.d.ts +3 -0
- package/dist/events/themes/Matrix.svelte +153 -0
- package/dist/events/themes/Matrix.svelte.d.ts +3 -0
- package/dist/events/themes/Stars.svelte +98 -0
- package/dist/events/themes/Stars.svelte.d.ts +3 -0
- package/dist/events/thumbnails/designs.d.ts +18 -0
- package/dist/events/thumbnails/designs.js +316 -0
- package/dist/events/view-data.d.ts +38 -0
- package/dist/events/view-data.js +1 -0
- package/dist/events-data.d.ts +15 -0
- package/dist/events-data.js +9 -0
- package/dist/events-editor.d.ts +2 -0
- package/dist/events-editor.js +2 -0
- package/dist/events.d.ts +19 -0
- package/dist/events.js +17 -0
- package/package.json +46 -4
|
@@ -0,0 +1,183 @@
|
|
|
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(
|
|
112
|
+
0,
|
|
113
|
+
accentColor
|
|
114
|
+
? `oklch(from ${accentColor} calc(l * 1.2) c calc(h + ${b.hueShift}) / ${b.alpha})`
|
|
115
|
+
: `rgba(200, 150, 255, ${b.alpha})`
|
|
116
|
+
);
|
|
117
|
+
g.addColorStop(
|
|
118
|
+
0.5,
|
|
119
|
+
accentColor
|
|
120
|
+
? `oklch(from ${accentColor} l c calc(h + ${b.hueShift}) / ${b.alpha * 0.3})`
|
|
121
|
+
: `rgba(200, 150, 255, ${b.alpha * 0.3})`
|
|
122
|
+
);
|
|
123
|
+
g.addColorStop(1, 'transparent');
|
|
124
|
+
sliceCtx.fillStyle = g;
|
|
125
|
+
sliceCtx.fillRect(px - br, py - br, br * 2, br * 2);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
sliceCtx.restore();
|
|
130
|
+
return { sliceW, sliceH };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function draw(now: number) {
|
|
134
|
+
const dt = Math.min((now - lastTime) / 1000, 0.1);
|
|
135
|
+
lastTime = now;
|
|
136
|
+
|
|
137
|
+
const w = canvas!.width;
|
|
138
|
+
const h = canvas!.height;
|
|
139
|
+
const cx = w / 2;
|
|
140
|
+
const cy = h / 2;
|
|
141
|
+
const maxR = Math.hypot(cx, cy);
|
|
142
|
+
|
|
143
|
+
globalRotation += ROTATION_SPEED * dt;
|
|
144
|
+
|
|
145
|
+
renderSlice(maxR, dt);
|
|
146
|
+
|
|
147
|
+
ctx.clearRect(0, 0, w, h);
|
|
148
|
+
ctx.save();
|
|
149
|
+
ctx.translate(cx, cy);
|
|
150
|
+
ctx.rotate(globalRotation);
|
|
151
|
+
|
|
152
|
+
const segAngle = (Math.PI * 2) / SEGMENTS;
|
|
153
|
+
|
|
154
|
+
for (let i = 0; i < SEGMENTS; i++) {
|
|
155
|
+
ctx.save();
|
|
156
|
+
ctx.rotate(segAngle * i);
|
|
157
|
+
|
|
158
|
+
// Normal slice
|
|
159
|
+
ctx.drawImage(sliceCanvas, 0, 0);
|
|
160
|
+
|
|
161
|
+
// Mirrored slice (flip along x-axis to fill the other half)
|
|
162
|
+
ctx.scale(1, -1);
|
|
163
|
+
ctx.drawImage(sliceCanvas, 0, 0);
|
|
164
|
+
|
|
165
|
+
ctx.restore();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
ctx.restore();
|
|
169
|
+
animId = requestAnimationFrame(draw);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
animId = requestAnimationFrame(draw);
|
|
173
|
+
|
|
174
|
+
return () => {
|
|
175
|
+
cancelAnimationFrame(animId);
|
|
176
|
+
window.removeEventListener('resize', resize);
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
</script>
|
|
180
|
+
|
|
181
|
+
<div class="pointer-events-none fixed inset-0 -z-10 bg-base-50 dark:bg-base-900">
|
|
182
|
+
<canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-50"></canvas>
|
|
183
|
+
</div>
|
|
@@ -0,0 +1,153 @@
|
|
|
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 fontSize = 14;
|
|
13
|
+
const chars =
|
|
14
|
+
'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789ABCDEF';
|
|
15
|
+
|
|
16
|
+
// Speeds in units per second
|
|
17
|
+
const DROP_SPEED = 8; // rows per second
|
|
18
|
+
const FADE_RATE = 2; // alpha per second for trail fade
|
|
19
|
+
const MUTATE_CHANCE = 0.8; // chance per column per second
|
|
20
|
+
|
|
21
|
+
let lastWidth = 0;
|
|
22
|
+
function resize() {
|
|
23
|
+
const w = window.innerWidth;
|
|
24
|
+
if (w === lastWidth) return;
|
|
25
|
+
lastWidth = w;
|
|
26
|
+
canvas!.width = w;
|
|
27
|
+
canvas!.height = window.screen.height;
|
|
28
|
+
}
|
|
29
|
+
resize();
|
|
30
|
+
window.addEventListener('resize', resize);
|
|
31
|
+
|
|
32
|
+
let columns = Math.floor(canvas.width / fontSize);
|
|
33
|
+
let rows = Math.ceil(canvas.height / fontSize) + 1;
|
|
34
|
+
let drops = new Array(columns).fill(0).map(() => Math.random() * -100);
|
|
35
|
+
let grid: string[][] = Array.from({ length: columns }, () =>
|
|
36
|
+
Array.from({ length: rows }, () => chars[Math.floor(Math.random() * chars.length)])
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const accentColor = getComputedStyle(document.documentElement)
|
|
40
|
+
.getPropertyValue('--color-accent-500')
|
|
41
|
+
.trim();
|
|
42
|
+
|
|
43
|
+
let bgColor = '';
|
|
44
|
+
function readBgColor() {
|
|
45
|
+
const isDark = document.documentElement.classList.contains('dark');
|
|
46
|
+
bgColor = getComputedStyle(document.documentElement)
|
|
47
|
+
.getPropertyValue(isDark ? '--color-base-900' : '--color-base-50')
|
|
48
|
+
.trim();
|
|
49
|
+
}
|
|
50
|
+
readBgColor();
|
|
51
|
+
|
|
52
|
+
const themeObserver = new MutationObserver(readBgColor);
|
|
53
|
+
themeObserver.observe(document.documentElement, {
|
|
54
|
+
attributes: true,
|
|
55
|
+
attributeFilter: ['class']
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
let lastResize = canvas.width;
|
|
59
|
+
let lastTime = performance.now();
|
|
60
|
+
|
|
61
|
+
function draw(now: number) {
|
|
62
|
+
const dt = Math.min((now - lastTime) / 1000, 0.1); // delta in seconds, capped
|
|
63
|
+
lastTime = now;
|
|
64
|
+
|
|
65
|
+
const w = canvas!.width;
|
|
66
|
+
const h = canvas!.height;
|
|
67
|
+
|
|
68
|
+
if (w !== lastResize) {
|
|
69
|
+
lastResize = w;
|
|
70
|
+
columns = Math.floor(w / fontSize);
|
|
71
|
+
rows = Math.ceil(h / fontSize) + 1;
|
|
72
|
+
drops = new Array(columns).fill(0).map(() => Math.random() * -100);
|
|
73
|
+
grid = Array.from({ length: columns }, () =>
|
|
74
|
+
Array.from({ length: rows }, () => chars[Math.floor(Math.random() * chars.length)])
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Randomly mutate characters — framerate independent
|
|
79
|
+
const mutatePerFrame = MUTATE_CHANCE * dt;
|
|
80
|
+
for (let m = 0; m < columns; m++) {
|
|
81
|
+
if (Math.random() < mutatePerFrame) {
|
|
82
|
+
const row = Math.floor(Math.random() * rows);
|
|
83
|
+
grid[m][row] = chars[Math.floor(Math.random() * chars.length)];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Fade trail — framerate independent
|
|
88
|
+
const fadeAlpha = Math.min(1, FADE_RATE * dt);
|
|
89
|
+
ctx.fillStyle = bgColor
|
|
90
|
+
? `oklch(from ${bgColor} l c h / ${fadeAlpha})`
|
|
91
|
+
: `rgba(0, 0, 0, ${fadeAlpha})`;
|
|
92
|
+
ctx.fillRect(0, 0, w, h);
|
|
93
|
+
|
|
94
|
+
ctx.font = `${fontSize}px monospace`;
|
|
95
|
+
|
|
96
|
+
const dropStep = DROP_SPEED * dt;
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < columns; i++) {
|
|
99
|
+
if (drops[i] * fontSize > h && Math.random() < 0.5 * dt) {
|
|
100
|
+
drops[i] = 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (drops[i] < 0) {
|
|
104
|
+
drops[i] += dropStep;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const row = Math.floor(drops[i]);
|
|
109
|
+
const y = row * fontSize;
|
|
110
|
+
const gridRow = ((row % rows) + rows) % rows;
|
|
111
|
+
const char = grid[i]?.[gridRow] ?? '0';
|
|
112
|
+
|
|
113
|
+
// Bright head
|
|
114
|
+
ctx.fillStyle = accentColor
|
|
115
|
+
? `oklch(from ${accentColor} calc(l * 1.3) c h / 0.9)`
|
|
116
|
+
: `rgba(150, 255, 150, 0.9)`;
|
|
117
|
+
ctx.fillText(char, i * fontSize, y);
|
|
118
|
+
|
|
119
|
+
// Dimmer trail chars
|
|
120
|
+
for (let t = 1; t < 3; t++) {
|
|
121
|
+
const trailRow = (((gridRow - t) % rows) + rows) % rows;
|
|
122
|
+
const trailY = y - t * fontSize;
|
|
123
|
+
if (trailY < 0) break;
|
|
124
|
+
const trailAlpha = 0.4 - t * 0.12;
|
|
125
|
+
ctx.fillStyle = accentColor
|
|
126
|
+
? `oklch(from ${accentColor} l c h / ${trailAlpha})`
|
|
127
|
+
: `rgba(100, 200, 100, ${trailAlpha})`;
|
|
128
|
+
ctx.fillText(grid[i]?.[trailRow] ?? '0', i * fontSize, trailY);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
drops[i] += dropStep;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
animId = requestAnimationFrame(draw);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Fill initial background
|
|
138
|
+
ctx.fillStyle = bgColor ? `oklch(from ${bgColor} l c h)` : '#000';
|
|
139
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
140
|
+
|
|
141
|
+
animId = requestAnimationFrame(draw);
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
cancelAnimationFrame(animId);
|
|
145
|
+
window.removeEventListener('resize', resize);
|
|
146
|
+
themeObserver.disconnect();
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
</script>
|
|
150
|
+
|
|
151
|
+
<div class="pointer-events-none fixed inset-0 -z-10 bg-base-50 dark:bg-base-900">
|
|
152
|
+
<canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-40"></canvas>
|
|
153
|
+
</div>
|
|
@@ -0,0 +1,98 @@
|
|
|
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 stars: { x: number; y: number; z: number; pz: number }[] = [];
|
|
13
|
+
const COUNT = 600;
|
|
14
|
+
const SPEED = 300; // pixels per second
|
|
15
|
+
|
|
16
|
+
let lastWidth = 0;
|
|
17
|
+
function resize() {
|
|
18
|
+
const w = window.innerWidth;
|
|
19
|
+
if (w === lastWidth) return;
|
|
20
|
+
lastWidth = w;
|
|
21
|
+
canvas!.width = w;
|
|
22
|
+
canvas!.height = window.screen.height;
|
|
23
|
+
}
|
|
24
|
+
resize();
|
|
25
|
+
window.addEventListener('resize', resize);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < COUNT; i++) {
|
|
28
|
+
stars.push({
|
|
29
|
+
x: (Math.random() - 0.5) * canvas.width,
|
|
30
|
+
y: (Math.random() - 0.5) * canvas.height,
|
|
31
|
+
z: Math.random() * canvas.width,
|
|
32
|
+
pz: 0
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
stars.forEach((s) => (s.pz = s.z));
|
|
36
|
+
|
|
37
|
+
const accentColor = getComputedStyle(document.documentElement)
|
|
38
|
+
.getPropertyValue('--color-accent-500')
|
|
39
|
+
.trim();
|
|
40
|
+
|
|
41
|
+
let lastTime = performance.now();
|
|
42
|
+
|
|
43
|
+
function draw(now: number) {
|
|
44
|
+
const dt = Math.min((now - lastTime) / 1000, 0.1);
|
|
45
|
+
lastTime = now;
|
|
46
|
+
|
|
47
|
+
const w = canvas!.width;
|
|
48
|
+
const h = canvas!.height;
|
|
49
|
+
const cx = w / 2;
|
|
50
|
+
const cy = h / 2;
|
|
51
|
+
const speed = SPEED * dt;
|
|
52
|
+
|
|
53
|
+
ctx.clearRect(0, 0, w, h);
|
|
54
|
+
|
|
55
|
+
for (const star of stars) {
|
|
56
|
+
star.pz = star.z;
|
|
57
|
+
star.z -= speed;
|
|
58
|
+
|
|
59
|
+
if (star.z <= 0) {
|
|
60
|
+
star.x = (Math.random() - 0.5) * w;
|
|
61
|
+
star.y = (Math.random() - 0.5) * h;
|
|
62
|
+
star.z = w;
|
|
63
|
+
star.pz = w;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const sx = (star.x / star.z) * w + cx;
|
|
67
|
+
const sy = (star.y / star.z) * h + cy;
|
|
68
|
+
const px = (star.x / star.pz) * w + cx;
|
|
69
|
+
const py = (star.y / star.pz) * h + cy;
|
|
70
|
+
|
|
71
|
+
const size = Math.max(0, (1 - star.z / w) * 4);
|
|
72
|
+
const alpha = Math.max(0, (1 - star.z / w) * 0.9);
|
|
73
|
+
|
|
74
|
+
ctx.beginPath();
|
|
75
|
+
ctx.moveTo(px, py);
|
|
76
|
+
ctx.lineTo(sx, sy);
|
|
77
|
+
ctx.strokeStyle = accentColor
|
|
78
|
+
? `oklch(from ${accentColor} l c h / ${alpha})`
|
|
79
|
+
: `rgba(255,255,255,${alpha})`;
|
|
80
|
+
ctx.lineWidth = size;
|
|
81
|
+
ctx.stroke();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
animId = requestAnimationFrame(draw);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
animId = requestAnimationFrame(draw);
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
cancelAnimationFrame(animId);
|
|
91
|
+
window.removeEventListener('resize', resize);
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<div class="pointer-events-none fixed inset-0 -z-10 bg-base-50 dark:bg-base-900">
|
|
97
|
+
<canvas bind:this={canvas} class="absolute inset-0 h-full w-full opacity-80"></canvas>
|
|
98
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ThumbnailRenderer = (ctx: CanvasRenderingContext2D, w: number, h: number, name: string, dateStr: string, seed: number, accent: string) => void;
|
|
2
|
+
export declare const gradientMesh: ThumbnailRenderer;
|
|
3
|
+
export declare const boldType: ThumbnailRenderer;
|
|
4
|
+
export declare const minimal: ThumbnailRenderer;
|
|
5
|
+
export declare const geometric: ThumbnailRenderer;
|
|
6
|
+
export declare const darkGradient: ThumbnailRenderer;
|
|
7
|
+
export declare const waves: ThumbnailRenderer;
|
|
8
|
+
/** Textless gradient-mesh preset — built from 6 overlapping radial hotspots
|
|
9
|
+
* placed around a loose 3×2 grid with seeded jitter. Used as the default
|
|
10
|
+
* thumbnail for new events. */
|
|
11
|
+
export declare const plainMesh: ThumbnailRenderer;
|
|
12
|
+
export declare const DEFAULT_PRESET = "plain";
|
|
13
|
+
export declare const designs: Record<string, ThumbnailRenderer>;
|
|
14
|
+
export declare function resolveAccentColor(name?: string): string;
|
|
15
|
+
/** Stable non-zero integer seed derived from a string (e.g. an event rkey).
|
|
16
|
+
* Same input always produces the same seed, so the picker preview matches
|
|
17
|
+
* the uploaded PNG for a given event. */
|
|
18
|
+
export declare function hashSeed(s: string): number;
|