+5
-33
docs/todo.md
+5
-33
docs/todo.md
···
26
26
- **(Done) Milestone I**: Social Layer v1: Follow graph, Feeds (Follows/Trending), Forking workflow, and Threaded comments.
27
27
- Full-text search with pg_trgm/unaccent, visibility filtering, and unified search index.
28
28
- Tag taxonomy and Discovery page with top tags.
29
-
30
-
### Milestone J - Static Content & Landing Page
31
-
32
-
#### Deliverables
33
-
34
-
**Marketing/Static Site:**
35
-
36
-
- [x] Landing page with hero section, feature highlights
37
-
- Hero has graph paper/grid background
38
-
- Floating flash cards, notes animations
39
-
- [x] "How it works" section with study flow visualization
40
-
- [x] About page with team/mission
41
-
42
-
**App Vision Content:**
43
-
44
-
- [x] Onboarding flow with persona selection (Learner/Creator/Curator)
45
-
- [x] Empty states with helpful prompts for new users
46
-
- [x] Help center/FAQ section (with beta development notice)
47
-
- [x] Tutorial/walkthrough for first deck creation
48
-
49
-
**SEO & Meta:**
50
-
51
-
- [ ] Open Graph / Twitter Card meta tags
52
-
- [ ] Scripted with HTML2Canvas/PNG generation
53
-
- Graph paper background
54
-
- Floating flash cards, notes (scribbles instead of text)
55
-
- [ ] Sitemap.xml generation
56
-
- [ ] robots.txt configuration
57
-
58
-
#### Acceptance
59
-
60
-
- New visitors understand the value proposition within 10 seconds.
61
-
- Onboarding flow guides users to create their first deck.
29
+
- **(Done) Milestone J**: Static Content & Landing Page.
30
+
- Marketing & Static Site: Landing page, "How it works", About page, Onboarding flow, Empty states, Help center/FAQ section.
31
+
- SEO & Meta: Open Graph / Twitter Card meta tags, Sitemap.xml generation, robots.txt configuration.
32
+
- Onboarding Flow & Help Center/FAQ
33
+
- Empty States
62
34
63
35
### Milestone K - AppView Indexing
64
36
+18
web/index.html
+18
web/index.html
···
6
6
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
<title>Malfestio</title>
9
+
<meta name="description"
10
+
content="Master complex topics with spaced repetition, linked notes, and active recall. Share your decks, notes, and discoveries with the community." />
11
+
12
+
<!-- Open Graph -->
13
+
<meta property="og:type" content="website" />
14
+
<meta property="og:url" content="https://malfestio.stormlightlabs.org/" />
15
+
<meta property="og:title" content="Malfestio — Learning on the AT Protocol" />
16
+
<meta property="og:description"
17
+
content="Master complex topics with spaced repetition, linked notes, and active recall. Share your decks, notes, and discoveries with the community." />
18
+
<meta property="og:image" content="https://malfestio.stormlightlabs.org/og-image.png" />
19
+
20
+
<!-- Twitter Card -->
21
+
<meta name="twitter:card" content="summary_large_image" />
22
+
<meta name="twitter:url" content="https://malfestio.stormlightlabs.org/" />
23
+
<meta name="twitter:title" content="Malfestio — Learning on the AT Protocol" />
24
+
<meta name="twitter:description"
25
+
content="Master complex topics with spaced repetition, linked notes, and active recall. Share your decks, notes, and discoveries with the community." />
26
+
<meta name="twitter:image" content="https://malfestio.stormlightlabs.org/og-image.png" />
9
27
</head>
10
28
11
29
<body>
+6
-2
web/package.json
+6
-2
web/package.json
···
5
5
"type": "module",
6
6
"scripts": {
7
7
"dev": "vite",
8
-
"build": "tsc -b && vite build",
8
+
"build": "pnpm run generate:og && tsc -b && vite build",
9
9
"preview": "vite preview",
10
10
"test": "vitest",
11
11
"check": "tsc --noEmit --project tsconfig.app.json",
12
-
"lint": "eslint ."
12
+
"lint": "eslint .",
13
+
"generate:og": "tsx scripts/generate-og-image.ts"
13
14
},
14
15
"dependencies": {
15
16
"@fontsource-variable/figtree": "^5.2.8",
···
34
35
"@egoist/tailwindcss-icons": "^1.9.0",
35
36
"@eslint/js": "^9.39.2",
36
37
"@iconify-json/bi": "^1.2.7",
38
+
"@resvg/resvg-js": "^2.6.2",
37
39
"@solidjs/testing-library": "^0.8.10",
38
40
"@testing-library/jest-dom": "^6.9.1",
39
41
"@testing-library/user-event": "^14.6.1",
···
43
45
"eslint-plugin-solid": "^0.14.5",
44
46
"globals": "^16.5.0",
45
47
"jsdom": "^27.4.0",
48
+
"satori": "^0.18.3",
49
+
"tsx": "^4.21.0",
46
50
"typescript": "~5.9.3",
47
51
"typescript-eslint": "^8.50.1",
48
52
"vite": "npm:rolldown-vite@7.2.5",
+587
-17
web/pnpm-lock.yaml
+587
-17
web/pnpm-lock.yaml
···
25
25
version: 0.15.4(solid-js@1.9.10)
26
26
'@tailwindcss/vite':
27
27
specifier: ^4.1.18
28
-
version: 4.1.18(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))
28
+
version: 4.1.18(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))
29
29
clsx:
30
30
specifier: ^2.1.1
31
31
version: 2.1.1
···
72
72
'@iconify-json/bi':
73
73
specifier: ^1.2.7
74
74
version: 1.2.7
75
+
'@resvg/resvg-js':
76
+
specifier: ^2.6.2
77
+
version: 2.6.2
75
78
'@solidjs/testing-library':
76
79
specifier: ^0.8.10
77
80
version: 0.8.10(@solidjs/router@0.15.4(solid-js@1.9.10))(solid-js@1.9.10)
···
99
102
jsdom:
100
103
specifier: ^27.4.0
101
104
version: 27.4.0
105
+
satori:
106
+
specifier: ^0.18.3
107
+
version: 0.18.3
108
+
tsx:
109
+
specifier: ^4.21.0
110
+
version: 4.21.0
102
111
typescript:
103
112
specifier: ~5.9.3
104
113
version: 5.9.3
···
107
116
version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
108
117
vite:
109
118
specifier: npm:rolldown-vite@7.2.5
110
-
version: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)
119
+
version: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)
111
120
vite-plugin-solid:
112
121
specifier: ^2.11.10
113
-
version: 2.11.10(@testing-library/jest-dom@6.9.1)(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))(solid-js@1.9.10)
122
+
version: 2.11.10(@testing-library/jest-dom@6.9.1)(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))(solid-js@1.9.10)
114
123
vitest:
115
124
specifier: ^4.0.16
116
-
version: 4.0.16(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.4.0)
125
+
version: 4.0.16(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0)
117
126
118
127
packages:
119
128
···
269
278
'@emnapi/wasi-threads@1.1.0':
270
279
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
271
280
281
+
'@esbuild/aix-ppc64@0.27.2':
282
+
resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==}
283
+
engines: {node: '>=18'}
284
+
cpu: [ppc64]
285
+
os: [aix]
286
+
287
+
'@esbuild/android-arm64@0.27.2':
288
+
resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==}
289
+
engines: {node: '>=18'}
290
+
cpu: [arm64]
291
+
os: [android]
292
+
293
+
'@esbuild/android-arm@0.27.2':
294
+
resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==}
295
+
engines: {node: '>=18'}
296
+
cpu: [arm]
297
+
os: [android]
298
+
299
+
'@esbuild/android-x64@0.27.2':
300
+
resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==}
301
+
engines: {node: '>=18'}
302
+
cpu: [x64]
303
+
os: [android]
304
+
305
+
'@esbuild/darwin-arm64@0.27.2':
306
+
resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==}
307
+
engines: {node: '>=18'}
308
+
cpu: [arm64]
309
+
os: [darwin]
310
+
311
+
'@esbuild/darwin-x64@0.27.2':
312
+
resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==}
313
+
engines: {node: '>=18'}
314
+
cpu: [x64]
315
+
os: [darwin]
316
+
317
+
'@esbuild/freebsd-arm64@0.27.2':
318
+
resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==}
319
+
engines: {node: '>=18'}
320
+
cpu: [arm64]
321
+
os: [freebsd]
322
+
323
+
'@esbuild/freebsd-x64@0.27.2':
324
+
resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==}
325
+
engines: {node: '>=18'}
326
+
cpu: [x64]
327
+
os: [freebsd]
328
+
329
+
'@esbuild/linux-arm64@0.27.2':
330
+
resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==}
331
+
engines: {node: '>=18'}
332
+
cpu: [arm64]
333
+
os: [linux]
334
+
335
+
'@esbuild/linux-arm@0.27.2':
336
+
resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==}
337
+
engines: {node: '>=18'}
338
+
cpu: [arm]
339
+
os: [linux]
340
+
341
+
'@esbuild/linux-ia32@0.27.2':
342
+
resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==}
343
+
engines: {node: '>=18'}
344
+
cpu: [ia32]
345
+
os: [linux]
346
+
347
+
'@esbuild/linux-loong64@0.27.2':
348
+
resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==}
349
+
engines: {node: '>=18'}
350
+
cpu: [loong64]
351
+
os: [linux]
352
+
353
+
'@esbuild/linux-mips64el@0.27.2':
354
+
resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==}
355
+
engines: {node: '>=18'}
356
+
cpu: [mips64el]
357
+
os: [linux]
358
+
359
+
'@esbuild/linux-ppc64@0.27.2':
360
+
resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==}
361
+
engines: {node: '>=18'}
362
+
cpu: [ppc64]
363
+
os: [linux]
364
+
365
+
'@esbuild/linux-riscv64@0.27.2':
366
+
resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==}
367
+
engines: {node: '>=18'}
368
+
cpu: [riscv64]
369
+
os: [linux]
370
+
371
+
'@esbuild/linux-s390x@0.27.2':
372
+
resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==}
373
+
engines: {node: '>=18'}
374
+
cpu: [s390x]
375
+
os: [linux]
376
+
377
+
'@esbuild/linux-x64@0.27.2':
378
+
resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==}
379
+
engines: {node: '>=18'}
380
+
cpu: [x64]
381
+
os: [linux]
382
+
383
+
'@esbuild/netbsd-arm64@0.27.2':
384
+
resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==}
385
+
engines: {node: '>=18'}
386
+
cpu: [arm64]
387
+
os: [netbsd]
388
+
389
+
'@esbuild/netbsd-x64@0.27.2':
390
+
resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==}
391
+
engines: {node: '>=18'}
392
+
cpu: [x64]
393
+
os: [netbsd]
394
+
395
+
'@esbuild/openbsd-arm64@0.27.2':
396
+
resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==}
397
+
engines: {node: '>=18'}
398
+
cpu: [arm64]
399
+
os: [openbsd]
400
+
401
+
'@esbuild/openbsd-x64@0.27.2':
402
+
resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==}
403
+
engines: {node: '>=18'}
404
+
cpu: [x64]
405
+
os: [openbsd]
406
+
407
+
'@esbuild/openharmony-arm64@0.27.2':
408
+
resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==}
409
+
engines: {node: '>=18'}
410
+
cpu: [arm64]
411
+
os: [openharmony]
412
+
413
+
'@esbuild/sunos-x64@0.27.2':
414
+
resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==}
415
+
engines: {node: '>=18'}
416
+
cpu: [x64]
417
+
os: [sunos]
418
+
419
+
'@esbuild/win32-arm64@0.27.2':
420
+
resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==}
421
+
engines: {node: '>=18'}
422
+
cpu: [arm64]
423
+
os: [win32]
424
+
425
+
'@esbuild/win32-ia32@0.27.2':
426
+
resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==}
427
+
engines: {node: '>=18'}
428
+
cpu: [ia32]
429
+
os: [win32]
430
+
431
+
'@esbuild/win32-x64@0.27.2':
432
+
resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==}
433
+
engines: {node: '>=18'}
434
+
cpu: [x64]
435
+
os: [win32]
436
+
272
437
'@eslint-community/eslint-utils@4.9.0':
273
438
resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==}
274
439
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
···
391
556
'@oxc-project/types@0.97.0':
392
557
resolution: {integrity: sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ==}
393
558
559
+
'@resvg/resvg-js-android-arm-eabi@2.6.2':
560
+
resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==}
561
+
engines: {node: '>= 10'}
562
+
cpu: [arm]
563
+
os: [android]
564
+
565
+
'@resvg/resvg-js-android-arm64@2.6.2':
566
+
resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==}
567
+
engines: {node: '>= 10'}
568
+
cpu: [arm64]
569
+
os: [android]
570
+
571
+
'@resvg/resvg-js-darwin-arm64@2.6.2':
572
+
resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==}
573
+
engines: {node: '>= 10'}
574
+
cpu: [arm64]
575
+
os: [darwin]
576
+
577
+
'@resvg/resvg-js-darwin-x64@2.6.2':
578
+
resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==}
579
+
engines: {node: '>= 10'}
580
+
cpu: [x64]
581
+
os: [darwin]
582
+
583
+
'@resvg/resvg-js-linux-arm-gnueabihf@2.6.2':
584
+
resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==}
585
+
engines: {node: '>= 10'}
586
+
cpu: [arm]
587
+
os: [linux]
588
+
589
+
'@resvg/resvg-js-linux-arm64-gnu@2.6.2':
590
+
resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==}
591
+
engines: {node: '>= 10'}
592
+
cpu: [arm64]
593
+
os: [linux]
594
+
595
+
'@resvg/resvg-js-linux-arm64-musl@2.6.2':
596
+
resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==}
597
+
engines: {node: '>= 10'}
598
+
cpu: [arm64]
599
+
os: [linux]
600
+
601
+
'@resvg/resvg-js-linux-x64-gnu@2.6.2':
602
+
resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==}
603
+
engines: {node: '>= 10'}
604
+
cpu: [x64]
605
+
os: [linux]
606
+
607
+
'@resvg/resvg-js-linux-x64-musl@2.6.2':
608
+
resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==}
609
+
engines: {node: '>= 10'}
610
+
cpu: [x64]
611
+
os: [linux]
612
+
613
+
'@resvg/resvg-js-win32-arm64-msvc@2.6.2':
614
+
resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==}
615
+
engines: {node: '>= 10'}
616
+
cpu: [arm64]
617
+
os: [win32]
618
+
619
+
'@resvg/resvg-js-win32-ia32-msvc@2.6.2':
620
+
resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==}
621
+
engines: {node: '>= 10'}
622
+
cpu: [ia32]
623
+
os: [win32]
624
+
625
+
'@resvg/resvg-js-win32-x64-msvc@2.6.2':
626
+
resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==}
627
+
engines: {node: '>= 10'}
628
+
cpu: [x64]
629
+
os: [win32]
630
+
631
+
'@resvg/resvg-js@2.6.2':
632
+
resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==}
633
+
engines: {node: '>= 10'}
634
+
394
635
'@rolldown/binding-android-arm64@1.0.0-beta.50':
395
636
resolution: {integrity: sha512-XlEkrOIHLyGT3avOgzfTFSjG+f+dZMw+/qd+Y3HLN86wlndrB/gSimrJCk4gOhr1XtRtEKfszpadI3Md4Z4/Ag==}
396
637
engines: {node: ^20.19.0 || >=22.12.0}
···
476
717
477
718
'@rolldown/pluginutils@1.0.0-beta.50':
478
719
resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==}
720
+
721
+
'@shuding/opentype.js@1.4.0-beta.0':
722
+
resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
723
+
engines: {node: '>= 8.0.0'}
724
+
hasBin: true
479
725
480
726
'@solid-primitives/props@3.2.2':
481
727
resolution: {integrity: sha512-lZOTwFJajBrshSyg14nBMEP0h8MXzPowGO0s3OeiR3z6nXHTfj0FhzDtJMv+VYoRJKQHG2QRnJTgCzK6erARAw==}
···
826
1072
balanced-match@1.0.2:
827
1073
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
828
1074
1075
+
base64-js@0.0.8:
1076
+
resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==}
1077
+
engines: {node: '>= 0.4'}
1078
+
829
1079
baseline-browser-mapping@2.9.11:
830
1080
resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==}
831
1081
hasBin: true
···
847
1097
callsites@3.1.0:
848
1098
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
849
1099
engines: {node: '>=6'}
1100
+
1101
+
camelize@1.0.1:
1102
+
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
850
1103
851
1104
caniuse-lite@1.0.30001761:
852
1105
resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==}
···
901
1154
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
902
1155
engines: {node: '>= 8'}
903
1156
1157
+
css-background-parser@0.1.0:
1158
+
resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==}
1159
+
1160
+
css-box-shadow@1.0.0-3:
1161
+
resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==}
1162
+
1163
+
css-color-keywords@1.0.0:
1164
+
resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==}
1165
+
engines: {node: '>=4'}
1166
+
1167
+
css-gradient-parser@0.0.17:
1168
+
resolution: {integrity: sha512-w2Xy9UMMwlKtou0vlRnXvWglPAceXCTtcmVSo8ZBUvqCV5aXEFP/PC6d+I464810I9FT++UACwTD5511bmGPUg==}
1169
+
engines: {node: '>=16'}
1170
+
1171
+
css-to-react-native@3.2.0:
1172
+
resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==}
1173
+
904
1174
css-tree@3.1.0:
905
1175
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
906
1176
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
···
957
1227
electron-to-chromium@1.5.267:
958
1228
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
959
1229
1230
+
emoji-regex-xs@2.0.1:
1231
+
resolution: {integrity: sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==}
1232
+
engines: {node: '>=10.0.0'}
1233
+
960
1234
enhanced-resolve@5.18.4:
961
1235
resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
962
1236
engines: {node: '>=10.13.0'}
···
968
1242
es-module-lexer@1.7.0:
969
1243
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
970
1244
1245
+
esbuild@0.27.2:
1246
+
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
1247
+
engines: {node: '>=18'}
1248
+
hasBin: true
1249
+
971
1250
escalade@3.2.0:
972
1251
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
973
1252
engines: {node: '>=6'}
1253
+
1254
+
escape-html@1.0.3:
1255
+
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
974
1256
975
1257
escape-string-regexp@4.0.0:
976
1258
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
···
1056
1338
picomatch:
1057
1339
optional: true
1058
1340
1341
+
fflate@0.7.4:
1342
+
resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==}
1343
+
1059
1344
file-entry-cache@8.0.0:
1060
1345
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
1061
1346
engines: {node: '>=16.0.0'}
···
1093
1378
gensync@1.0.0-beta.2:
1094
1379
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
1095
1380
engines: {node: '>=6.9.0'}
1381
+
1382
+
get-tsconfig@4.13.0:
1383
+
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
1096
1384
1097
1385
glob-parent@6.0.2:
1098
1386
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
···
1128
1416
1129
1417
hast-util-whitespace@3.0.0:
1130
1418
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
1419
+
1420
+
hex-rgb@4.3.0:
1421
+
resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==}
1422
+
engines: {node: '>=6'}
1131
1423
1132
1424
hey-listen@1.0.8:
1133
1425
resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
···
1332
1624
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
1333
1625
engines: {node: '>= 12.0.0'}
1334
1626
1627
+
linebreak@1.1.0:
1628
+
resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==}
1629
+
1335
1630
local-pkg@1.1.2:
1336
1631
resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
1337
1632
engines: {node: '>=14'}
···
1502
1797
package-manager-detector@1.6.0:
1503
1798
resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
1504
1799
1800
+
pako@0.2.9:
1801
+
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
1802
+
1505
1803
parent-module@1.0.1:
1506
1804
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
1507
1805
engines: {node: '>=6'}
1806
+
1807
+
parse-css-color@0.2.1:
1808
+
resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==}
1508
1809
1509
1810
parse5@7.3.0:
1510
1811
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
···
1535
1836
1536
1837
pkg-types@2.3.0:
1537
1838
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
1839
+
1840
+
postcss-value-parser@4.2.0:
1841
+
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
1538
1842
1539
1843
postcss@8.5.6:
1540
1844
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
···
1588
1892
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
1589
1893
engines: {node: '>=4'}
1590
1894
1895
+
resolve-pkg-maps@1.0.0:
1896
+
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
1897
+
1591
1898
rolldown-vite@7.2.5:
1592
1899
resolution: {integrity: sha512-u09tdk/huMiN8xwoiBbig197jKdCamQTtOruSalOzbqGje3jdHiV0njQlAW0YvzoahkirFePNQ4RYlfnRQpXZA==}
1593
1900
engines: {node: ^20.19.0 || >=22.12.0}
···
1632
1939
resolution: {integrity: sha512-JFULvCNl/anKn99eKjOSEubi0lLmNqQDAjyEMME2T4CwezUDL0i6t1O9xZsu2OMehPnV2caNefWpGF+8TnzB6A==}
1633
1940
engines: {node: ^20.19.0 || >=22.12.0}
1634
1941
hasBin: true
1942
+
1943
+
satori@0.18.3:
1944
+
resolution: {integrity: sha512-T3DzWNmnrfVmk2gCIlAxLRLbGkfp3K7TyRva+Byyojqu83BNvnMeqVeYRdmUw4TKCsyH4RiQ/KuF/I4yEzgR5A==}
1945
+
engines: {node: '>=16'}
1635
1946
1636
1947
saxes@6.0.0:
1637
1948
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
···
1693
2004
std-env@3.10.0:
1694
2005
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
1695
2006
2007
+
string.prototype.codepointat@0.2.1:
2008
+
resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==}
2009
+
1696
2010
stringify-entities@4.0.4:
1697
2011
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
1698
2012
···
1723
2037
tapable@2.3.0:
1724
2038
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
1725
2039
engines: {node: '>=6'}
2040
+
2041
+
tiny-inflate@1.0.3:
2042
+
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
1726
2043
1727
2044
tinybench@2.9.0:
1728
2045
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
···
1769
2086
tslib@2.8.1:
1770
2087
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
1771
2088
2089
+
tsx@4.21.0:
2090
+
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
2091
+
engines: {node: '>=18.0.0'}
2092
+
hasBin: true
2093
+
1772
2094
type-check@0.4.0:
1773
2095
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
1774
2096
engines: {node: '>= 0.8.0'}
···
1791
2113
undici-types@7.16.0:
1792
2114
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
1793
2115
2116
+
unicode-trie@2.0.0:
2117
+
resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
2118
+
1794
2119
unified@11.0.5:
1795
2120
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
1796
2121
···
1931
2256
yocto-queue@0.1.0:
1932
2257
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
1933
2258
engines: {node: '>=10'}
2259
+
2260
+
yoga-layout@3.2.1:
2261
+
resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==}
1934
2262
1935
2263
zwitch@2.0.4:
1936
2264
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
···
2124
2452
tslib: 2.8.1
2125
2453
optional: true
2126
2454
2455
+
'@esbuild/aix-ppc64@0.27.2':
2456
+
optional: true
2457
+
2458
+
'@esbuild/android-arm64@0.27.2':
2459
+
optional: true
2460
+
2461
+
'@esbuild/android-arm@0.27.2':
2462
+
optional: true
2463
+
2464
+
'@esbuild/android-x64@0.27.2':
2465
+
optional: true
2466
+
2467
+
'@esbuild/darwin-arm64@0.27.2':
2468
+
optional: true
2469
+
2470
+
'@esbuild/darwin-x64@0.27.2':
2471
+
optional: true
2472
+
2473
+
'@esbuild/freebsd-arm64@0.27.2':
2474
+
optional: true
2475
+
2476
+
'@esbuild/freebsd-x64@0.27.2':
2477
+
optional: true
2478
+
2479
+
'@esbuild/linux-arm64@0.27.2':
2480
+
optional: true
2481
+
2482
+
'@esbuild/linux-arm@0.27.2':
2483
+
optional: true
2484
+
2485
+
'@esbuild/linux-ia32@0.27.2':
2486
+
optional: true
2487
+
2488
+
'@esbuild/linux-loong64@0.27.2':
2489
+
optional: true
2490
+
2491
+
'@esbuild/linux-mips64el@0.27.2':
2492
+
optional: true
2493
+
2494
+
'@esbuild/linux-ppc64@0.27.2':
2495
+
optional: true
2496
+
2497
+
'@esbuild/linux-riscv64@0.27.2':
2498
+
optional: true
2499
+
2500
+
'@esbuild/linux-s390x@0.27.2':
2501
+
optional: true
2502
+
2503
+
'@esbuild/linux-x64@0.27.2':
2504
+
optional: true
2505
+
2506
+
'@esbuild/netbsd-arm64@0.27.2':
2507
+
optional: true
2508
+
2509
+
'@esbuild/netbsd-x64@0.27.2':
2510
+
optional: true
2511
+
2512
+
'@esbuild/openbsd-arm64@0.27.2':
2513
+
optional: true
2514
+
2515
+
'@esbuild/openbsd-x64@0.27.2':
2516
+
optional: true
2517
+
2518
+
'@esbuild/openharmony-arm64@0.27.2':
2519
+
optional: true
2520
+
2521
+
'@esbuild/sunos-x64@0.27.2':
2522
+
optional: true
2523
+
2524
+
'@esbuild/win32-arm64@0.27.2':
2525
+
optional: true
2526
+
2527
+
'@esbuild/win32-ia32@0.27.2':
2528
+
optional: true
2529
+
2530
+
'@esbuild/win32-x64@0.27.2':
2531
+
optional: true
2532
+
2127
2533
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))':
2128
2534
dependencies:
2129
2535
eslint: 9.39.2(jiti@2.6.1)
···
2271
2677
2272
2678
'@oxc-project/types@0.97.0': {}
2273
2679
2680
+
'@resvg/resvg-js-android-arm-eabi@2.6.2':
2681
+
optional: true
2682
+
2683
+
'@resvg/resvg-js-android-arm64@2.6.2':
2684
+
optional: true
2685
+
2686
+
'@resvg/resvg-js-darwin-arm64@2.6.2':
2687
+
optional: true
2688
+
2689
+
'@resvg/resvg-js-darwin-x64@2.6.2':
2690
+
optional: true
2691
+
2692
+
'@resvg/resvg-js-linux-arm-gnueabihf@2.6.2':
2693
+
optional: true
2694
+
2695
+
'@resvg/resvg-js-linux-arm64-gnu@2.6.2':
2696
+
optional: true
2697
+
2698
+
'@resvg/resvg-js-linux-arm64-musl@2.6.2':
2699
+
optional: true
2700
+
2701
+
'@resvg/resvg-js-linux-x64-gnu@2.6.2':
2702
+
optional: true
2703
+
2704
+
'@resvg/resvg-js-linux-x64-musl@2.6.2':
2705
+
optional: true
2706
+
2707
+
'@resvg/resvg-js-win32-arm64-msvc@2.6.2':
2708
+
optional: true
2709
+
2710
+
'@resvg/resvg-js-win32-ia32-msvc@2.6.2':
2711
+
optional: true
2712
+
2713
+
'@resvg/resvg-js-win32-x64-msvc@2.6.2':
2714
+
optional: true
2715
+
2716
+
'@resvg/resvg-js@2.6.2':
2717
+
optionalDependencies:
2718
+
'@resvg/resvg-js-android-arm-eabi': 2.6.2
2719
+
'@resvg/resvg-js-android-arm64': 2.6.2
2720
+
'@resvg/resvg-js-darwin-arm64': 2.6.2
2721
+
'@resvg/resvg-js-darwin-x64': 2.6.2
2722
+
'@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2
2723
+
'@resvg/resvg-js-linux-arm64-gnu': 2.6.2
2724
+
'@resvg/resvg-js-linux-arm64-musl': 2.6.2
2725
+
'@resvg/resvg-js-linux-x64-gnu': 2.6.2
2726
+
'@resvg/resvg-js-linux-x64-musl': 2.6.2
2727
+
'@resvg/resvg-js-win32-arm64-msvc': 2.6.2
2728
+
'@resvg/resvg-js-win32-ia32-msvc': 2.6.2
2729
+
'@resvg/resvg-js-win32-x64-msvc': 2.6.2
2730
+
2274
2731
'@rolldown/binding-android-arm64@1.0.0-beta.50':
2275
2732
optional: true
2276
2733
···
2316
2773
optional: true
2317
2774
2318
2775
'@rolldown/pluginutils@1.0.0-beta.50': {}
2776
+
2777
+
'@shuding/opentype.js@1.4.0-beta.0':
2778
+
dependencies:
2779
+
fflate: 0.7.4
2780
+
string.prototype.codepointat: 0.2.1
2319
2781
2320
2782
'@solid-primitives/props@3.2.2(solid-js@1.9.10)':
2321
2783
dependencies:
···
2413
2875
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
2414
2876
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
2415
2877
2416
-
'@tailwindcss/vite@4.1.18(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))':
2878
+
'@tailwindcss/vite@4.1.18(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))':
2417
2879
dependencies:
2418
2880
'@tailwindcss/node': 4.1.18
2419
2881
'@tailwindcss/oxide': 4.1.18
2420
2882
tailwindcss: 4.1.18
2421
-
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)
2883
+
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)
2422
2884
2423
2885
'@testing-library/dom@10.4.1':
2424
2886
dependencies:
···
2605
3067
chai: 6.2.2
2606
3068
tinyrainbow: 3.0.3
2607
3069
2608
-
'@vitest/mocker@4.0.16(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))':
3070
+
'@vitest/mocker@4.0.16(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))':
2609
3071
dependencies:
2610
3072
'@vitest/spy': 4.0.16
2611
3073
estree-walker: 3.0.3
2612
3074
magic-string: 0.30.21
2613
3075
optionalDependencies:
2614
-
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)
3076
+
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)
2615
3077
2616
3078
'@vitest/pretty-format@4.0.16':
2617
3079
dependencies:
···
2688
3150
2689
3151
balanced-match@1.0.2: {}
2690
3152
3153
+
base64-js@0.0.8: {}
3154
+
2691
3155
baseline-browser-mapping@2.9.11: {}
2692
3156
2693
3157
bidi-js@1.0.3:
···
2712
3176
update-browserslist-db: 1.2.3(browserslist@4.28.1)
2713
3177
2714
3178
callsites@3.1.0: {}
3179
+
3180
+
camelize@1.0.1: {}
2715
3181
2716
3182
caniuse-lite@1.0.30001761: {}
2717
3183
···
2754
3220
shebang-command: 2.0.0
2755
3221
which: 2.0.2
2756
3222
3223
+
css-background-parser@0.1.0: {}
3224
+
3225
+
css-box-shadow@1.0.0-3: {}
3226
+
3227
+
css-color-keywords@1.0.0: {}
3228
+
3229
+
css-gradient-parser@0.0.17: {}
3230
+
3231
+
css-to-react-native@3.2.0:
3232
+
dependencies:
3233
+
camelize: 1.0.1
3234
+
css-color-keywords: 1.0.0
3235
+
postcss-value-parser: 4.2.0
3236
+
2757
3237
css-tree@3.1.0:
2758
3238
dependencies:
2759
3239
mdn-data: 2.12.2
···
2800
3280
2801
3281
electron-to-chromium@1.5.267: {}
2802
3282
3283
+
emoji-regex-xs@2.0.1: {}
3284
+
2803
3285
enhanced-resolve@5.18.4:
2804
3286
dependencies:
2805
3287
graceful-fs: 4.2.11
···
2809
3291
2810
3292
es-module-lexer@1.7.0: {}
2811
3293
3294
+
esbuild@0.27.2:
3295
+
optionalDependencies:
3296
+
'@esbuild/aix-ppc64': 0.27.2
3297
+
'@esbuild/android-arm': 0.27.2
3298
+
'@esbuild/android-arm64': 0.27.2
3299
+
'@esbuild/android-x64': 0.27.2
3300
+
'@esbuild/darwin-arm64': 0.27.2
3301
+
'@esbuild/darwin-x64': 0.27.2
3302
+
'@esbuild/freebsd-arm64': 0.27.2
3303
+
'@esbuild/freebsd-x64': 0.27.2
3304
+
'@esbuild/linux-arm': 0.27.2
3305
+
'@esbuild/linux-arm64': 0.27.2
3306
+
'@esbuild/linux-ia32': 0.27.2
3307
+
'@esbuild/linux-loong64': 0.27.2
3308
+
'@esbuild/linux-mips64el': 0.27.2
3309
+
'@esbuild/linux-ppc64': 0.27.2
3310
+
'@esbuild/linux-riscv64': 0.27.2
3311
+
'@esbuild/linux-s390x': 0.27.2
3312
+
'@esbuild/linux-x64': 0.27.2
3313
+
'@esbuild/netbsd-arm64': 0.27.2
3314
+
'@esbuild/netbsd-x64': 0.27.2
3315
+
'@esbuild/openbsd-arm64': 0.27.2
3316
+
'@esbuild/openbsd-x64': 0.27.2
3317
+
'@esbuild/openharmony-arm64': 0.27.2
3318
+
'@esbuild/sunos-x64': 0.27.2
3319
+
'@esbuild/win32-arm64': 0.27.2
3320
+
'@esbuild/win32-ia32': 0.27.2
3321
+
'@esbuild/win32-x64': 0.27.2
3322
+
2812
3323
escalade@3.2.0: {}
3324
+
3325
+
escape-html@1.0.3: {}
2813
3326
2814
3327
escape-string-regexp@4.0.0: {}
2815
3328
···
2914
3427
optionalDependencies:
2915
3428
picomatch: 4.0.3
2916
3429
3430
+
fflate@0.7.4: {}
3431
+
2917
3432
file-entry-cache@8.0.0:
2918
3433
dependencies:
2919
3434
flat-cache: 4.0.1
···
2940
3455
optional: true
2941
3456
2942
3457
gensync@1.0.0-beta.2: {}
3458
+
3459
+
get-tsconfig@4.13.0:
3460
+
dependencies:
3461
+
resolve-pkg-maps: 1.0.0
2943
3462
2944
3463
glob-parent@6.0.2:
2945
3464
dependencies:
···
2982
3501
hast-util-whitespace@3.0.0:
2983
3502
dependencies:
2984
3503
'@types/hast': 3.0.4
3504
+
3505
+
hex-rgb@4.3.0: {}
2985
3506
2986
3507
hey-listen@1.0.8: {}
2987
3508
···
3156
3677
lightningcss-win32-arm64-msvc: 1.30.2
3157
3678
lightningcss-win32-x64-msvc: 1.30.2
3158
3679
3680
+
linebreak@1.1.0:
3681
+
dependencies:
3682
+
base64-js: 0.0.8
3683
+
unicode-trie: 2.0.0
3684
+
3159
3685
local-pkg@1.1.2:
3160
3686
dependencies:
3161
3687
mlly: 1.8.0
···
3409
3935
3410
3936
package-manager-detector@1.6.0: {}
3411
3937
3938
+
pako@0.2.9: {}
3939
+
3412
3940
parent-module@1.0.1:
3413
3941
dependencies:
3414
3942
callsites: 3.1.0
3415
3943
3944
+
parse-css-color@0.2.1:
3945
+
dependencies:
3946
+
color-name: 1.1.4
3947
+
hex-rgb: 4.3.0
3948
+
3416
3949
parse5@7.3.0:
3417
3950
dependencies:
3418
3951
entities: 6.0.1
···
3442
3975
confbox: 0.2.2
3443
3976
exsolve: 1.0.8
3444
3977
pathe: 2.0.3
3978
+
3979
+
postcss-value-parser@4.2.0: {}
3445
3980
3446
3981
postcss@8.5.6:
3447
3982
dependencies:
···
3511
4046
3512
4047
resolve-from@4.0.0: {}
3513
4048
3514
-
rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1):
4049
+
resolve-pkg-maps@1.0.0: {}
4050
+
4051
+
rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0):
3515
4052
dependencies:
3516
4053
'@oxc-project/runtime': 0.97.0
3517
4054
fdir: 6.5.0(picomatch@4.0.3)
···
3524
4061
'@types/node': 24.10.4
3525
4062
fsevents: 2.3.3
3526
4063
jiti: 2.6.1
4064
+
tsx: 4.21.0
3527
4065
3528
4066
rolldown@1.0.0-beta.50:
3529
4067
dependencies:
···
3545
4083
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.50
3546
4084
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.50
3547
4085
4086
+
satori@0.18.3:
4087
+
dependencies:
4088
+
'@shuding/opentype.js': 1.4.0-beta.0
4089
+
css-background-parser: 0.1.0
4090
+
css-box-shadow: 1.0.0-3
4091
+
css-gradient-parser: 0.0.17
4092
+
css-to-react-native: 3.2.0
4093
+
emoji-regex-xs: 2.0.1
4094
+
escape-html: 1.0.3
4095
+
linebreak: 1.1.0
4096
+
parse-css-color: 0.2.1
4097
+
postcss-value-parser: 4.2.0
4098
+
yoga-layout: 3.2.1
4099
+
3548
4100
saxes@6.0.0:
3549
4101
dependencies:
3550
4102
xmlchars: 2.2.0
···
3599
4151
stackback@0.0.2: {}
3600
4152
3601
4153
std-env@3.10.0: {}
4154
+
4155
+
string.prototype.codepointat@0.2.1: {}
3602
4156
3603
4157
stringify-entities@4.0.4:
3604
4158
dependencies:
···
3627
4181
3628
4182
tapable@2.3.0: {}
3629
4183
4184
+
tiny-inflate@1.0.3: {}
4185
+
3630
4186
tinybench@2.9.0: {}
3631
4187
3632
4188
tinyexec@1.0.2: {}
···
3662
4218
3663
4219
tslib@2.8.1: {}
3664
4220
4221
+
tsx@4.21.0:
4222
+
dependencies:
4223
+
esbuild: 0.27.2
4224
+
get-tsconfig: 4.13.0
4225
+
optionalDependencies:
4226
+
fsevents: 2.3.3
4227
+
3665
4228
type-check@0.4.0:
3666
4229
dependencies:
3667
4230
prelude-ls: 1.2.1
···
3682
4245
ufo@1.6.1: {}
3683
4246
3684
4247
undici-types@7.16.0: {}
4248
+
4249
+
unicode-trie@2.0.0:
4250
+
dependencies:
4251
+
pako: 0.2.9
4252
+
tiny-inflate: 1.0.3
3685
4253
3686
4254
unified@11.0.5:
3687
4255
dependencies:
···
3736
4304
'@types/unist': 3.0.3
3737
4305
vfile-message: 4.0.3
3738
4306
3739
-
vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))(solid-js@1.9.10):
4307
+
vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))(solid-js@1.9.10):
3740
4308
dependencies:
3741
4309
'@babel/core': 7.28.5
3742
4310
'@types/babel__core': 7.20.5
···
3744
4312
merge-anything: 5.1.7
3745
4313
solid-js: 1.9.10
3746
4314
solid-refresh: 0.6.3(solid-js@1.9.10)
3747
-
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)
3748
-
vitefu: 1.1.1(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))
4315
+
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)
4316
+
vitefu: 1.1.1(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))
3749
4317
optionalDependencies:
3750
4318
'@testing-library/jest-dom': 6.9.1
3751
4319
transitivePeerDependencies:
3752
4320
- supports-color
3753
4321
3754
-
vitefu@1.1.1(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)):
4322
+
vitefu@1.1.1(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)):
3755
4323
optionalDependencies:
3756
-
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)
4324
+
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)
3757
4325
3758
-
vitest@4.0.16(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.4.0):
4326
+
vitest@4.0.16(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.4.0)(tsx@4.21.0):
3759
4327
dependencies:
3760
4328
'@vitest/expect': 4.0.16
3761
-
'@vitest/mocker': 4.0.16(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1))
4329
+
'@vitest/mocker': 4.0.16(rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0))
3762
4330
'@vitest/pretty-format': 4.0.16
3763
4331
'@vitest/runner': 4.0.16
3764
4332
'@vitest/snapshot': 4.0.16
···
3775
4343
tinyexec: 1.0.2
3776
4344
tinyglobby: 0.2.15
3777
4345
tinyrainbow: 3.0.3
3778
-
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)
4346
+
vite: rolldown-vite@7.2.5(@types/node@24.10.4)(jiti@2.6.1)(tsx@4.21.0)
3779
4347
why-is-node-running: 2.3.0
3780
4348
optionalDependencies:
3781
4349
'@types/node': 24.10.4
···
3826
4394
yallist@3.1.1: {}
3827
4395
3828
4396
yocto-queue@0.1.0: {}
4397
+
4398
+
yoga-layout@3.2.1: {}
3829
4399
3830
4400
zwitch@2.0.4: {}
web/public/og-image.png
web/public/og-image.png
This is a binary file and will not be displayed.
+3
web/public/robots.txt
+3
web/public/robots.txt
+23
web/public/sitemap.xml
+23
web/public/sitemap.xml
···
1
+
<?xml version="1.0" encoding="UTF-8"?>
2
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
+
<url>
4
+
<loc>https://malfestio.stormlightlabs.org/</loc>
5
+
<changefreq>weekly</changefreq>
6
+
<priority>1.0</priority>
7
+
</url>
8
+
<url>
9
+
<loc>https://malfestio.stormlightlabs.org/about</loc>
10
+
<changefreq>monthly</changefreq>
11
+
<priority>0.7</priority>
12
+
</url>
13
+
<url>
14
+
<loc>https://malfestio.stormlightlabs.org/login</loc>
15
+
<changefreq>monthly</changefreq>
16
+
<priority>0.5</priority>
17
+
</url>
18
+
<url>
19
+
<loc>https://malfestio.stormlightlabs.org/help</loc>
20
+
<changefreq>monthly</changefreq>
21
+
<priority>0.6</priority>
22
+
</url>
23
+
</urlset>
+247
web/scripts/generate-og-image.ts
+247
web/scripts/generate-og-image.ts
···
1
+
/**
2
+
* OpenGraph Image Generator
3
+
*
4
+
* Generates a 1200x630 OG image matching the hero section styling.
5
+
*
6
+
* Run with: pnpm run generate:og
7
+
*/
8
+
import { Resvg } from "@resvg/resvg-js";
9
+
import { writeFileSync } from "fs";
10
+
import { dirname, join } from "path";
11
+
import satori from "satori";
12
+
import { fileURLToPath } from "url";
13
+
14
+
const __dirname = dirname(fileURLToPath(import.meta.url));
15
+
16
+
const WIDTH = 1200;
17
+
const HEIGHT = 630;
18
+
const GRID_SIZE = 32;
19
+
20
+
/**
21
+
* Fetches a font from Google Fonts as a TTF file.
22
+
*
23
+
* We use an older user-agent to get TTF instead of woff2.
24
+
*
25
+
* @param family - The font family to fetch.
26
+
* @param weight - The font weight to fetch.
27
+
* @returns A Promise that resolves to the font file as an ArrayBuffer.
28
+
*/
29
+
async function fetchFont(family: string, weight: number): Promise<ArrayBuffer> {
30
+
const url = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:wght@${weight}&display=swap`;
31
+
32
+
const cssRes = await fetch(url, {
33
+
headers: { "User-Agent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)" },
34
+
});
35
+
const css = await cssRes.text();
36
+
37
+
const fontUrlMatch = css.match(/src: url\(([^)]+)\)/);
38
+
if (!fontUrlMatch) {
39
+
throw new Error(`Could not find font URL for ${family}`);
40
+
}
41
+
42
+
const fontRes = await fetch(fontUrlMatch[1]);
43
+
return fontRes.arrayBuffer();
44
+
}
45
+
46
+
/**
47
+
* Generates a grid pattern as SVG.
48
+
*
49
+
* @returns An object representing the grid pattern.
50
+
*/
51
+
function GridPattern() {
52
+
const lines: { x1: number; y1: number; x2: number; y2: number }[] = [];
53
+
54
+
for (let x = 0; x <= WIDTH; x += GRID_SIZE) {
55
+
lines.push({ x1: x, y1: 0, x2: x, y2: HEIGHT });
56
+
}
57
+
58
+
for (let y = 0; y <= HEIGHT; y += GRID_SIZE) {
59
+
lines.push({ x1: 0, y1: y, x2: WIDTH, y2: y });
60
+
}
61
+
62
+
return {
63
+
type: "div",
64
+
props: {
65
+
style: { position: "absolute", top: 0, left: 0, width: WIDTH, height: HEIGHT, display: "flex" },
66
+
children: {
67
+
type: "svg",
68
+
props: {
69
+
width: WIDTH,
70
+
height: HEIGHT,
71
+
children: lines.map((line, i) => ({
72
+
type: "line",
73
+
props: {
74
+
key: i,
75
+
x1: line.x1,
76
+
y1: line.y1,
77
+
x2: line.x2,
78
+
y2: line.y2,
79
+
stroke: "rgba(85, 85, 85, 0.3)",
80
+
strokeWidth: 1,
81
+
},
82
+
})),
83
+
},
84
+
},
85
+
},
86
+
};
87
+
}
88
+
89
+
function NoteCard(
90
+
config: { x: number; y: number; width: number; bgColor: string; borderColor: string; scribbleColor: string },
91
+
) {
92
+
return {
93
+
type: "div",
94
+
props: {
95
+
style: {
96
+
position: "absolute",
97
+
left: config.x,
98
+
top: config.y,
99
+
width: config.width,
100
+
height: 80,
101
+
backgroundColor: config.bgColor,
102
+
border: `1px solid ${config.borderColor}`,
103
+
borderRadius: 8,
104
+
padding: 12,
105
+
display: "flex",
106
+
flexDirection: "column",
107
+
gap: 8,
108
+
},
109
+
children: [{
110
+
type: "div",
111
+
props: { style: { width: "80%", height: 8, backgroundColor: config.scribbleColor, borderRadius: 4 } },
112
+
}, {
113
+
type: "div",
114
+
props: { style: { width: "60%", height: 8, backgroundColor: config.scribbleColor, borderRadius: 4 } },
115
+
}],
116
+
},
117
+
};
118
+
}
119
+
120
+
const cards = [
121
+
NoteCard({
122
+
x: 800,
123
+
y: 60,
124
+
width: 180,
125
+
bgColor: "rgba(37, 99, 235, 0.2)",
126
+
borderColor: "rgba(59, 130, 246, 0.3)",
127
+
scribbleColor: "rgba(147, 197, 253, 0.5)",
128
+
}),
129
+
NoteCard({
130
+
x: 950,
131
+
y: 180,
132
+
width: 160,
133
+
bgColor: "rgba(147, 51, 234, 0.2)",
134
+
borderColor: "rgba(168, 85, 247, 0.3)",
135
+
scribbleColor: "rgba(216, 180, 254, 0.5)",
136
+
}),
137
+
NoteCard({
138
+
x: 820,
139
+
y: 300,
140
+
width: 170,
141
+
bgColor: "rgba(234, 88, 12, 0.2)",
142
+
borderColor: "rgba(251, 146, 60, 0.3)",
143
+
scribbleColor: "rgba(253, 186, 116, 0.5)",
144
+
}),
145
+
NoteCard({
146
+
x: 920,
147
+
y: 420,
148
+
width: 200,
149
+
bgColor: "rgba(14, 116, 144, 0.2)",
150
+
borderColor: "rgba(34, 211, 238, 0.3)",
151
+
scribbleColor: "rgba(103, 232, 249, 0.5)",
152
+
}),
153
+
];
154
+
155
+
const ogImage = {
156
+
type: "div",
157
+
props: {
158
+
style: {
159
+
width: WIDTH,
160
+
height: HEIGHT,
161
+
backgroundColor: "#000000",
162
+
display: "flex",
163
+
flexDirection: "column",
164
+
position: "relative",
165
+
},
166
+
children: [GridPattern(), ...cards, {
167
+
type: "div",
168
+
props: {
169
+
style: { position: "absolute", left: 60, top: 180, display: "flex", flexDirection: "column" },
170
+
children: [{
171
+
type: "div",
172
+
props: {
173
+
style: { fontSize: 96, fontFamily: "Source Serif 4", fontWeight: 500, color: "#ffffff", lineHeight: 1.1 },
174
+
children: "Learning on",
175
+
},
176
+
}, {
177
+
type: "div",
178
+
props: {
179
+
style: { fontSize: 96, fontFamily: "Source Serif 4", fontWeight: 500, color: "#737373", lineHeight: 1.1 },
180
+
children: "the AT Protocol.",
181
+
},
182
+
}],
183
+
},
184
+
}, {
185
+
type: "div",
186
+
props: {
187
+
style: {
188
+
position: "absolute",
189
+
left: 60,
190
+
bottom: 50,
191
+
fontSize: 48,
192
+
fontFamily: "Figtree",
193
+
fontWeight: 600,
194
+
color: "#ffffff",
195
+
},
196
+
children: "Malfestio",
197
+
},
198
+
}, {
199
+
type: "div",
200
+
props: {
201
+
style: {
202
+
position: "absolute",
203
+
right: 72,
204
+
bottom: 50,
205
+
fontSize: 32,
206
+
fontFamily: "Figtree",
207
+
fontWeight: 500,
208
+
textShadow: "0px 0px 10px rgba(0, 0, 0, 0.5)",
209
+
color: "#737373",
210
+
},
211
+
children: "malfestio.stormlightlabs.org",
212
+
},
213
+
}],
214
+
},
215
+
};
216
+
217
+
async function main() {
218
+
console.log("Generating OpenGraph image...");
219
+
console.log("Fetching fonts from Google Fonts...");
220
+
221
+
const [sourceSerif, figtree] = await Promise.all([fetchFont("Source Serif 4", 500), fetchFont("Figtree", 600)]);
222
+
223
+
console.log("Rendering SVG...");
224
+
225
+
const svg = await satori(ogImage, {
226
+
width: WIDTH,
227
+
height: HEIGHT,
228
+
fonts: [{ name: "Source Serif 4", data: sourceSerif, weight: 500, style: "normal" }, {
229
+
name: "Figtree",
230
+
data: figtree,
231
+
weight: 600,
232
+
style: "normal",
233
+
}],
234
+
});
235
+
236
+
console.log("Converting to PNG...");
237
+
238
+
const resvg = new Resvg(svg, { fitTo: { mode: "width", value: WIDTH } });
239
+
const pngBuffer = resvg.render().asPng();
240
+
const outputPath = join(__dirname, "..", "public", "og-image.png");
241
+
writeFileSync(outputPath, pngBuffer);
242
+
243
+
console.log(`✓ Generated: ${outputPath}`);
244
+
console.log(` Dimensions: ${WIDTH}x${HEIGHT}px`);
245
+
}
246
+
247
+
main().catch(console.error);