browse the protocol like its 2008 ibex.desertthunder.dev
ubuntu atproto svelte
7

Configure Feed

Select the types of activity you want to include in your feed.

feat: og image

Owais Jamil (Jun 9, 2026, 3:56 PM -0500) 0e9f1bbb 71ec42e5

+461
+4
package.json
··· 49 49 "@atcute/bluesky": "^4.0.7", 50 50 "@atcute/client": "^5.0.0", 51 51 "@atcute/lexicons": "^2.0.0", 52 + "@fontsource/ubuntu": "^5.2.8", 53 + "@resvg/resvg-js": "^2.6.2", 52 54 "@shikijs/core": "^4.2.0", 53 55 "@shikijs/engine-javascript": "^4.2.0", 54 56 "@shikijs/langs": "^4.2.0", 55 57 "dexie": "^4.4.3", 56 58 "flexsearch": "^0.8.212", 59 + "satori": "^0.26.0", 60 + "satori-html": "^0.3.2", 57 61 "shiki": "^4.2.0" 58 62 } 59 63 }
+306
pnpm-lock.yaml
··· 20 20 '@atcute/lexicons': 21 21 specifier: ^2.0.0 22 22 version: 2.0.0 23 + '@fontsource/ubuntu': 24 + specifier: ^5.2.8 25 + version: 5.2.8 26 + '@resvg/resvg-js': 27 + specifier: ^2.6.2 28 + version: 2.6.2 23 29 '@shikijs/core': 24 30 specifier: ^4.2.0 25 31 version: 4.2.0 ··· 35 41 flexsearch: 36 42 specifier: ^0.8.212 37 43 version: 0.8.212 44 + satori: 45 + specifier: ^0.26.0 46 + version: 0.26.0 47 + satori-html: 48 + specifier: ^0.3.2 49 + version: 0.3.2 38 50 shiki: 39 51 specifier: ^4.2.0 40 52 version: 4.2.0 ··· 406 418 '@fontsource/ubuntu-mono@5.2.8': 407 419 resolution: {integrity: sha512-N4nT8+GYWWcDODVSBLU4f3PycZQH9YIF6SypDI0rti3HrLqcXFS9u6wMvAd9vx1FmjAQkYv7Ld9CZ8XYTEOD0A==} 408 420 421 + '@fontsource/ubuntu@5.2.8': 422 + resolution: {integrity: sha512-esSJCpgigwWOm4Ug9f7AMozUyBq5Iobea5C9QYsl2OlCb62wZABBUbXahHLdFv5Ru4lJCD9tUX6xEAeLwUTNBg==} 423 + 409 424 '@humanfs/core@0.19.2': 410 425 resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} 411 426 engines: {node: '>=18.18.0'} ··· 619 634 '@poppinss/exception@1.2.3': 620 635 resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} 621 636 637 + '@resvg/resvg-js-android-arm-eabi@2.6.2': 638 + resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==} 639 + engines: {node: '>= 10'} 640 + cpu: [arm] 641 + os: [android] 642 + 643 + '@resvg/resvg-js-android-arm64@2.6.2': 644 + resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==} 645 + engines: {node: '>= 10'} 646 + cpu: [arm64] 647 + os: [android] 648 + 649 + '@resvg/resvg-js-darwin-arm64@2.6.2': 650 + resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==} 651 + engines: {node: '>= 10'} 652 + cpu: [arm64] 653 + os: [darwin] 654 + 655 + '@resvg/resvg-js-darwin-x64@2.6.2': 656 + resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==} 657 + engines: {node: '>= 10'} 658 + cpu: [x64] 659 + os: [darwin] 660 + 661 + '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': 662 + resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==} 663 + engines: {node: '>= 10'} 664 + cpu: [arm] 665 + os: [linux] 666 + 667 + '@resvg/resvg-js-linux-arm64-gnu@2.6.2': 668 + resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==} 669 + engines: {node: '>= 10'} 670 + cpu: [arm64] 671 + os: [linux] 672 + libc: [glibc] 673 + 674 + '@resvg/resvg-js-linux-arm64-musl@2.6.2': 675 + resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==} 676 + engines: {node: '>= 10'} 677 + cpu: [arm64] 678 + os: [linux] 679 + libc: [musl] 680 + 681 + '@resvg/resvg-js-linux-x64-gnu@2.6.2': 682 + resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==} 683 + engines: {node: '>= 10'} 684 + cpu: [x64] 685 + os: [linux] 686 + libc: [glibc] 687 + 688 + '@resvg/resvg-js-linux-x64-musl@2.6.2': 689 + resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==} 690 + engines: {node: '>= 10'} 691 + cpu: [x64] 692 + os: [linux] 693 + libc: [musl] 694 + 695 + '@resvg/resvg-js-win32-arm64-msvc@2.6.2': 696 + resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==} 697 + engines: {node: '>= 10'} 698 + cpu: [arm64] 699 + os: [win32] 700 + 701 + '@resvg/resvg-js-win32-ia32-msvc@2.6.2': 702 + resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==} 703 + engines: {node: '>= 10'} 704 + cpu: [ia32] 705 + os: [win32] 706 + 707 + '@resvg/resvg-js-win32-x64-msvc@2.6.2': 708 + resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==} 709 + engines: {node: '>= 10'} 710 + cpu: [x64] 711 + os: [win32] 712 + 713 + '@resvg/resvg-js@2.6.2': 714 + resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==} 715 + engines: {node: '>= 10'} 716 + 622 717 '@rolldown/binding-android-arm64@1.0.3': 623 718 resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} 624 719 engines: {node: ^20.19.0 || >=22.12.0} ··· 747 842 748 843 '@shikijs/vscode-textmate@10.0.2': 749 844 resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} 845 + 846 + '@shuding/opentype.js@1.4.0-beta.0': 847 + resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==} 848 + engines: {node: '>= 8.0.0'} 849 + hasBin: true 750 850 751 851 '@sindresorhus/is@7.2.0': 752 852 resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} ··· 971 1071 resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} 972 1072 engines: {node: 18 || 20 || >=22} 973 1073 1074 + base64-js@0.0.8: 1075 + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} 1076 + engines: {node: '>= 0.4'} 1077 + 974 1078 blake3-wasm@2.1.5: 975 1079 resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} 976 1080 977 1081 brace-expansion@5.0.6: 978 1082 resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} 979 1083 engines: {node: 18 || 20 || >=22} 1084 + 1085 + camelize@1.0.1: 1086 + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} 980 1087 981 1088 ccount@2.0.1: 982 1089 resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} ··· 999 1106 resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} 1000 1107 engines: {node: '>=6'} 1001 1108 1109 + color-name@1.1.4: 1110 + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 1111 + 1002 1112 comma-separated-tokens@2.0.3: 1003 1113 resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} 1004 1114 ··· 1017 1127 resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 1018 1128 engines: {node: '>= 8'} 1019 1129 1130 + css-background-parser@0.1.0: 1131 + resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==} 1132 + 1133 + css-box-shadow@1.0.0-3: 1134 + resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==} 1135 + 1136 + css-color-keywords@1.0.0: 1137 + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} 1138 + engines: {node: '>=4'} 1139 + 1140 + css-gradient-parser@0.0.17: 1141 + resolution: {integrity: sha512-w2Xy9UMMwlKtou0vlRnXvWglPAceXCTtcmVSo8ZBUvqCV5aXEFP/PC6d+I464810I9FT++UACwTD5511bmGPUg==} 1142 + engines: {node: '>=16'} 1143 + 1144 + css-to-react-native@3.2.0: 1145 + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} 1146 + 1020 1147 cssesc@3.0.0: 1021 1148 resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 1022 1149 engines: {node: '>=4'} ··· 1055 1182 dexie@4.4.3: 1056 1183 resolution: {integrity: sha512-N+3IGQ3HPlyO2YAkntGAwitm42BpBGV86MttzUMiRzWLa4NGh0pltVRcUVF4ybL/OnXjCrr9k7SDPIKkFYP2Lg==} 1057 1184 1185 + emoji-regex-xs@2.0.1: 1186 + resolution: {integrity: sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==} 1187 + engines: {node: '>=10.0.0'} 1188 + 1058 1189 error-stack-parser-es@1.0.5: 1059 1190 resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} 1060 1191 ··· 1065 1196 resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} 1066 1197 engines: {node: '>=18'} 1067 1198 hasBin: true 1199 + 1200 + escape-html@1.0.3: 1201 + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 1068 1202 1069 1203 escape-string-regexp@4.0.0: 1070 1204 resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} ··· 1180 1314 picomatch: 1181 1315 optional: true 1182 1316 1317 + fflate@0.7.4: 1318 + resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} 1319 + 1183 1320 file-entry-cache@8.0.0: 1184 1321 resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} 1185 1322 engines: {node: '>=16.0.0'} ··· 1225 1362 1226 1363 hast-util-whitespace@3.0.0: 1227 1364 resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} 1365 + 1366 + hex-rgb@4.3.0: 1367 + resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==} 1368 + engines: {node: '>=6'} 1228 1369 1229 1370 html-void-elements@3.0.0: 1230 1371 resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} ··· 1355 1496 lilconfig@2.1.0: 1356 1497 resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} 1357 1498 engines: {node: '>=10'} 1499 + 1500 + linebreak@1.1.0: 1501 + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} 1358 1502 1359 1503 locate-character@3.0.0: 1360 1504 resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} ··· 1439 1583 resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 1440 1584 engines: {node: '>=10'} 1441 1585 1586 + pako@0.2.9: 1587 + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} 1588 + 1589 + parse-css-color@0.2.1: 1590 + resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} 1591 + 1442 1592 path-exists@4.0.0: 1443 1593 resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1444 1594 engines: {node: '>=8'} ··· 1501 1651 postcss-selector-parser@7.1.1: 1502 1652 resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} 1503 1653 engines: {node: '>=4'} 1654 + 1655 + postcss-value-parser@4.2.0: 1656 + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 1504 1657 1505 1658 postcss@8.5.15: 1506 1659 resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} ··· 1557 1710 resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 1558 1711 engines: {node: '>=6'} 1559 1712 1713 + satori-html@0.3.2: 1714 + resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==} 1715 + 1716 + satori@0.26.0: 1717 + resolution: {integrity: sha512-tkMFrfIs3l2mQ2JEcyW0ADTy3zGggFRFzi6Ef8YozQSFsFKEqaSO1Y8F9wJg4//PJGQauMalHGTUEkPrFwhVPA==} 1718 + engines: {node: '>=16'} 1719 + 1560 1720 semver@7.8.3: 1561 1721 resolution: {integrity: sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==} 1562 1722 engines: {node: '>=10'} ··· 1600 1760 1601 1761 std-env@4.1.0: 1602 1762 resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} 1763 + 1764 + string.prototype.codepointat@0.2.1: 1765 + resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} 1603 1766 1604 1767 stringify-entities@4.0.4: 1605 1768 resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} ··· 1629 1792 resolution: {integrity: sha512-w7JvrM5IFl5cmfbY0TLik9o7mjRUJmRMhOR51tBPu708Gr/MjbGs7VnJnr/B0CaXeI4vtnOh7RKxDr0cwhMdDA==} 1630 1793 engines: {node: '>=18'} 1631 1794 1795 + tiny-inflate@1.0.3: 1796 + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} 1797 + 1632 1798 tinybench@2.9.0: 1633 1799 resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1634 1800 ··· 1676 1842 engines: {node: '>=14.17'} 1677 1843 hasBin: true 1678 1844 1845 + ultrahtml@1.6.0: 1846 + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} 1847 + 1679 1848 undici-types@7.18.2: 1680 1849 resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} 1681 1850 ··· 1688 1857 1689 1858 unicode-segmenter@0.14.5: 1690 1859 resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==} 1860 + 1861 + unicode-trie@2.0.0: 1862 + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} 1691 1863 1692 1864 unist-util-is@4.1.0: 1693 1865 resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} ··· 1898 2070 resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 1899 2071 engines: {node: '>=10'} 1900 2072 2073 + yoga-layout@3.2.1: 2074 + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} 2075 + 1901 2076 youch-core@0.3.3: 1902 2077 resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} 1903 2078 ··· 2109 2284 2110 2285 '@fontsource/ubuntu-mono@5.2.8': {} 2111 2286 2287 + '@fontsource/ubuntu@5.2.8': {} 2288 + 2112 2289 '@humanfs/core@0.19.2': 2113 2290 dependencies: 2114 2291 '@humanfs/types': 0.15.0 ··· 2268 2445 2269 2446 '@poppinss/exception@1.2.3': {} 2270 2447 2448 + '@resvg/resvg-js-android-arm-eabi@2.6.2': 2449 + optional: true 2450 + 2451 + '@resvg/resvg-js-android-arm64@2.6.2': 2452 + optional: true 2453 + 2454 + '@resvg/resvg-js-darwin-arm64@2.6.2': 2455 + optional: true 2456 + 2457 + '@resvg/resvg-js-darwin-x64@2.6.2': 2458 + optional: true 2459 + 2460 + '@resvg/resvg-js-linux-arm-gnueabihf@2.6.2': 2461 + optional: true 2462 + 2463 + '@resvg/resvg-js-linux-arm64-gnu@2.6.2': 2464 + optional: true 2465 + 2466 + '@resvg/resvg-js-linux-arm64-musl@2.6.2': 2467 + optional: true 2468 + 2469 + '@resvg/resvg-js-linux-x64-gnu@2.6.2': 2470 + optional: true 2471 + 2472 + '@resvg/resvg-js-linux-x64-musl@2.6.2': 2473 + optional: true 2474 + 2475 + '@resvg/resvg-js-win32-arm64-msvc@2.6.2': 2476 + optional: true 2477 + 2478 + '@resvg/resvg-js-win32-ia32-msvc@2.6.2': 2479 + optional: true 2480 + 2481 + '@resvg/resvg-js-win32-x64-msvc@2.6.2': 2482 + optional: true 2483 + 2484 + '@resvg/resvg-js@2.6.2': 2485 + optionalDependencies: 2486 + '@resvg/resvg-js-android-arm-eabi': 2.6.2 2487 + '@resvg/resvg-js-android-arm64': 2.6.2 2488 + '@resvg/resvg-js-darwin-arm64': 2.6.2 2489 + '@resvg/resvg-js-darwin-x64': 2.6.2 2490 + '@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2 2491 + '@resvg/resvg-js-linux-arm64-gnu': 2.6.2 2492 + '@resvg/resvg-js-linux-arm64-musl': 2.6.2 2493 + '@resvg/resvg-js-linux-x64-gnu': 2.6.2 2494 + '@resvg/resvg-js-linux-x64-musl': 2.6.2 2495 + '@resvg/resvg-js-win32-arm64-msvc': 2.6.2 2496 + '@resvg/resvg-js-win32-ia32-msvc': 2.6.2 2497 + '@resvg/resvg-js-win32-x64-msvc': 2.6.2 2498 + 2271 2499 '@rolldown/binding-android-arm64@1.0.3': 2272 2500 optional: true 2273 2501 ··· 2359 2587 2360 2588 '@shikijs/vscode-textmate@10.0.2': {} 2361 2589 2590 + '@shuding/opentype.js@1.4.0-beta.0': 2591 + dependencies: 2592 + fflate: 0.7.4 2593 + string.prototype.codepointat: 0.2.1 2594 + 2362 2595 '@sindresorhus/is@7.2.0': {} 2363 2596 2364 2597 '@speed-highlight/core@1.2.16': {} ··· 2631 2864 2632 2865 balanced-match@4.0.4: {} 2633 2866 2867 + base64-js@0.0.8: {} 2868 + 2634 2869 blake3-wasm@2.1.5: {} 2635 2870 2636 2871 brace-expansion@5.0.6: 2637 2872 dependencies: 2638 2873 balanced-match: 4.0.4 2874 + 2875 + camelize@1.0.1: {} 2639 2876 2640 2877 ccount@2.0.1: {} 2641 2878 ··· 2651 2888 2652 2889 clsx@2.1.1: {} 2653 2890 2891 + color-name@1.1.4: {} 2892 + 2654 2893 comma-separated-tokens@2.0.3: {} 2655 2894 2656 2895 convert-source-map@2.0.0: {} ··· 2665 2904 shebang-command: 2.0.0 2666 2905 which: 2.0.2 2667 2906 2907 + css-background-parser@0.1.0: {} 2908 + 2909 + css-box-shadow@1.0.0-3: {} 2910 + 2911 + css-color-keywords@1.0.0: {} 2912 + 2913 + css-gradient-parser@0.0.17: {} 2914 + 2915 + css-to-react-native@3.2.0: 2916 + dependencies: 2917 + camelize: 1.0.1 2918 + css-color-keywords: 1.0.0 2919 + postcss-value-parser: 4.2.0 2920 + 2668 2921 cssesc@3.0.0: {} 2669 2922 2670 2923 debug@4.4.3: ··· 2686 2939 dequal: 2.0.3 2687 2940 2688 2941 dexie@4.4.3: {} 2942 + 2943 + emoji-regex-xs@2.0.1: {} 2689 2944 2690 2945 error-stack-parser-es@1.0.5: {} 2691 2946 ··· 2719 2974 '@esbuild/win32-arm64': 0.27.3 2720 2975 '@esbuild/win32-ia32': 0.27.3 2721 2976 '@esbuild/win32-x64': 0.27.3 2977 + 2978 + escape-html@1.0.3: {} 2722 2979 2723 2980 escape-string-regexp@4.0.0: {} 2724 2981 ··· 2846 3103 fdir@6.5.0(picomatch@4.0.4): 2847 3104 optionalDependencies: 2848 3105 picomatch: 4.0.4 3106 + 3107 + fflate@0.7.4: {} 2849 3108 2850 3109 file-entry-cache@8.0.0: 2851 3110 dependencies: ··· 2897 3156 dependencies: 2898 3157 '@types/hast': 3.0.4 2899 3158 3159 + hex-rgb@4.3.0: {} 3160 + 2900 3161 html-void-elements@3.0.0: {} 2901 3162 2902 3163 ignore@5.3.2: {} ··· 2986 3247 lightningcss-win32-x64-msvc: 1.32.0 2987 3248 2988 3249 lilconfig@2.1.0: {} 3250 + 3251 + linebreak@1.1.0: 3252 + dependencies: 3253 + base64-js: 0.0.8 3254 + unicode-trie: 2.0.0 2989 3255 2990 3256 locate-character@3.0.0: {} 2991 3257 ··· 3089 3355 dependencies: 3090 3356 p-limit: 3.1.0 3091 3357 3358 + pako@0.2.9: {} 3359 + 3360 + parse-css-color@0.2.1: 3361 + dependencies: 3362 + color-name: 1.1.4 3363 + hex-rgb: 4.3.0 3364 + 3092 3365 path-exists@4.0.0: {} 3093 3366 3094 3367 path-key@3.1.1: {} ··· 3130 3403 dependencies: 3131 3404 cssesc: 3.0.0 3132 3405 util-deprecate: 1.0.2 3406 + 3407 + postcss-value-parser@4.2.0: {} 3133 3408 3134 3409 postcss@8.5.15: 3135 3410 dependencies: ··· 3191 3466 dependencies: 3192 3467 mri: 1.2.0 3193 3468 3469 + satori-html@0.3.2: 3470 + dependencies: 3471 + ultrahtml: 1.6.0 3472 + 3473 + satori@0.26.0: 3474 + dependencies: 3475 + '@shuding/opentype.js': 1.4.0-beta.0 3476 + css-background-parser: 0.1.0 3477 + css-box-shadow: 1.0.0-3 3478 + css-gradient-parser: 0.0.17 3479 + css-to-react-native: 3.2.0 3480 + emoji-regex-xs: 2.0.1 3481 + escape-html: 1.0.3 3482 + linebreak: 1.1.0 3483 + parse-css-color: 0.2.1 3484 + postcss-value-parser: 4.2.0 3485 + yoga-layout: 3.2.1 3486 + 3194 3487 semver@7.8.3: {} 3195 3488 3196 3489 set-cookie-parser@3.1.0: {} ··· 3259 3552 3260 3553 std-env@4.1.0: {} 3261 3554 3555 + string.prototype.codepointat@0.2.1: {} 3556 + 3262 3557 stringify-entities@4.0.4: 3263 3558 dependencies: 3264 3559 character-entities-html4: 2.1.0 ··· 3311 3606 zimmerframe: 1.1.4 3312 3607 transitivePeerDependencies: 3313 3608 - '@typescript-eslint/types' 3609 + 3610 + tiny-inflate@1.0.3: {} 3314 3611 3315 3612 tinybench@2.9.0: {} 3316 3613 ··· 3351 3648 3352 3649 typescript@6.0.3: {} 3353 3650 3651 + ultrahtml@1.6.0: {} 3652 + 3354 3653 undici-types@7.18.2: {} 3355 3654 3356 3655 undici@7.24.8: {} ··· 3360 3659 pathe: 2.0.3 3361 3660 3362 3661 unicode-segmenter@0.14.5: {} 3662 + 3663 + unicode-trie@2.0.0: 3664 + dependencies: 3665 + pako: 0.2.9 3666 + tiny-inflate: 1.0.3 3363 3667 3364 3668 unist-util-is@4.1.0: {} 3365 3669 ··· 3518 3822 yaml@1.10.3: {} 3519 3823 3520 3824 yocto-queue@0.1.0: {} 3825 + 3826 + yoga-layout@3.2.1: {} 3521 3827 3522 3828 youch-core@0.3.3: 3523 3829 dependencies:
+2
pnpm-workspace.yaml
··· 1 1 onlyBuiltDependencies: 2 2 - esbuild 3 + - sharp 4 + - workerd
+97
src/lib/components/Opengraph.svelte
··· 1 + <script lang="ts"> 2 + interface Props { 3 + browserIcon: string; 4 + width: number; 5 + height: number; 6 + } 7 + 8 + let { browserIcon, width, height }: Props = $props(); 9 + </script> 10 + 11 + <div 12 + style="display:flex; width:{width}px; height:{height}px; background:#5b412e; color:#251b13; font-family:'Ubuntu Sans'; position:relative; overflow:hidden;"> 13 + <div 14 + style="display:flex; position:absolute; inset:0; background:linear-gradient(135deg, #6f4c30 0%, #4f3729 46%, #2c001e 100%);"> 15 + </div> 16 + <div 17 + style="display:flex; position:absolute; left:-130px; bottom:-180px; width:520px; height:520px; border-radius:260px; background:#dd6f1a; opacity:0.22;"> 18 + </div> 19 + <div 20 + style="display:flex; position:absolute; right:-180px; top:80px; width:540px; height:540px; border-radius:270px; background:#f28c22; opacity:0.16;"> 21 + </div> 22 + 23 + <div 24 + style="display:flex; position:absolute; top:0; left:0; right:0; height:38px; align-items:center; padding:0 16px; color:#fff5df; background:linear-gradient(90deg, #3b2418, #1f140d); border-bottom:2px solid rgba(0,0,0,0.65); font-size:19px; text-shadow:0 2px 0 rgba(0,0,0,0.65);"> 25 + <div style="display:flex; align-items:center; gap:11px; font-weight:700;"> 26 + <span>Applications</span><span>Places</span><span>System</span> 27 + </div> 28 + <div style="display:flex; margin-left:auto; gap:18px; font-family:'Ubuntu Mono'; font-size:17px; opacity:0.92;"> 29 + <span>Made by</span><span>@desertthunder.dev</span> 30 + </div> 31 + </div> 32 + 33 + <div 34 + style="display:flex; position:absolute; left:74px; top:86px; width:956px; height:456px; flex-direction:column; background:#d9c7aa; border:3px solid #6b401e; border-radius:8px; box-shadow:0 24px 56px rgba(0,0,0,0.45); overflow:hidden;"> 35 + <div 36 + style="display:flex; height:46px; align-items:center; padding:0 13px; color:#fff5df; background:linear-gradient(90deg, #704321, #3c2113); border-bottom:2px solid #27160d; text-shadow:0 2px 0 rgba(0,0,0,0.72);"> 37 + <img src={browserIcon} alt="" style="width:30px; height:30px; margin-right:10px;" /> 38 + <div style="display:flex; font-size:23px; font-weight:700;">Intrepid Ibex — ATProto Browser</div> 39 + <div style="display:flex; margin-left:auto; gap:7px;"> 40 + <div 41 + style="display:flex; width:22px; height:22px; align-items:center; justify-content:center; background:#e6d2b3; border:1px solid #4b2e19; color:#251b13; font-family:'Ubuntu Mono'; font-size:18px;"> 42 + 43 + </div> 44 + <div 45 + style="display:flex; width:22px; height:22px; align-items:center; justify-content:center; background:#d96c18; border:1px solid #4b2e19; color:white; font-family:'Ubuntu Mono'; font-size:18px;"> 46 + × 47 + </div> 48 + </div> 49 + </div> 50 + 51 + <div style="display:flex; flex:1; background:#f3eadb; padding:32px 36px; gap:30px;"> 52 + <div 53 + style="display:flex; width:248px; flex-direction:column; gap:12px; padding:18px; background:#fffaf0; border:2px solid #b99d78;"> 54 + <div style="display:flex; font-family:'Ubuntu Mono'; font-size:18px; color:#67594c;">at://browser</div> 55 + <div 56 + style="display:flex; height:30px; align-items:center; padding:0 9px; background:#d8c7ab; border:1px solid #8a5527; font-family:'Ubuntu Mono'; font-size:17px;"> 57 + repos 58 + </div> 59 + <div 60 + style="display:flex; height:30px; align-items:center; padding:0 9px; background:#f2ead9; border:1px solid #d1b183; font-family:'Ubuntu Mono'; font-size:17px;"> 61 + collections 62 + </div> 63 + <div 64 + style="display:flex; height:30px; align-items:center; padding:0 9px; background:#f2ead9; border:1px solid #d1b183; font-family:'Ubuntu Mono'; font-size:17px;"> 65 + records 66 + </div> 67 + </div> 68 + 69 + <div style="display:flex; flex:1; flex-direction:column;"> 70 + <div style="display:flex; color:#dd6f1a; font-size:28px; font-weight:700; margin-bottom:14px;"> 71 + A silly desktop-like UI for browsing the atmosphere 72 + </div> 73 + <div 74 + style="display:flex; color:#251b13; font-size:58px; line-height:1.04; font-weight:700; max-width:590px; letter-spacing:-1px;"> 75 + Ubuntu 8.10 meets the ATmosphere. 76 + </div> 77 + <div style="display:flex; margin-top:22px; color:#67594c; font-size:26px; line-height:1.28; max-width:620px;"> 78 + Browse records like its 2008. 79 + </div> 80 + <div 81 + style="display:flex; margin-top:auto; gap:12px; align-items:center; font-family:'Ubuntu Mono'; font-size:19px; color:#fff5df;"> 82 + <div style="display:flex; background:#704321; border:2px solid #4b2e19; padding:9px 13px;">GNOME(-ish)</div> 83 + <div style="display:flex; background:#dd6f1a; border:2px solid #8a5527; padding:9px 13px;">Svelte 5</div> 84 + </div> 85 + </div> 86 + </div> 87 + </div> 88 + 89 + <div 90 + style="display:flex; position:absolute; left:0; right:0; bottom:0; height:34px; align-items:center; padding:0 15px; color:#fff5df; background:linear-gradient(90deg, #3b2418, #1f140d); border-top:2px solid rgba(255,255,255,0.16); font-family:'Ubuntu Mono'; font-size:17px;"> 91 + <div 92 + style="display:flex; background:#f5e7cb; color:#23170f; border:1px solid #4b2e19; padding:3px 24px; margin-right:12px;"> 93 + Intrepid Ibex 94 + </div> 95 + <span style="opacity:0.82;">tangled.org/desertthunder.dev/ibex</span> 96 + </div> 97 + </div>
+52
src/routes/og.png/+server.ts
··· 1 + import { readFile } from 'node:fs/promises'; 2 + import { join } from 'node:path'; 3 + 4 + import { Resvg } from '@resvg/resvg-js'; 5 + import Opengraph from '$lib/components/Opengraph.svelte'; 6 + import satori from 'satori'; 7 + import { html } from 'satori-html'; 8 + import { render } from 'svelte/server'; 9 + 10 + export const prerender = true; 11 + 12 + const width = 1200; 13 + const height = 630; 14 + 15 + const staticPath = (file: string) => join(process.cwd(), 'static', file); 16 + 17 + const toArrayBuffer = (buffer: Buffer): ArrayBuffer => 18 + buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer; 19 + 20 + const toDataUri = (mimeType: string, buffer: Buffer): string => `data:${mimeType};base64,${buffer.toString('base64')}`; 21 + 22 + const stripSvelteComments = (value: string) => value.replace(/<!--[\s\S]*?-->/g, ''); 23 + 24 + export async function GET() { 25 + const [ubuntu, ubuntuBold, ubuntuMono, ubuntuMonoBold, browserIcon] = await Promise.all([ 26 + readFile(staticPath('og/fonts/ubuntu-latin-400-normal.woff')).then(toArrayBuffer), 27 + readFile(staticPath('og/fonts/ubuntu-latin-700-normal.woff')).then(toArrayBuffer), 28 + readFile(staticPath('og/fonts/ubuntu-mono-latin-400-normal.woff')).then(toArrayBuffer), 29 + readFile(staticPath('og/fonts/ubuntu-mono-latin-700-normal.woff')).then(toArrayBuffer), 30 + readFile(staticPath('icons/humanity/apps/web-browser.svg')).then((buffer) => toDataUri('image/svg+xml', buffer)) 31 + ]); 32 + 33 + const { body } = render(Opengraph, { props: { browserIcon, width, height } }); 34 + const markup = html(stripSvelteComments(body)); 35 + 36 + const svg = await satori(markup, { 37 + width, 38 + height, 39 + fonts: [ 40 + { name: 'Ubuntu Sans', data: ubuntu, weight: 400, style: 'normal' }, 41 + { name: 'Ubuntu Sans', data: ubuntuBold, weight: 700, style: 'normal' }, 42 + { name: 'Ubuntu Mono', data: ubuntuMono, weight: 400, style: 'normal' }, 43 + { name: 'Ubuntu Mono', data: ubuntuMonoBold, weight: 700, style: 'normal' } 44 + ] 45 + }); 46 + 47 + const png = new Resvg(svg, { fitTo: { mode: 'width', value: width } }).render().asPng(); 48 + 49 + return new Response(toArrayBuffer(png), { 50 + headers: { 'content-type': 'image/png', 'cache-control': 'public, immutable, max-age=31536000' } 51 + }); 52 + }
static/og/fonts/ubuntu-latin-400-normal.woff

This is a binary file and will not be displayed.

static/og/fonts/ubuntu-latin-700-normal.woff

This is a binary file and will not be displayed.

static/og/fonts/ubuntu-mono-latin-400-normal.woff

This is a binary file and will not be displayed.

static/og/fonts/ubuntu-mono-latin-700-normal.woff

This is a binary file and will not be displayed.