Compare commits

...

32 Commits

Author SHA1 Message Date
Muthu Kumar efdf56df2e
chore: fiddling with numbers 1 month ago
Muthu Kumar 7a8c7ca61d
fix: background things get selected on Safari even while dragging 1 month ago
Muthu Kumar 73d73cb11e
fix: Draggable+Flippable interactions. blur, ESC to stop 1 month ago
Muthu Kumar 17831c3849
fix: make things more accessible for tiny screens like watches 1 month ago
Muthu Kumar f7d1573746
fix: fix viewport coords to use page coordinates 1 month ago
Muthu Kumar 30f17ab8d6
chore: adjust button/card sizing 1 month ago
Muthu Kumar 818bbf08c6
use throttle instead of debounce for isOutside calculation 1 month ago
Muthu Kumar 7a9c01673f
fix: avoid AnimateEntry conflict with Draggable over transform by using translate instead 1 month ago
Muthu Kumar 329b22f15b
feat: add viewport exit & initialRotation support 1 month ago
Muthu Kumar c15cbdbc75
feat: use new Draggable 1 month ago
Muthu Kumar 5a6d07edb9
feat: composeRefs 1 month ago
Muthu Kumar 82e3cc00ac
feat: attempt 6 at creating standalone draaggable (finally works!) 1 month ago
Muthu Kumar 5e9eebb4ab
feat: attempt 5 at creating standalone draaggable 1 month ago
Muthu Kumar bb71e987df
feat: attempt 4 at creating standalone draaggable 1 month ago
Muthu Kumar 1aa29f16ba
feat: attempt 3 at creating standalone draaggable 1 month ago
Muthu Kumar 32c7e4a5d1
feat: attempt 2 at creating standalone draaggable 1 month ago
Muthu Kumar 014376678c
feat: attempt at creating standalone draaggable 1 month ago
Muthu Kumar 52fa434f59
fix: attempt to fix problems with DraggableButton 1 month ago
Muthu Kumar 158d427aa4
chore: more flexible container top 1 month ago
Muthu Kumar 9359bcac53
chore: package upgrades and maintenance 1 month ago
Muthu Kumar ce595da37a
chore: unlink wip things 2 months ago
Muthu Kumar 2a1c3f4eab
feat: isOutsideViewport 🐰🥚 2 months ago
Muthu Kumar 3199c10300
feat: AnimateEntry component & Container refactor 2 months ago
Muthu Kumar 4357ac6ec5
chore: minor cleanup 2 months ago
Muthu Kumar fb6eccc835
feat: use Flippable to make chaotic Contact page 2 months ago
Muthu Kumar 59725af5da
feat: improved <DraggableButton /> rotations 2 months ago
Muthu Kumar c02d123ab5
chore: Container improvements, refactor ugly code to CSS 2 months ago
Muthu Kumar 813e4db875
feat: <Flippable /> 2 months ago
Muthu Kumar b301d1a598
feat: I made the Draggables rotate 2 months ago
Muthu Kumar a19b8f6372
feat: I added draggable cards for some reason 2 months ago
Muthu Kumar 55aae5d732
chore: update email 2 months ago
Muthu Kumar 221bc03796
feat: add second project list 2 months ago
  1. 826
      bun.lock
  2. 26
      package.json
  3. 52
      src/components/AnimateEntry.tsx
  4. 77
      src/components/Container.tsx
  5. 247
      src/components/DraggableButton.tsx
  6. 83
      src/components/Flippable.tsx
  7. 218
      src/draggable.attempts/1/index.html
  8. 57
      src/draggable.attempts/2/index.html
  9. 292
      src/draggable.attempts/2/mod.ts
  10. 15
      src/draggable.attempts/2/vite.config.ts
  11. 321
      src/draggable.attempts/3/index.html
  12. 176
      src/draggable.attempts/4/index.html
  13. 15
      src/draggable.attempts/4/vite.config.ts
  14. 236
      src/draggable.attempts/5/Draggable.ts
  15. 40
      src/draggable.attempts/5/Draggable2.tsx
  16. 273
      src/draggable.attempts/6/Draggable.ts
  17. 55
      src/draggable.attempts/6/Draggable2.tsx
  18. 72
      src/draggable.attempts/6/index.html
  19. 15
      src/draggable.attempts/6/vite.config.ts
  20. 24
      src/index.css
  21. 254
      src/pages/main/Contact.tsx
  22. 13
      src/pages/main/Home.tsx
  23. 220
      src/pages/main/Work.tsx
  24. 87
      src/pages/main/data/project.ts
  25. 68
      src/util/index.ts
  26. 2
      tsconfig.json
  27. 2
      vite.config.ts

826
bun.lock

@ -0,0 +1,826 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "pw2",
"dependencies": {
"@emotion/css": "^11.13.5",
"date-fns": "^2.30.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"wouter": "^2.12.1",
},
"devDependencies": {
"@svgr/rollup": "^8.1.0",
"@types/gm": "^1.25.4",
"@types/marked": "^5.0.2",
"@types/react": "^18.3.20",
"@types/react-dom": "^18.3.6",
"@vitejs/plugin-react": "^4.3.4",
"gm": "^1.25.1",
"imagen": "github:MKRhere/imagen",
"marked": "^9.1.6",
"rollup-plugin-visualizer": "^5.14.0",
"typescript": "^5.8.3",
"vite": "^6.2.5",
},
},
},
"packages": {
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
"@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="],
"@babel/compat-data": ["@babel/compat-data@7.26.8", "", {}, "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ=="],
"@babel/core": ["@babel/core@7.26.10", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.10", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.10", "@babel/parser": "^7.26.10", "@babel/template": "^7.26.9", "@babel/traverse": "^7.26.10", "@babel/types": "^7.26.10", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ=="],
"@babel/generator": ["@babel/generator@7.27.0", "", { "dependencies": { "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw=="],
"@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.0", "", { "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA=="],
"@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-replace-supers": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/traverse": "^7.27.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg=="],
"@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ=="],
"@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw=="],
"@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.26.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw=="],
"@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.25.9", "", { "dependencies": { "@babel/types": "^7.25.9" } }, "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.26.5", "", {}, "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg=="],
"@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-wrap-function": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw=="],
"@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.26.5", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/traverse": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg=="],
"@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.25.9", "", { "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="],
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.25.9", "", {}, "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw=="],
"@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.25.9", "", { "dependencies": { "@babel/template": "^7.25.9", "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" } }, "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g=="],
"@babel/helpers": ["@babel/helpers@7.27.0", "", { "dependencies": { "@babel/template": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg=="],
"@babel/parser": ["@babel/parser@7.27.0", "", { "dependencies": { "@babel/types": "^7.27.0" }, "bin": "./bin/babel-parser.js" }, "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg=="],
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g=="],
"@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw=="],
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ["@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug=="],
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g=="],
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg=="],
"@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w=="],
"@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.26.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg=="],
"@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.26.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A=="],
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA=="],
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ=="],
"@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg=="],
"@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg=="],
"@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.26.8", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-remap-async-to-generator": "^7.25.9", "@babel/traverse": "^7.26.8" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg=="],
"@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.25.9", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-remap-async-to-generator": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ=="],
"@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.26.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ=="],
"@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ=="],
"@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.25.9", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q=="],
"@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.26.0", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ=="],
"@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9", "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg=="],
"@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/template": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA=="],
"@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ=="],
"@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA=="],
"@babel/plugin-transform-duplicate-keys": ["@babel/plugin-transform-duplicate-keys@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw=="],
"@babel/plugin-transform-duplicate-named-capturing-groups-regex": ["@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog=="],
"@babel/plugin-transform-dynamic-import": ["@babel/plugin-transform-dynamic-import@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg=="],
"@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.26.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ=="],
"@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww=="],
"@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.26.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg=="],
"@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.25.9", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA=="],
"@babel/plugin-transform-json-strings": ["@babel/plugin-transform-json-strings@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw=="],
"@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ=="],
"@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q=="],
"@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA=="],
"@babel/plugin-transform-modules-amd": ["@babel/plugin-transform-modules-amd@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw=="],
"@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.26.3", "", { "dependencies": { "@babel/helper-module-transforms": "^7.26.0", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ=="],
"@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA=="],
"@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.25.9", "", { "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw=="],
"@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA=="],
"@babel/plugin-transform-new-target": ["@babel/plugin-transform-new-target@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ=="],
"@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.26.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw=="],
"@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q=="],
"@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.25.9", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg=="],
"@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A=="],
"@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g=="],
"@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A=="],
"@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g=="],
"@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.25.9", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw=="],
"@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw=="],
"@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA=="],
"@babel/plugin-transform-react-constant-elements": ["@babel/plugin-transform-react-constant-elements@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow=="],
"@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ=="],
"@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/types": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw=="],
"@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.25.9", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw=="],
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg=="],
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg=="],
"@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.25.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg=="],
"@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "regenerator-transform": "^0.15.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA=="],
"@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.26.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw=="],
"@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg=="],
"@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng=="],
"@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A=="],
"@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA=="],
"@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.26.8", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q=="],
"@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+LLkxA9rKJpNoGsbLnAgOCdESl73vwYn+V6b+5wHbrE7OGKVDPHIQvbFSzqE6rwqaCw2RE+zdJrlLkcf8YOA0w=="],
"@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.27.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.27.0", "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg=="],
"@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.25.9", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q=="],
"@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg=="],
"@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA=="],
"@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.25.9", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ=="],
"@babel/preset-env": ["@babel/preset-env@7.26.9", "", { "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.26.0", "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.9", "@babel/plugin-transform-async-generator-functions": "^7.26.8", "@babel/plugin-transform-async-to-generator": "^7.25.9", "@babel/plugin-transform-block-scoped-functions": "^7.26.5", "@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-static-block": "^7.26.0", "@babel/plugin-transform-classes": "^7.25.9", "@babel/plugin-transform-computed-properties": "^7.25.9", "@babel/plugin-transform-destructuring": "^7.25.9", "@babel/plugin-transform-dotall-regex": "^7.25.9", "@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-exponentiation-operator": "^7.26.3", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-for-of": "^7.26.9", "@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-json-strings": "^7.25.9", "@babel/plugin-transform-literals": "^7.25.9", "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9", "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9", "@babel/plugin-transform-optional-catch-binding": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9", "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/plugin-transform-private-property-in-object": "^7.25.9", "@babel/plugin-transform-property-literals": "^7.25.9", "@babel/plugin-transform-regenerator": "^7.25.9", "@babel/plugin-transform-regexp-modifiers": "^7.26.0", "@babel/plugin-transform-reserved-words": "^7.25.9", "@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", "@babel/plugin-transform-template-literals": "^7.26.8", "@babel/plugin-transform-typeof-symbol": "^7.26.7", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9", "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.11.0", "babel-plugin-polyfill-regenerator": "^0.6.1", "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ=="],
"@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA=="],
"@babel/preset-react": ["@babel/preset-react@7.26.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-transform-react-display-name": "^7.25.9", "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/plugin-transform-react-jsx-development": "^7.25.9", "@babel/plugin-transform-react-pure-annotations": "^7.25.9" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw=="],
"@babel/preset-typescript": ["@babel/preset-typescript@7.27.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-syntax-jsx": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/plugin-transform-typescript": "^7.27.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vxaPFfJtHhgeOVXRKuHpHPAOgymmy8V8I65T1q53R7GCZlefKeCaTyDs3zOPHTTbmquvNlQYC5klEvWsBAtrBQ=="],
"@babel/runtime": ["@babel/runtime@7.27.0", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw=="],
"@babel/template": ["@babel/template@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA=="],
"@babel/traverse": ["@babel/traverse@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", "@babel/parser": "^7.27.0", "@babel/template": "^7.27.0", "@babel/types": "^7.27.0", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA=="],
"@babel/types": ["@babel/types@7.27.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg=="],
"@emotion/babel-plugin": ["@emotion/babel-plugin@11.13.5", "", { "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", "stylis": "4.2.0" } }, "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ=="],
"@emotion/cache": ["@emotion/cache@11.14.0", "", { "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA=="],
"@emotion/css": ["@emotion/css@11.13.5", "", { "dependencies": { "@emotion/babel-plugin": "^11.13.5", "@emotion/cache": "^11.13.5", "@emotion/serialize": "^1.3.3", "@emotion/sheet": "^1.4.0", "@emotion/utils": "^1.4.2" } }, "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w=="],
"@emotion/hash": ["@emotion/hash@0.9.2", "", {}, "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="],
"@emotion/memoize": ["@emotion/memoize@0.9.0", "", {}, "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="],
"@emotion/serialize": ["@emotion/serialize@1.3.3", "", { "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", "@emotion/utils": "^1.4.2", "csstype": "^3.0.2" } }, "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA=="],
"@emotion/sheet": ["@emotion/sheet@1.4.0", "", {}, "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="],
"@emotion/unitless": ["@emotion/unitless@0.10.0", "", {}, "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="],
"@emotion/utils": ["@emotion/utils@1.4.2", "", {}, "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA=="],
"@emotion/weak-memoize": ["@emotion/weak-memoize@0.4.0", "", {}, "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.2", "", { "os": "android", "cpu": "arm" }, "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.2", "", { "os": "android", "cpu": "x64" }, "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.2", "", { "os": "linux", "cpu": "arm" }, "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.2", "", { "os": "linux", "cpu": "x64" }, "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.2", "", { "os": "none", "cpu": "arm64" }, "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.2", "", { "os": "none", "cpu": "x64" }, "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.2", "", { "os": "win32", "cpu": "x64" }, "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@mapbox/node-pre-gyp": ["@mapbox/node-pre-gyp@1.0.11", "", { "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", "node-fetch": "^2.6.7", "nopt": "^5.0.0", "npmlog": "^5.0.1", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" }, "bin": { "node-pre-gyp": "bin/node-pre-gyp" } }, "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ=="],
"@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.39.0", "", { "os": "android", "cpu": "arm" }, "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.39.0", "", { "os": "android", "cpu": "arm64" }, "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.39.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.39.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.39.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.39.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.39.0", "", { "os": "linux", "cpu": "arm" }, "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.39.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA=="],
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw=="],
"@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.39.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.39.0", "", { "os": "linux", "cpu": "none" }, "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.39.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.39.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.39.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.39.0", "", { "os": "win32", "cpu": "x64" }, "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug=="],
"@svgr/babel-plugin-add-jsx-attribute": ["@svgr/babel-plugin-add-jsx-attribute@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g=="],
"@svgr/babel-plugin-remove-jsx-attribute": ["@svgr/babel-plugin-remove-jsx-attribute@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA=="],
"@svgr/babel-plugin-remove-jsx-empty-expression": ["@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA=="],
"@svgr/babel-plugin-replace-jsx-attribute-value": ["@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ=="],
"@svgr/babel-plugin-svg-dynamic-title": ["@svgr/babel-plugin-svg-dynamic-title@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og=="],
"@svgr/babel-plugin-svg-em-dimensions": ["@svgr/babel-plugin-svg-em-dimensions@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g=="],
"@svgr/babel-plugin-transform-react-native-svg": ["@svgr/babel-plugin-transform-react-native-svg@8.1.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q=="],
"@svgr/babel-plugin-transform-svg-component": ["@svgr/babel-plugin-transform-svg-component@8.0.0", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw=="],
"@svgr/babel-preset": ["@svgr/babel-preset@8.1.0", "", { "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", "@svgr/babel-plugin-transform-svg-component": "8.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug=="],
"@svgr/core": ["@svgr/core@8.1.0", "", { "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", "camelcase": "^6.2.0", "cosmiconfig": "^8.1.3", "snake-case": "^3.0.4" } }, "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA=="],
"@svgr/hast-util-to-babel-ast": ["@svgr/hast-util-to-babel-ast@8.0.0", "", { "dependencies": { "@babel/types": "^7.21.3", "entities": "^4.4.0" } }, "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q=="],
"@svgr/plugin-jsx": ["@svgr/plugin-jsx@8.1.0", "", { "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", "@svgr/hast-util-to-babel-ast": "8.0.0", "svg-parser": "^2.0.4" }, "peerDependencies": { "@svgr/core": "*" } }, "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA=="],
"@svgr/plugin-svgo": ["@svgr/plugin-svgo@8.1.0", "", { "dependencies": { "cosmiconfig": "^8.1.3", "deepmerge": "^4.3.1", "svgo": "^3.0.2" }, "peerDependencies": { "@svgr/core": "*" } }, "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA=="],
"@svgr/rollup": ["@svgr/rollup@8.1.0", "", { "dependencies": { "@babel/core": "^7.21.3", "@babel/plugin-transform-react-constant-elements": "^7.21.3", "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", "@babel/preset-typescript": "^7.21.0", "@rollup/pluginutils": "^5.0.2", "@svgr/core": "8.1.0", "@svgr/plugin-jsx": "8.1.0", "@svgr/plugin-svgo": "8.1.0" } }, "sha512-0XR1poYvPQoPpmfDYLEqUGu5ePAQ4pdgN3VFsZBNAeze7qubVpsIY1o1R6PZpKep/DKu33GSm2NhwpCLkMs2Cw=="],
"@trysound/sax": ["@trysound/sax@0.2.0", "", {}, "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="],
"@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
"@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
"@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="],
"@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
"@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
"@types/gm": ["@types/gm@1.25.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-123Spjn7f0eZZOiFlXCiloBRga+uczwAdZOlcgtva+I1h137ADcbC7I5B3SZToQBzYLMokYDlyPxRUozKSQ+Ow=="],
"@types/marked": ["@types/marked@5.0.2", "", {}, "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg=="],
"@types/node": ["@types/node@20.17.30", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg=="],
"@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="],
"@types/prop-types": ["@types/prop-types@15.7.14", "", {}, "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="],
"@types/react": ["@types/react@18.3.20", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg=="],
"@types/react-dom": ["@types/react-dom@18.3.6", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw=="],
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
"abbrev": ["abbrev@1.1.1", "", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="],
"agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"aproba": ["aproba@2.0.0", "", {}, "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="],
"are-we-there-yet": ["are-we-there-yet@2.0.0", "", { "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" } }, "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"array-parallel": ["array-parallel@0.1.3", "", {}, "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w=="],
"array-series": ["array-series@0.1.5", "", {}, "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg=="],
"babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="],
"babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.13", "", { "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.4", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g=="],
"babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.11.1", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.3", "core-js-compat": "^3.40.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ=="],
"babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.4", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.4" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="],
"caniuse-lite": ["caniuse-lite@1.0.30001712", "", {}, "sha512-MBqPpGYYdQ7/hfKiet9SCI+nmN5/hp4ZzveOJubl5DTAMa5oggjAuoi0Z4onBpKPFI2ePGnQuQIzF3VxDjDJig=="],
"cargo-cp-artifact": ["cargo-cp-artifact@0.1.9", "", { "bin": { "cargo-cp-artifact": "bin/cargo-cp-artifact.js" } }, "sha512-6F+UYzTaGB+awsTXg0uSJA1/b/B3DDJzpKVRu0UmyI7DmNeaAl2RFHuTGIN6fEgpadRxoXGb7gbC1xo4C3IdyA=="],
"chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"color-support": ["color-support@1.1.3", "", { "bin": { "color-support": "bin.js" } }, "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="],
"commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"console-control-strings": ["console-control-strings@1.1.0", "", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"core-js-compat": ["core-js-compat@3.41.0", "", { "dependencies": { "browserslist": "^4.24.4" } }, "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A=="],
"cosmiconfig": ["cosmiconfig@8.3.6", "", { "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0", "path-type": "^4.0.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"css-select": ["css-select@5.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg=="],
"css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="],
"css-what": ["css-what@6.1.0", "", {}, "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw=="],
"csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="],
"debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
"delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="],
"detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
"dot-case": ["dot-case@3.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w=="],
"electron-to-chromium": ["electron-to-chromium@1.5.134", "", {}, "sha512-zSwzrLg3jNP3bwsLqWHmS5z2nIOQ5ngMnfMZOWWtXnqqQkPVyOipxK98w+1beLw1TB+EImPNcG8wVP/cLVs2Og=="],
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
"esbuild": ["esbuild@0.25.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.2", "@esbuild/android-arm": "0.25.2", "@esbuild/android-arm64": "0.25.2", "@esbuild/android-x64": "0.25.2", "@esbuild/darwin-arm64": "0.25.2", "@esbuild/darwin-x64": "0.25.2", "@esbuild/freebsd-arm64": "0.25.2", "@esbuild/freebsd-x64": "0.25.2", "@esbuild/linux-arm": "0.25.2", "@esbuild/linux-arm64": "0.25.2", "@esbuild/linux-ia32": "0.25.2", "@esbuild/linux-loong64": "0.25.2", "@esbuild/linux-mips64el": "0.25.2", "@esbuild/linux-ppc64": "0.25.2", "@esbuild/linux-riscv64": "0.25.2", "@esbuild/linux-s390x": "0.25.2", "@esbuild/linux-x64": "0.25.2", "@esbuild/netbsd-arm64": "0.25.2", "@esbuild/netbsd-x64": "0.25.2", "@esbuild/openbsd-arm64": "0.25.2", "@esbuild/openbsd-x64": "0.25.2", "@esbuild/sunos-x64": "0.25.2", "@esbuild/win32-arm64": "0.25.2", "@esbuild/win32-ia32": "0.25.2", "@esbuild/win32-x64": "0.25.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"find-root": ["find-root@1.1.0", "", {}, "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="],
"fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"gauge": ["gauge@3.0.2", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.1", "object-assign": "^4.1.1", "signal-exit": "^3.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.2" } }, "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
"glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
"globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
"gm": ["gm@1.25.1", "", { "dependencies": { "array-parallel": "~0.1.3", "array-series": "~0.1.5", "cross-spawn": "^7.0.5", "debug": "^3.1.0" } }, "sha512-jgcs2vKir9hFogGhXIfs0ODhJTfIrbECCehg38tqFgHm8zqXx7kAJyCYAFK4jTjx71AxrkFtkJBawbAxYUPX9A=="],
"has-unicode": ["has-unicode@2.0.1", "", {}, "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
"imagen": ["imagen@github:MKRhere/imagen#c9988ae", { "dependencies": { "skia-canvas": "^0.9.30" } }, "MKRhere-imagen-c9988ae"],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
"is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
"lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="],
"marked": ["marked@9.1.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q=="],
"mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="],
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
"minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
"minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
"mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="],
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
"nopt": ["nopt@5.0.0", "", { "dependencies": { "abbrev": "1" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ=="],
"npmlog": ["npmlog@5.0.1", "", { "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", "gauge": "^3.0.0", "set-blocking": "^2.0.0" } }, "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw=="],
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
"open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"parenthesis": ["parenthesis@3.1.8", "", {}, "sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw=="],
"parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
"react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
"react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="],
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
"regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="],
"regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.0", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA=="],
"regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="],
"regenerator-transform": ["regenerator-transform@0.15.2", "", { "dependencies": { "@babel/runtime": "^7.8.4" } }, "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg=="],
"regexpu-core": ["regexpu-core@6.2.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA=="],
"regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="],
"regjsparser": ["regjsparser@0.12.0", "", { "dependencies": { "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ=="],
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
"resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
"rollup": ["rollup@3.29.5", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w=="],
"rollup-plugin-visualizer": ["rollup-plugin-visualizer@5.14.0", "", { "dependencies": { "open": "^8.4.0", "picomatch": "^4.0.2", "source-map": "^0.7.4", "yargs": "^17.5.1" }, "peerDependencies": { "rolldown": "1.x", "rollup": "2.x || 3.x || 4.x" }, "optionalPeers": ["rolldown", "rollup"], "bin": { "rollup-plugin-visualizer": "dist/bin/cli.js" } }, "sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
"simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="],
"simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="],
"skia-canvas": ["skia-canvas@0.9.30", "", { "dependencies": { "@mapbox/node-pre-gyp": "^1.0.9", "cargo-cp-artifact": "^0.1", "glob": "^8.0.3", "path-browserify": "^1.0.1", "simple-get": "^4.0.1", "string-split-by": "^1.0.0" } }, "sha512-Y4BZZhJpdGeRRfu/pyT1395UAE5Hgzup+P5tDq1vTTKcOgXmUuAWeDhvfeDn9FWaE6tNkOTQWO/mK7fdD5qIrw=="],
"snake-case": ["snake-case@3.0.4", "", { "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg=="],
"source-map": ["source-map@0.7.4", "", {}, "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"string-split-by": ["string-split-by@1.0.0", "", { "dependencies": { "parenthesis": "^3.1.5" } }, "sha512-KaJKY+hfpzNyet/emP81PJA9hTVSfxNLS9SFTWxdCnnW1/zOOwiV248+EfoX7IQFcBaOp4G5YE6xTJMF+pLg6A=="],
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"stylis": ["stylis@4.2.0", "", {}, "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"svg-parser": ["svg-parser@2.0.4", "", {}, "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="],
"svgo": ["svgo@3.3.2", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0" }, "bin": "./bin/svgo" }, "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw=="],
"tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
"unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="],
"unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="],
"unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.0", "", {}, "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg=="],
"unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.1.0", "", {}, "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w=="],
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"vite": ["vite@6.2.5", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA=="],
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="],
"wouter": ["wouter@2.12.1", "", { "dependencies": { "use-sync-external-store": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-G7a6JMSLSNcu6o8gdOfIzqxuo8Qx1qs+9rpVnlurH69angsSFPZP5gESNuVNeJct/MGpQg191pDo4HUjTx7IIQ=="],
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="],
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
"@babel/core/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@babel/helper-define-polyfill-provider/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@babel/traverse/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@emotion/babel-plugin/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="],
"@emotion/babel-plugin/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="],
"@mapbox/node-pre-gyp/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"agent-base/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"babel-plugin-macros/cosmiconfig": ["cosmiconfig@7.1.0", "", { "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" } }, "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA=="],
"csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"https-proxy-agent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"minizlib/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
"regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="],
"rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
"tar/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
"vite/rollup": ["rollup@4.39.0", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.39.0", "@rollup/rollup-android-arm64": "4.39.0", "@rollup/rollup-darwin-arm64": "4.39.0", "@rollup/rollup-darwin-x64": "4.39.0", "@rollup/rollup-freebsd-arm64": "4.39.0", "@rollup/rollup-freebsd-x64": "4.39.0", "@rollup/rollup-linux-arm-gnueabihf": "4.39.0", "@rollup/rollup-linux-arm-musleabihf": "4.39.0", "@rollup/rollup-linux-arm64-gnu": "4.39.0", "@rollup/rollup-linux-arm64-musl": "4.39.0", "@rollup/rollup-linux-loongarch64-gnu": "4.39.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.39.0", "@rollup/rollup-linux-riscv64-gnu": "4.39.0", "@rollup/rollup-linux-riscv64-musl": "4.39.0", "@rollup/rollup-linux-s390x-gnu": "4.39.0", "@rollup/rollup-linux-x64-gnu": "4.39.0", "@rollup/rollup-linux-x64-musl": "4.39.0", "@rollup/rollup-win32-arm64-msvc": "4.39.0", "@rollup/rollup-win32-ia32-msvc": "4.39.0", "@rollup/rollup-win32-x64-msvc": "4.39.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g=="],
"csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
"fs-minipass/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
"rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
}
}

26
package.json

@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"start": "vite --host",
"check": "tsc --noEmit",
"build": "tsc && vite build",
"serve": "vite preview",
"blog": "node scripts/blog.js"
@ -15,25 +16,24 @@
]
},
"dependencies": {
"@emotion/css": "^11.11.2",
"@emotion/css": "^11.13.5",
"date-fns": "^2.30.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"wouter": "^2.12.1"
},
"devDependencies": {
"@svgr/rollup": "^8.1.0",
"@types/gm": "^1.25.3",
"@types/gm": "^1.25.4",
"@types/marked": "^5.0.2",
"@types/node": "^20.8.7",
"@types/react": "^18.2.30",
"@types/react-dom": "^18.2.14",
"@vitejs/plugin-react": "^4.1.0",
"gm": "^1.25.0",
"@types/react": "^18.3.20",
"@types/react-dom": "^18.3.6",
"@vitejs/plugin-react": "^4.3.4",
"gm": "^1.25.1",
"imagen": "github:MKRhere/imagen",
"marked": "^9.1.2",
"rollup-plugin-visualizer": "^5.12.0",
"typescript": "^5.2.2",
"vite": "^4.5.0"
"marked": "^9.1.6",
"rollup-plugin-visualizer": "^5.14.0",
"typescript": "^5.8.3",
"vite": "^6.2.5"
}
}

52
src/components/AnimateEntry.tsx

@ -0,0 +1,52 @@
import React, { forwardRef } from "react";
import { css, cx } from "@emotion/css";
export interface AnimateEntryProps extends React.HTMLAttributes<any> {
as?: React.ElementType;
delay?: number;
}
export const AnimateEntry = forwardRef<HTMLDivElement, AnimateEntryProps>(
(
{ children, className, as: Component = "div", delay = 100, ...props },
ref,
) => {
return (
<Component
className={cx(
css`
& > * {
animation: slideIn 300ms backwards;
}
${React.Children.map(
children,
(child, i) =>
child &&
css`
& > *:nth-child(${i + 1}) {
animation-delay: ${i * delay}ms;
}
`,
)}
@keyframes slideIn {
from {
opacity: 0;
translate: 0 3rem;
}
to {
opacity: 1;
translate: 0 0;
}
}
`,
className,
)}
{...props}
ref={ref}>
{children}
</Component>
);
},
);

77
src/components/Container.tsx

@ -7,18 +7,16 @@ import { ReactComponent as Right } from "../assets/arrow-right.svg";
import { get, getTimeout } from "../util";
import Menu, { MenuEntries } from "./Menu";
import useMediaQuery from "../util/useMediaQuery";
import { AnimateEntry } from "./AnimateEntry";
const [timer, clear] = getTimeout();
const Container: React.FC<{
children: (
| string
| React.DetailedReactHTMLElement<any, HTMLElement>
| React.ReactElement
)[];
children: React.ReactNode | React.ReactNode[];
hideNav?: boolean;
className?: string;
}> = ({ children: _children, hideNav = false, className, ...props }) => {
delay?: number;
}> = ({ children, hideNav = false, className, delay = 100, ...props }) => {
const [location, navigate] = useLocation();
const mobile = useMediaQuery("(max-width: 50rem)");
@ -30,27 +28,6 @@ const Container: React.FC<{
const [showMenu, setShowMenu] = useState(false);
const children = React.Children.map(
_children,
(
child:
| string
| React.DetailedReactHTMLElement<any, HTMLElement>
| React.ReactElement,
) =>
!child || typeof child === "string"
? child
: React.cloneElement(child, {
...child.props,
style: {
...child.props.style,
opacity: 0,
transform: "translateY(3rem)",
transition: "all 300ms",
},
}),
);
useEffect(() => {
// scroll back to top when new page is loaded
window.scrollTo({ top: 0 });
@ -73,19 +50,6 @@ const Container: React.FC<{
);
}
if (containerChild.current) {
const containerChildren = [...containerChild.current.children] as (
| HTMLElement
| SVGElement
)[];
containerChildren.forEach((child, idx) => {
timer(() => {
child.style.removeProperty("opacity");
child.style.removeProperty("transform");
}, 100 * idx);
});
}
// cleanup
return clear;
}, []);
@ -163,9 +127,13 @@ const Container: React.FC<{
return (
<div
className={css`
padding-block-start: 15rem;
padding-block-end: 8rem;
padding-inline: 10vw;
--cntr-pad-b-start: 12rem;
--cntr-pad-b-end: 8rem;
--cntr-pad-inline: 10vw;
--logo-size: 5rem;
padding-block-start: var(--cntr-pad-b-start);
padding-block-end: var(--cntr-pad-b-end);
padding-inline: var(--cntr-pad-inline);
overflow: hidden;
min-height: 100vh;
position: relative;
@ -179,7 +147,7 @@ const Container: React.FC<{
width: 100vw;
left: 0;
bottom: 0;
height: 8rem;
height: 8vh;
background: rgb(0, 0, 0);
background: linear-gradient(
180deg,
@ -196,8 +164,13 @@ const Container: React.FC<{
ref={logoContainer}
className={css`
position: absolute;
top: 8rem;
left: 5rem;
/* prettier-ignore */
top: calc(
calc(var(--cntr-pad-b-start) / 2)
- calc(var(--logo-size) / 2)
+ 1rem
);
left: var(--cntr-pad-inline);
background: none;
border: 0;
font-size: 1rem;
@ -211,8 +184,8 @@ const Container: React.FC<{
css`
position: absolute;
left: 0;
height: 5rem;
width: 5rem;
height: var(--logo-size);
width: var(--logo-size);
border-radius: 100%;
border: 0;
background: none;
@ -311,23 +284,25 @@ const Container: React.FC<{
`}
/>
</button>
<div
<AnimateEntry
delay={delay}
className={cx(
css`
width: 100%;
max-width: 62rem;
min-height: 100%;
margin: auto;
gap: 2rem;
display: flex;
flex-direction: column;
gap: 2rem;
position: relative;
`,
className,
)}
ref={containerChild}
{...props}>
{children}
</div>
</AnimateEntry>
</div>
);
};

247
src/components/DraggableButton.tsx

@ -0,0 +1,247 @@
import { css, cx } from "@emotion/css";
import React, { useEffect, useRef, useState } from "react";
import { composeRefs } from "../util";
const isOutsideViewport = (el: HTMLElement) => {
const rect = el.getBoundingClientRect();
const isOutside =
rect.right < 0 ||
rect.left > window.innerWidth ||
rect.bottom < 0 ||
rect.top > window.innerHeight;
return isOutside;
};
export interface DraggableButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
onOutsideViewport?: () => void;
}
interface Pos {
x: number;
y: number;
rot: number;
touchOffsetX?: number;
touchOffsetY?: number;
}
interface Velocity extends Pos {
timestamp: number;
}
const relativePos = (pos: Pos, container: DOMRect) => {
return {
x: pos.x - container.left,
y: pos.y - container.top,
};
};
const getEventPos = (e: MouseEvent | TouchEvent): Pos => {
if ("touches" in e)
return {
x: e.touches[0].clientX,
y: e.touches[0].clientY,
rot: 0,
};
return {
x: e.clientX,
y: e.clientY,
rot: 0,
};
};
export const DraggableButton = React.forwardRef<
HTMLButtonElement,
DraggableButtonProps
>(({ children, onOutsideViewport, ...props }, ref) => {
const [transform, setTransform] = useState<Pos>({ x: 0, y: 0, rot: 0 });
const [isDragging, setIsDragging] = useState(false);
const [dragStart, setDragStart] = useState<Pos | null>(null);
const myRef = useRef<HTMLButtonElement | null>(null);
const containerRef = useRef<DOMRect | null>(null);
const lastVelocity = useRef<Velocity>({ x: 0, y: 0, rot: 0, timestamp: 0 });
const lastPosition = useRef<Pos>({ x: 0, y: 0, rot: 0 });
const animationFrame = useRef<number>();
const [isOutside, setIsOutside] = useState(false);
useEffect(() => {
if (isOutside) onOutsideViewport?.();
}, [isOutside, onOutsideViewport]);
const updateContainerRef = () => {
if (myRef.current?.parentElement) {
containerRef.current =
myRef.current.parentElement.getBoundingClientRect();
}
};
const handleStart = (e: MouseEvent | TouchEvent) => {
if (!myRef.current) return;
if ("touches" in e) e.preventDefault();
updateContainerRef();
if (!containerRef.current) return;
if (animationFrame.current) cancelAnimationFrame(animationFrame.current);
const eventPos = getEventPos(e);
setDragStart({
x: eventPos.x,
y: eventPos.y,
rot: transform.rot,
});
lastPosition.current = eventPos;
lastVelocity.current = { x: 0, y: 0, rot: 0, timestamp: performance.now() };
setIsDragging(true);
};
const handleMove = (e: MouseEvent | TouchEvent) => {
if (!isDragging || !dragStart || !containerRef.current) return;
if ("touches" in e) e.preventDefault();
const currentPos = getEventPos(e);
// Calculate movement since last frame
const frameDelta = {
x: currentPos.x - lastPosition.current.x,
y: currentPos.y - lastPosition.current.y,
};
const now = performance.now();
const elapsed = now - lastVelocity.current.timestamp;
if (elapsed > 0) {
lastVelocity.current = {
x: (frameDelta.x / elapsed) * 16,
y: (frameDelta.y / elapsed) * 16,
rot: 0,
timestamp: now,
};
}
// Calculate rotation based on horizontal movement
const ROTATION_FACTOR = 0.2;
const rotationDelta = frameDelta.x * ROTATION_FACTOR;
lastPosition.current = currentPos;
// Update transform based on frame delta
setTransform(prev => ({
x: prev.x + frameDelta.x,
y: prev.y + frameDelta.y,
rot: prev.rot + rotationDelta,
}));
};
const handleEnd = () => {
setIsDragging(false);
if (
Math.abs(lastVelocity.current.x) > 0.1 ||
Math.abs(lastVelocity.current.y) > 0.1
)
animationFrame.current = requestAnimationFrame(applyMomentum);
if (myRef.current && isOutsideViewport(myRef.current)) setIsOutside(true);
};
const applyMomentum = () => {
const now = performance.now();
const elapsed = now - lastVelocity.current.timestamp;
const decay = Math.pow(0.7, elapsed / 16);
const newVelocity = {
x: lastVelocity.current.x * decay,
y: lastVelocity.current.y * decay,
rot: lastVelocity.current.rot * decay,
timestamp: now,
};
if (Math.abs(newVelocity.x) < 0.01 && Math.abs(newVelocity.y) < 0.01) {
cancelAnimationFrame(animationFrame.current!);
return;
}
setTransform(prev => ({
x: prev.x + newVelocity.x,
y: prev.y + newVelocity.y,
rot: prev.rot,
}));
lastVelocity.current = newVelocity;
animationFrame.current = requestAnimationFrame(applyMomentum);
};
useEffect(() => {
if (!myRef.current) return;
const el = myRef.current;
// Always listen for drag start
el.addEventListener("mousedown", handleStart, { passive: false });
el.addEventListener("touchstart", handleStart, { passive: false });
// Only add move/end handlers when dragging
if (isDragging) {
window.addEventListener("mousemove", handleMove, { passive: false });
window.addEventListener("touchmove", handleMove, { passive: false });
window.addEventListener("mouseup", handleEnd);
window.addEventListener("touchend", handleEnd);
window.addEventListener("touchcancel", handleEnd);
}
return () => {
if (animationFrame.current) {
cancelAnimationFrame(animationFrame.current);
}
el.removeEventListener("mousedown", handleStart);
el.removeEventListener("touchstart", handleStart);
window.removeEventListener("mousemove", handleMove);
window.removeEventListener("touchmove", handleMove);
window.removeEventListener("mouseup", handleEnd);
window.removeEventListener("touchend", handleEnd);
window.removeEventListener("touchcancel", handleEnd);
};
}, [isDragging]);
useEffect(() => {
const el = myRef.current;
if (!el) return;
// Apply transform
el.style.transform = `translate(${transform.x}px, ${transform.y}px) rotate(${transform.rot}deg)`;
if (!isDragging && isOutsideViewport(el)) setIsOutside(true);
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") setIsDragging(false);
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [transform, isDragging]);
return (
<button
ref={composeRefs(myRef, ref)}
{...props}
className={cx(
props.className,
css`
position: absolute;
transition: none;
cursor: ${isDragging ? "grabbing" : "grab"};
touch-action: none;
will-change: transform;
.dynamic-gradient {
cursor: inherit;
}
`,
)}>
{children}
</button>
);
});

83
src/components/Flippable.tsx

@ -0,0 +1,83 @@
import { css, cx } from "@emotion/css";
import React, { useState, useRef } from "react";
export interface FlippableProps {
front: React.ReactNode;
back: React.ReactNode;
className?: string;
defaultFlipped?: boolean;
}
export const Flippable: React.FC<FlippableProps> = ({
front,
back,
className,
defaultFlipped,
}) => {
const ref = useRef<HTMLDivElement>(null);
const [isFlipped, setIsFlipped] = useState(defaultFlipped);
const mouseDownTime = useRef<number>(0);
const DRAG_THRESHOLD = 250; // milliseconds
const down = () => {
mouseDownTime.current = Date.now();
};
const up = () => {
if (Date.now() - mouseDownTime.current < DRAG_THRESHOLD) {
setIsFlipped(prev => !prev);
ref.current?.animate(
[
{ transform: "scale(1)" },
{ transform: "scale(1.2)", offset: 0.4 },
{ transform: "scale(1.2)", offset: 0.6 },
{ transform: "scale(1)" },
],
{
duration: 600,
easing: "cubic-bezier(0.4, 0, 0.2, 1)",
},
);
}
};
return (
<div
ref={ref}
onPointerUp={up}
onPointerDown={down}
className={cx(
css`
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
cursor: pointer;
transition: rotate 0.6s cubic-bezier(0.4, 0, 0.2, 1);
rotate: ${isFlipped ? "y 180deg" : "y 0deg"};
.card-face {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
-webkit-backface-visibility: hidden; /* Safari */
}
.card-front {
pointer-events: ${isFlipped ? "none" : "auto"};
}
.card-back {
rotate: y 180deg;
pointer-events: ${isFlipped ? "auto" : "none"};
}
`,
className,
)}>
<div className="card-face card-front">{front}</div>
<div className="card-face card-back">{back}</div>
</div>
);
};

218
src/draggable.attempts/1/index.html

@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="container">
<div id="rectangle"></div>
</div>
<style>
#container {
position: relative;
width: 100%;
height: 600px;
overflow: hidden;
background-color: #f0f0f0;
}
#rectangle {
position: absolute;
width: 200px;
height: 120px;
background-color: #3498db;
border-radius: 8px;
cursor: grab;
user-select: none;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transform-origin: center;
transition: box-shadow 0.2s ease;
}
#rectangle:active {
cursor: grabbing;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const rectangle = document.getElementById("rectangle");
const container = document.getElementById("container");
// Position and movement state
let isDragging = false;
let currentX = 50;
let currentY = 50;
let rotation = 0;
// Drag state tracking
let dragPointX = 0;
let dragPointY = 0;
let prevMouseX = 0;
let prevMouseY = 0;
// Physics constants
const friction = 0.95; // General friction (higher = less friction)
const rotationFactor = 0.1; // How much rotation is applied (lower = less rotation)
// Momentum tracking
let momentumX = 0;
let momentumY = 0;
let angularMomentum = 0;
let momentumAnimationId = null;
// Initialize position
setTransform(currentX, currentY, rotation);
function setTransform(x, y, rot) {
currentX = x;
currentY = y;
rotation = rot;
rectangle.style.transform = `translate(${x}px, ${y}px) rotate(${rot}deg)`;
}
function getRectCenter() {
const rect = rectangle.getBoundingClientRect();
return {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
};
}
// Start dragging
rectangle.addEventListener("mousedown", dragStart);
rectangle.addEventListener("touchstart", dragStart, { passive: false });
function dragStart(e) {
e.preventDefault();
if (momentumAnimationId !== null) {
cancelAnimationFrame(momentumAnimationId);
momentumAnimationId = null;
}
// Get event coordinates
const eventX =
e.type === "touchstart" ? e.touches[0].clientX : e.clientX;
const eventY =
e.type === "touchstart" ? e.touches[0].clientY : e.clientY;
// Record where on the card we're dragging from (relative to its center)
const center = getRectCenter();
dragPointX = eventX - center.x;
dragPointY = eventY - center.y;
// Initialize previous mouse position for momentum calculations
prevMouseX = eventX;
prevMouseY = eventY;
isDragging = true;
momentumX = 0;
momentumY = 0;
angularMomentum = 0;
}
// Drag movement
document.addEventListener("mousemove", drag);
document.addEventListener("touchmove", drag, { passive: false });
function drag(e) {
if (!isDragging) return;
e.preventDefault();
// Get event coordinates
const eventX =
e.type === "touchmove" ? e.touches[0].clientX : e.clientX;
const eventY =
e.type === "touchmove" ? e.touches[0].clientY : e.clientY;
// Calculate movement delta
const dx = eventX - prevMouseX;
const dy = eventY - prevMouseY;
// Update position based on direct movement
const newX = currentX + dx;
const newY = currentY + dy;
// Calculate rotation based on the movement direction and drag point
// The further from center, the more leverage for rotation
const dragDistance = Math.sqrt(
dragPointX * dragPointX + dragPointY * dragPointY,
);
// Calculate the tangential component of movement
// We use the cross product to determine how much the movement is perpendicular to the radius
const tangentialForce =
(dx * dragPointY - dy * dragPointX) / (dragDistance || 1);
// Apply rotation with distance-based scaling
// This mimics the lever effect - further from center = more rotation
const rotationDelta =
tangentialForce * rotationFactor * (dragDistance / 100 + 0.5);
const newRotation = rotation + rotationDelta;
// Update momentum for after drag ends
momentumX = dx * 0.9; // Reduced to prevent excessive sliding
momentumY = dy * 0.9;
angularMomentum = rotationDelta * 0.9;
// Apply the transforms
setTransform(newX, newY, newRotation);
// Update previous mouse position
prevMouseX = eventX;
prevMouseY = eventY;
}
// End dragging
document.addEventListener("mouseup", dragEnd);
document.addEventListener("touchend", dragEnd);
function dragEnd() {
if (isDragging) {
isDragging = false;
applyMomentum();
}
}
// Apply momentum after release with friction
function applyMomentum() {
if (
Math.abs(momentumX) < 0.1 &&
Math.abs(momentumY) < 0.1 &&
Math.abs(angularMomentum) < 0.01
) {
momentumAnimationId = null;
return; // Stop if momentum is very small
}
// Apply friction
momentumX *= friction;
momentumY *= friction;
angularMomentum *= friction;
// Apply momentum
setTransform(
currentX + momentumX,
currentY + momentumY,
rotation + angularMomentum,
);
// Continue applying momentum
momentumAnimationId = requestAnimationFrame(applyMomentum);
}
// Handle edge cases
document.addEventListener("mouseleave", function () {
if (isDragging) {
isDragging = false;
applyMomentum();
}
});
});
</script>
</body>
</html>

57
src/draggable.attempts/2/index.html

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<style>
body {
width: 100vw;
height: 100vh;
margin: 40px;
padding: 0;
}
#rectangle {
width: 200px;
height: 120px;
background-color: #3498db;
cursor: grab;
user-select: none;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
position: relative;
}
#handle {
width: 10px;
height: 10px;
background-color: #e74c3c;
border-radius: 50%;
position: absolute;
top: 0;
left: 0;
margin-left: -5px;
margin-top: -5px;
pointer-events: none;
}
#reference {
width: 200px;
height: 120px;
position: absolute;
top: 0;
left: 0;
opacity: 0.2;
background-color: #2ecc71;
pointer-events: none;
}
</style>
<div id="rectangle">
<div id="handle"></div>
</div>
<div id="reference"></div>
<script type="module" src="mod.ts"></script>
</body>
</html>

292
src/draggable.attempts/2/mod.ts

@ -0,0 +1,292 @@
const rectangle = document.getElementById("rectangle")!;
const handle = document.getElementById("handle")!;
const reference = document.getElementById("reference")!;
class Vec2 {
constructor(public x: number, public y: number) {}
toString() {
return `Vec<${this.x.toString().padStart(3, " ")}, ${this.y
.toString()
.padStart(3, " ")}>`;
}
clone() {
return new Vec2(this.x, this.y);
}
eq(v: Vec2) {
return this.x === v.x && this.y === v.y;
}
add(x: number, y: number): Vec2;
add(v: Vec2): Vec2;
add(c: number): Vec2;
add(x: number | Vec2, y?: number) {
if (x instanceof Vec2) return new Vec2(this.x + x.x, this.y + x.y);
if (typeof y === "number") return new Vec2(this.x + x, this.y + y);
return new Vec2(this.x + x, this.y + x);
}
sub(x: number, y: number): Vec2;
sub(v: Vec2): Vec2;
sub(c: number): Vec2;
sub(x: number | Vec2, y?: number) {
if (x instanceof Vec2) return new Vec2(this.x - x.x, this.y - x.y);
if (typeof y === "number") return new Vec2(this.x - x, this.y - y);
return new Vec2(this.x - x, this.y - x);
}
mult(x: number, y: number): Vec2;
mult(v: Vec2): Vec2;
mult(c: number): Vec2;
mult(x: number | Vec2, y?: number) {
if (x instanceof Vec2) return new Vec2(this.x * x.x, this.y * x.y);
if (typeof y === "number") return new Vec2(this.x * x, this.y * y);
return new Vec2(this.x * x, this.y * x);
}
div(x: number, y: number): Vec2;
div(v: Vec2): Vec2;
div(c: number): Vec2;
div(x: number | Vec2, y?: number) {
if (x instanceof Vec2) return new Vec2(this.x / x.x, this.y / x.y);
if (typeof y === "number") return new Vec2(this.x / x, this.y / y);
return new Vec2(this.x / x, this.y / x);
}
}
class State {
public dragging: boolean;
public origin: Vec2;
public pos: Vec2;
public size: Vec2;
public rot: number;
public cursor: Vec2;
constructor({
dragging,
origin,
pos,
size,
rot,
cursor,
}: {
dragging: boolean;
origin: Vec2;
pos: Vec2;
size: Vec2;
rot: number;
cursor: Vec2;
}) {
this.dragging = dragging;
this.origin = origin;
this.pos = pos;
this.size = size;
this.rot = rot;
this.cursor = cursor;
}
toString() {
return (
`State [\n` +
` dragging: ${this.dragging},\n` +
` origin: ${this.origin},\n` +
` pos: ${this.pos},\n` +
` rot: ${this.rot},\n` +
` cursor: ${this.cursor}\n` +
`]`
);
}
clone() {
return new State({
dragging: this.dragging,
origin: this.origin.clone(),
size: this.size.clone(),
pos: this.pos.clone(),
rot: this.rot,
cursor: this.cursor?.clone(),
});
}
eq(s: State) {
return (
this.dragging === s.dragging &&
this.origin.eq(s.origin) &&
this.pos.eq(s.pos) &&
this.rot === s.rot &&
this.cursor.eq(s.cursor)
);
}
}
function getCursorPositionRelativeToElement(
cursor: Vec2,
size: Vec2,
element: HTMLElement,
) {
const boundingRect = element.getBoundingClientRect();
const computedStyle = window.getComputedStyle(element);
const transformValue = computedStyle.transform;
if (transformValue === "none" || !transformValue)
return cursor.sub(boundingRect.left, boundingRect.top);
const matrix = new DOMMatrix(transformValue);
const centerX = boundingRect.left + boundingRect.width / 2;
const centerY = boundingRect.top + boundingRect.height / 2;
// temporarily convert relative to center for easier calculations
const relativeToCenter = {
x: cursor.x - centerX,
y: cursor.y - centerY,
};
const inverseMatrix = matrix.inverse();
inverseMatrix.e = 0;
inverseMatrix.f = 0;
const transformedPoint = {
x:
relativeToCenter.x * inverseMatrix.a +
relativeToCenter.y * inverseMatrix.c,
y:
relativeToCenter.x * inverseMatrix.b +
relativeToCenter.y * inverseMatrix.d,
};
// restore relative to top-left
return new Vec2(
transformedPoint.x + size.x / 2,
transformedPoint.y + size.y / 2,
);
}
interface Transform {
translation: Vec2; // equivalent to state.pos
rotation: number; // equivalent to state.rot
scale?: Vec2; // if you need scaling, defaults to (1,1)
origin: Vec2; // equivalent to state.origin
}
function getCursorPositionRelativeToElement2(
cursor: Vec2, // cursor in page coordinates
size: Vec2, // original element size
transform: Transform,
) {
const scale = transform.scale ?? new Vec2(1, 1);
// First get cursor position relative to the element's translated position
const relativeToElement = cursor.sub(transform.translation);
// Calculate the actual pivot point (origin) for transformations
const pivotPoint = transform.origin;
// Get position relative to pivot point
const relativeToPivot = relativeToElement.sub(pivotPoint);
// Apply inverse rotation around pivot
const cosTheta = Math.cos(-transform.rotation);
const sinTheta = Math.sin(-transform.rotation);
const rotatedPoint = new Vec2(
relativeToPivot.x * cosTheta - relativeToPivot.y * sinTheta,
relativeToPivot.x * sinTheta + relativeToPivot.y * cosTheta,
);
// Apply inverse scale if present
const scaledPoint = transform.scale ? rotatedPoint.div(scale) : rotatedPoint;
// Add back pivot offset to get final position
return scaledPoint.add(pivotPoint);
}
const rect = rectangle.getBoundingClientRect();
// state is the source of truth
const state = new State({
dragging: false,
// initial origin
origin: new Vec2(rect.width / 2, rect.height / 2),
// initial position of the rectangle
pos: new Vec2(0, 0),
// size of the rectangle
size: new Vec2(rect.width, rect.height),
// initial rotation
rot: 0,
// placeholder cursor position
cursor: new Vec2(0, 0),
});
{
rectangle.style.transformOrigin = `${state.origin.x}px ${state.origin.y}px`;
rectangle.style.transform = `translate(${state.pos.x}px, ${state.pos.y}px) rotate(${state.rot}rad)`;
handle.style.transform = `translate(${state.origin.x}px, ${state.origin.y}px)`;
}
let prev = state.clone();
{
const rect = rectangle.getBoundingClientRect();
reference.style.transformOrigin = `${state.origin.x}px ${state.origin.y}px`;
reference.style.transform = `translate(${rect.left}px, ${rect.top}px)`;
reference.style.width = `${rect.width}px`;
reference.style.height = `${rect.height}px`;
}
rectangle.addEventListener("mousedown", e => {
prev = state.clone();
state.dragging = true;
});
window.addEventListener("mouseup", () => {
state.dragging = false;
});
const degree = 180 / Math.PI;
window.addEventListener("mousemove", e => {
state.cursor = new Vec2(e.pageX, e.pageY);
if (!state.dragging) return;
const deltaCursor = state.cursor.sub(prev.cursor);
state.pos = state.pos.add(deltaCursor);
const rect = rectangle.getBoundingClientRect();
reference.style.transformOrigin = `${state.origin.x}px ${state.origin.y}px`;
reference.style.transform = `translate(${rect.left}px, ${rect.top}px)`;
reference.style.width = `${rect.width}px`;
reference.style.height = `${rect.height}px`;
// state.origin = state.cursor.sub(new Vec2(rect.left, rect.top));
// state.rot = 0.05 + prev.rot;
state.origin = getCursorPositionRelativeToElement2(
state.cursor,
state.size,
// rectangle,
{
translation: state.pos,
rotation: state.rot,
origin: state.origin,
},
);
if (!state.eq(prev)) {
// always keep DOM updated to state
rectangle.style.transformOrigin = `${state.origin.x}px ${state.origin.y}px`;
rectangle.style.transform = `translate(${state.pos.x}px, ${state.pos.y}px) rotate(${state.rot}rad)`;
handle.style.transform = `translate(${state.origin.x}px, ${state.origin.y}px)`;
}
prev = state.clone();
});

15
src/draggable.attempts/2/vite.config.ts

@ -0,0 +1,15 @@
import { defineConfig } from "vite";
import { resolve } from "path";
// https://vitejs.dev/config/
export default defineConfig({
server: { port: 10000, allowedHosts: ["dev.mkr.thefeathers.co"] },
plugins: [],
build: {
rollupOptions: {
input: {
main: resolve(__dirname, "index.html"),
},
},
},
});

321
src/draggable.attempts/3/index.html

@ -0,0 +1,321 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cursor Position in Transformed Element</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f5f5f5;
}
.container {
margin: 50px;
position: relative;
width: 600px;
height: 400px;
border: 1px solid #ccc;
background-color: #fff;
}
#transformed-element {
position: absolute;
width: 200px;
height: 150px;
background-color: rgba(100, 150, 250, 0.5);
border: 2px solid #4080ff;
top: 125px;
left: 200px;
transform-origin: center center;
transform: rotate(30deg) scale(1.2, 0.9);
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
color: #333;
}
#position-indicator {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(255, 255, 255, 0.8);
padding: 5px 10px;
border-radius: 5px;
font-family: monospace;
font-size: 14px;
}
#cursor-dot {
position: absolute;
top: 0;
left: 0;
width: 6px;
height: 6px;
background-color: red;
border-radius: 50%;
margin-left: -3px;
margin-top: -3px;
pointer-events: none;
}
#controls {
margin-bottom: 20px;
display: flex;
gap: 20px;
align-items: center;
}
.control-group {
display: flex;
flex-direction: column;
gap: 5px;
}
label {
font-size: 12px;
color: #666;
}
.status {
margin-top: 15px;
font-size: 14px;
font-weight: bold;
}
#inside-status {
margin-left: 20px;
}
</style>
</head>
<body>
<h1>Cursor Position in Transformed Element</h1>
<div id="controls">
<div class="control-group">
<label for="rotation">Rotation (degrees)</label>
<input
type="range"
id="rotation"
min="-180"
max="180"
value="30"
step="5"
/>
</div>
<div class="control-group">
<label for="scale-x">Scale X</label>
<input
type="range"
id="scale-x"
min="0.5"
max="2"
value="1.2"
step="0.1"
/>
</div>
<div class="control-group">
<label for="scale-y">Scale Y</label>
<input
type="range"
id="scale-y"
min="0.5"
max="2"
value="0.9"
step="0.1"
/>
</div>
<div class="control-group">
<label for="translate-x">Translate X</label>
<input
type="range"
id="translate-x"
min="-100"
max="100"
value="0"
step="0.1"
/>
</div>
<div class="control-group">
<label for="translate-y">Translate Y</label>
<input
type="range"
id="translate-y"
min="-100"
max="100"
value="0"
step="0.1"
/>
</div>
</div>
<div class="status">
Element coordinates: <span id="coords"></span>
<span id="inside-status">Outside element</span>
</div>
<div class="container">
<div id="position-indicator">Position: (0, 0)</div>
<div id="transformed-element">
Transformed Element
<div id="cursor-dot"></div>
</div>
</div>
<script>
/**
* Calculate cursor position relative to a transformed DOM element's original coordinate system
*
* @param {MouseEvent} event - The mouse event containing cursor position
* @param {HTMLElement} element - The transformed DOM element
* @returns {Object} - The x,y coordinates relative to the element's internal coordinate system
*/
function getCursorPositionRelativeToElement(event, element) {
// Get the mouse coordinates in client space
const clientX = event.clientX;
const clientY = event.clientY;
// Get the element's current bounding box (includes transformation effects)
const boundingRect = element.getBoundingClientRect();
// If no transform is applied, do simple calculation
const computedStyle = window.getComputedStyle(element);
const transformValue =
computedStyle.transform ||
computedStyle.webkitTransform ||
computedStyle.mozTransform;
if (transformValue === "none" || !transformValue) {
return {
x: clientX - boundingRect.left,
y: clientY - boundingRect.top,
};
}
// Create a matrix from the transform string
const matrix = new DOMMatrix(transformValue);
// Get the element's dimensions
const width = element.offsetWidth;
const height = element.offsetHeight;
// Calculate the center of the transformed element
const centerX = boundingRect.left + boundingRect.width / 2;
const centerY = boundingRect.top + boundingRect.height / 2;
// Calculate mouse position relative to the element's transformed center
const relativeToCenter = {
x: clientX - centerX,
y: clientY - centerY,
};
// Create the inverse of the transformation matrix
const inverseMatrix = matrix.inverse();
// Remove the translation components from the inverse matrix
inverseMatrix.e = 0;
inverseMatrix.f = 0;
// Apply the inverse transformation (rotation and scaling only)
const transformedPoint = {
x:
relativeToCenter.x * inverseMatrix.a +
relativeToCenter.y * inverseMatrix.c,
y:
relativeToCenter.x * inverseMatrix.b +
relativeToCenter.y * inverseMatrix.d,
};
// Convert from center-relative to top-left-relative coordinates
return {
x: transformedPoint.x + width / 2,
y: transformedPoint.y + height / 2,
};
}
// DOM elements
const element = document.getElementById("transformed-element");
const indicator = document.getElementById("position-indicator");
const cursorDot = document.getElementById("cursor-dot");
const coordsDisplay = document.getElementById("coords");
const insideStatus = document.getElementById("inside-status");
// Control elements
const rotationControl = document.getElementById("rotation");
const scaleXControl = document.getElementById("scale-x");
const scaleYControl = document.getElementById("scale-y");
const translateXControl = document.getElementById("translate-x");
const translateYControl = document.getElementById("translate-y");
// Update transform based on controls
function updateTransform() {
const rotation = rotationControl.value;
const scaleX = scaleXControl.value;
const scaleY = scaleYControl.value;
const translateX = translateXControl.value;
const translateY = translateYControl.value;
element.style.transform = `rotate(${rotation}deg) scale(${scaleX}, ${scaleY}) translate(${translateX}px, ${translateY}px)`;
}
// Listen to control changes
rotationControl.addEventListener("input", updateTransform);
scaleXControl.addEventListener("input", updateTransform);
scaleYControl.addEventListener("input", updateTransform);
translateXControl.addEventListener("input", updateTransform);
translateYControl.addEventListener("input", updateTransform);
// Track mouse movement
document.addEventListener("mousemove", event => {
// Show cursor dot
// cursorDot.style.left = `${event.clientX}px`;
// cursorDot.style.top = `${event.clientY}px`;
// Get relative position
const relativePos = getCursorPositionRelativeToElement(event, element);
// Round values for display
const x = Math.round(relativePos.x);
const y = Math.round(relativePos.y);
// Update position indicator
indicator.textContent = `Position: (${x}, ${y})`;
coordsDisplay.textContent = `(${x}, ${y})`;
// Check if cursor is within original element dimensions
const isInside =
relativePos.x >= 0 &&
relativePos.x <= element.offsetWidth &&
relativePos.y >= 0 &&
relativePos.y <= element.offsetHeight;
// Update status indicators
if (isInside) {
insideStatus.textContent = "Inside element";
insideStatus.style.color = "green";
coordsDisplay.style.color = "green";
cursorDot.style.transform = `translate(${relativePos.x}px, ${relativePos.y}px)`;
cursorDot.style.opacity = "1";
} else {
insideStatus.textContent = "Outside element";
insideStatus.style.color = "red";
coordsDisplay.style.color = "red";
cursorDot.style.transform = `translate(0px, 0px)`;
cursorDot.style.opacity = "0";
}
});
</script>
</body>
</html>

176
src/draggable.attempts/4/index.html

@ -0,0 +1,176 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
<style>
html,
body {
margin: 0;
width: 100vw;
height: 100vh;
background: #111;
overflow: hidden;
}
#card {
width: 24rem;
height: 16rem;
background: linear-gradient(135deg, #ff9a9e, #fad0c4);
border-radius: 20px;
position: absolute;
left: 0;
top: 0;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.3);
transform-origin: center center;
cursor: grab;
/* touch-action: none; */
}
</style>
</head>
<body>
<div id="card"></div>
<script>
const card = document.getElementById("card");
function makeDraggable(card) {
const rect = card.getBoundingClientRect();
let center = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2,
};
let rotation = 0;
let dragging = false;
let offsetLocal = { x: 0, y: 0 };
let velocity = { x: 0, y: 0 };
let angularVelocity = 0;
const dampingFactor = 0.7;
const springFactor = 0.2;
const maxAngularVelocity = 0.95;
const momentumDampening = 0.98;
let lastMousePosition = { x: 0, y: 0 };
let activePointerId = null;
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
const down = e => {
if (activePointerId !== null) return;
dragging = true;
activePointerId = e.pointerId;
card.setPointerCapture(e.pointerId);
velocity = { x: 0, y: 0 };
const dx = e.pageX - center.x;
const dy = e.pageY - center.y;
const cos = Math.cos(-rotation);
const sin = Math.sin(-rotation);
offsetLocal = {
x: dx * cos - dy * sin,
y: dx * sin + dy * cos,
};
console.log(offsetLocal);
lastMousePosition = { x: e.pageX, y: e.pageY };
};
const move = e => {
if (!dragging || e.pointerId !== activePointerId) return;
const mx = e.pageX;
const my = e.pageY;
velocity = {
x: mx - lastMousePosition.x,
y: my - lastMousePosition.y,
};
lastMousePosition = { x: mx, y: my };
const px = offsetLocal.x;
const py = offsetLocal.y;
const targetRotation =
Math.atan2(my - center.y, mx - center.x) - Math.atan2(py, px);
angularVelocity += (targetRotation - rotation) * springFactor;
angularVelocity *= dampingFactor;
angularVelocity = clamp(
angularVelocity,
-maxAngularVelocity,
maxAngularVelocity,
);
rotation += angularVelocity;
const cos = Math.cos(rotation);
const sin = Math.sin(rotation);
const rx = px * cos - py * sin;
const ry = px * sin + py * cos;
center = {
x: mx - rx,
y: my - ry,
};
};
const up = e => {
if (e.pointerId === activePointerId) {
dragging = false;
activePointerId = null;
}
};
card.addEventListener("pointerdown", down, { passive: false });
window.addEventListener("pointermove", move, { passive: false });
window.addEventListener("pointerup", up, { passive: false });
function render() {
if (!dragging) {
if (Math.abs(angularVelocity) > 0.01) {
rotation += angularVelocity;
angularVelocity *= momentumDampening;
}
const speed = Math.sqrt(
velocity.x * velocity.x + velocity.y * velocity.y,
);
if (speed > 0.01) {
center.x += velocity.x * 0.4;
center.y += velocity.y * 0.4;
velocity.x *= momentumDampening;
velocity.y *= momentumDampening;
}
}
card.style.transform = `
translate(${center.x}px, ${center.y}px)
translate(-50%, -50%)
rotate(${rotation}rad)
`;
requestAnimationFrame(render);
}
render();
}
makeDraggable(card);
</script>
</body>
</html>

15
src/draggable.attempts/4/vite.config.ts

@ -0,0 +1,15 @@
import { defineConfig } from "vite";
import { resolve } from "path";
// https://vitejs.dev/config/
export default defineConfig({
server: { port: 10000, allowedHosts: ["dev.mkr.thefeathers.co"] },
plugins: [],
build: {
rollupOptions: {
input: {
main: resolve(__dirname, "index.html"),
},
},
},
});

236
src/draggable.attempts/5/Draggable.ts

@ -0,0 +1,236 @@
interface Vec2 {
x: number;
y: number;
}
function getCursorPositionRelativeToElement(
cursor: Vec2,
element: HTMLElement,
): Vec2 {
const size = {
x: element.offsetWidth,
y: element.offsetHeight,
};
const boundingRect = element.getBoundingClientRect();
const computedStyle = window.getComputedStyle(element);
const transformValue = computedStyle.transform;
if (transformValue === "none" || !transformValue)
return {
x: cursor.x - boundingRect.left,
y: cursor.y - boundingRect.top,
};
const matrix = new DOMMatrix(transformValue);
const centerX = boundingRect.left + boundingRect.width / 2;
const centerY = boundingRect.top + boundingRect.height / 2;
const relativeToCenter = {
x: cursor.x - centerX,
y: cursor.y - centerY,
};
const inverseMatrix = matrix.inverse();
inverseMatrix.e = 0;
inverseMatrix.f = 0;
const transformedPoint = {
x:
relativeToCenter.x * inverseMatrix.a +
relativeToCenter.y * inverseMatrix.c,
y:
relativeToCenter.x * inverseMatrix.b +
relativeToCenter.y * inverseMatrix.d,
};
return {
x: transformedPoint.x + size.x / 2,
y: transformedPoint.y + size.y / 2,
};
}
export function makeDraggable(card: HTMLElement) {
let position: Vec2 = { x: 0, y: 0 };
let rotation = 0;
let dragging = false;
let offset__local: Vec2 = { x: 0, y: 0 };
let grabAngleLocal = 0;
let velocity: Vec2 = { x: 0, y: 0 };
let angularVelocity = 0;
const dampingFactor = 0.5;
const springFactor = 0.2;
const maxAngularVelocity = 0.95;
const momentumDampening = 0.98;
let lastMousePosition__page: Vec2 = { x: 0, y: 0 };
let activePointerId: number | null = null;
// Keep original factors for momentum physics
const momentumDampingFactor = 0.7; // Renamed for clarity
const momentumSpringFactor = 0.2; // Renamed for clarity
const momentumMaxAngularVelocity = 0.95;
const momentumDampeningDecay = 0.98; // Renamed for clarity
// Add a specific damping factor for the active drag rotation spring
const dragRotationDamping = 0.4; // TUNABLE: Higher value = more damping (less springy/oscillating)
function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
const down = (e: PointerEvent) => {
if (activePointerId !== null) return;
dragging = true;
activePointerId = e.pointerId;
card.setPointerCapture(e.pointerId);
velocity = { x: 0, y: 0 };
angularVelocity = 0;
offset__local = getCursorPositionRelativeToElement(
{ x: e.pageX, y: e.pageY },
card,
);
const cardWidth = card.offsetWidth;
const cardHeight = card.offsetHeight;
const grabCentre__local = {
x: offset__local.x - cardWidth / 2,
y: offset__local.y - cardHeight / 2,
};
grabAngleLocal = Math.atan2(grabCentre__local.y, grabCentre__local.x);
lastMousePosition__page = { x: e.pageX, y: e.pageY };
};
// TODO: this function is still not working as expected
// Come back to it some day
const move = (e: PointerEvent) => {
if (!dragging || e.pointerId !== activePointerId) return;
const mx = e.pageX;
const my = e.pageY;
// Calculate mouse movement delta
const mouseDelta = {
x: mx - lastMousePosition__page.x,
y: my - lastMousePosition__page.y,
};
position.x += mouseDelta.x;
position.y += mouseDelta.y;
// Update velocity (for momentum) and last mouse position
velocity = mouseDelta; // Store the delta for momentum phase
lastMousePosition__page = { x: mx, y: my };
const rect = card.getBoundingClientRect();
// Use rect dimensions in case transforms (like scale) affect offsetWidth/offsetHeight differently
const cardWidth = rect.width;
const cardHeight = rect.height;
const currentCenter__page = {
x: rect.left + cardWidth / 2 + window.scrollX,
y: rect.top + cardHeight / 2 + window.scrollY,
};
const angleToMouse = Math.atan2(
my - currentCenter__page.y,
mx - currentCenter__page.x,
);
const angleToMouse_Local = angleToMouse - grabAngleLocal;
const px = offset__local.x;
const py = offset__local.y;
const targetRotation =
Math.atan2(my - position.y, mx - position.x) - Math.atan2(py, px);
angularVelocity += (targetRotation - rotation) * springFactor;
angularVelocity *= dampingFactor;
angularVelocity = clamp(
angularVelocity,
-maxAngularVelocity,
maxAngularVelocity,
);
rotation += angularVelocity;
const cos = Math.cos(rotation);
const sin = Math.sin(rotation);
const rx = px * cos - py * sin;
const ry = px * sin + py * cos;
// position = {
// x: mx - rx,
// y: my - ry,
// };
};
const up = (e: PointerEvent) => {
if (e.pointerId === activePointerId) {
dragging = false;
activePointerId = null;
// When dragging stops, the existing angularVelocity
// is used by the render() loop for momentum.
}
};
card.addEventListener("pointerdown", down, { passive: false });
window.addEventListener("pointermove", move, { passive: false });
window.addEventListener("pointerup", up, { passive: false });
let frame = 0;
function render() {
if (!dragging) {
// --- Momentum Phase ---
// Use the angularVelocity calculated by the last 'move' or previous 'render' frame
if (Math.abs(angularVelocity) > 0.001) {
rotation += angularVelocity; // Apply momentum rotation
angularVelocity *= momentumDampeningDecay; // Apply decay damping
} else {
angularVelocity = 0;
}
const speed = Math.sqrt(
velocity.x * velocity.x + velocity.y * velocity.y,
);
if (speed > 0.01) {
position.x += velocity.x;
position.y += velocity.y;
velocity.x *= momentumDampening;
velocity.y *= momentumDampening;
} else {
velocity = { x: 0, y: 0 };
}
} // else: if dragging, rotation is updated in move()
// --- Apply Transform ---
card.style.transform = `
translate(${position.x}px, ${position.y}px)
rotate(${rotation}rad)
`;
card.style.transformOrigin = "50% 50%";
frame = requestAnimationFrame(render);
}
render();
return () => {
card.removeEventListener("pointerdown", down);
window.removeEventListener("pointermove", move);
window.removeEventListener("pointerup", up);
cancelAnimationFrame(frame);
// Optional: Reset transform on cleanup?
// card.style.transform = originalTransform || 'none';
card.style.transformOrigin = "";
};
}

40
src/draggable.attempts/5/Draggable2.tsx

@ -0,0 +1,40 @@
import React, { forwardRef, useEffect, useRef } from "react";
import { makeDraggable } from "./Draggable";
import { composeRefs } from "../../util";
import { css, cx } from "@emotion/css";
export type DraggableProps = React.ComponentPropsWithRef<any> & {
as?: React.ElementType;
children: React.ReactNode;
};
export const Draggable = forwardRef<HTMLElement, DraggableProps>(
(
{ as: Comp = "div", children, className, ...props }: DraggableProps,
ref,
) => {
const cardRef = useRef<HTMLElement>(null);
useEffect(() => {
if (!cardRef.current) return;
return makeDraggable(cardRef.current);
}, []);
return (
<Comp
className={cx(
className,
"draggable",
css`
cursor: grab;
`,
)}
ref={composeRefs(cardRef, ref)}
{...props}>
{children}
</Comp>
);
},
);
Draggable.displayName = "Draggable";

273
src/draggable.attempts/6/Draggable.ts

@ -0,0 +1,273 @@
import {
clamp,
debounce,
normaliseAngleDifference,
throttle,
} from "../../util/index.ts";
interface Vec2 {
x: number;
y: number;
}
export interface DraggableOpts {
initialRotation?: number;
onPageExit?: () => void;
onPageEnter?: () => void;
}
export function makeDraggable(card: HTMLElement, opts: DraggableOpts = {}) {
// --- Initial Setup ---
const calculateInitialCenter = (): Vec2 => {
const rect = card.getBoundingClientRect();
return {
x: rect.left + rect.width / 2 + window.scrollX,
y: rect.top + rect.height / 2 + window.scrollY,
};
};
// Use mutable objects to allow updates in resize handler
let initialCenter = calculateInitialCenter();
let center = { ...initialCenter };
let rotation = opts.initialRotation ?? 0;
let dragging = false;
const state = { dragging };
let offsetLocal: Vec2 = { x: 0, y: 0 };
let velocity: Vec2 = { x: 0, y: 0 };
let angularVelocity = 0;
// --- Constants ---
const dampingFactor = 0.7;
const springFactor = 0.2;
const maxAngularVelocity = 0.95;
const RESIZE_DEBOUNCE_MS = 100;
const VIEWPORT_CHECK_INTERVAL_MS = 100;
// Adjust damping factors (base + velocity-dependent part)
const baseDamping = 0.98; // Base exponential damping
const angularVelocityDecay = 0.99;
const velocityDecay = 0.005;
const maxEffectiveSpeed = 50;
// --- State ---
let lastMousePosition: Vec2 = { x: 0, y: 0 };
let activePointerId: number | null = null;
let animationFrameId: number | null = null;
let isOutsideBounds = false;
// --- Helpers ---
const checkPageBounds = throttle(() => {
if (state.dragging) return;
const rect = card.getBoundingClientRect();
const pageLeft = rect.left + window.scrollX;
const pageTop = rect.top + window.scrollY;
const pageRight = rect.right + window.scrollX;
const pageBottom = rect.bottom + window.scrollY;
const outside =
pageRight < 0 ||
pageBottom < 0 ||
pageLeft > document.documentElement.scrollWidth ||
pageTop > document.documentElement.scrollHeight;
if (outside !== isOutsideBounds) {
isOutsideBounds = outside;
if (isOutsideBounds) opts.onPageExit?.();
else opts.onPageEnter?.();
}
}, VIEWPORT_CHECK_INTERVAL_MS);
// --- Event Handlers ---
const down = (e: PointerEvent) => {
if (activePointerId !== null) return;
state.dragging = true;
activePointerId = e.pointerId;
card.style.cursor = "grabbing";
velocity = { x: 0, y: 0 };
const dx = e.pageX - center.x;
const dy = e.pageY - center.y;
const cos = Math.cos(-rotation);
const sin = Math.sin(-rotation);
offsetLocal = {
x: dx * cos - dy * sin,
y: dx * sin + dy * cos,
};
lastMousePosition = { x: e.pageX, y: e.pageY };
angularVelocity = 0;
document.body.style.userSelect = "none";
document.body.style.webkitUserSelect = "none";
};
const move = (e: PointerEvent) => {
if (!state.dragging || e.pointerId !== activePointerId) return;
const mx = e.pageX;
const my = e.pageY;
velocity = {
x: mx - lastMousePosition.x,
y: my - lastMousePosition.y,
};
lastMousePosition = { x: mx, y: my };
const px = offsetLocal.x;
const py = offsetLocal.y;
const targetRotation =
Math.atan2(my - center.y, mx - center.x) - Math.atan2(py, px);
const shortestAngleDifference = normaliseAngleDifference(
targetRotation - rotation,
);
angularVelocity += shortestAngleDifference * springFactor;
angularVelocity *= dampingFactor;
angularVelocity = clamp(
angularVelocity,
-maxAngularVelocity,
maxAngularVelocity,
);
rotation += angularVelocity;
const cos = Math.cos(rotation);
const sin = Math.sin(rotation);
const rx = px * cos - py * sin;
const ry = px * sin + py * cos;
center = {
x: mx - rx,
y: my - ry,
};
};
const cancel = () => {
state.dragging = false;
activePointerId = null;
card.style.cursor = "grab";
document.body.style.userSelect = "auto";
document.body.style.webkitUserSelect = "auto";
// Momentum is handled in the render loop
};
const up = (e: PointerEvent | FocusEvent | KeyboardEvent) => {
if ("pointerId" in e && e.pointerId === activePointerId) return cancel();
else if ("key" in e && e.key === "Escape") return cancel();
else return cancel();
};
// Debounced Resize Handler using the Reset-Reflow-Recalculate-Reapply strategy
const handleResize = debounce(() => {
// 1. Store current visual state relative to the *old* initialCenter
const currentDeltaX = center.x - initialCenter.x;
const currentDeltaY = center.y - initialCenter.y;
// 2. Temporarily remove the transform
card.style.transform = "none";
// 3. Force browser reflow to get the *untouched* layout position
// Reading offsetWidth is a common way to trigger this synchronously.
void card.offsetWidth;
// 4. Recalculate initialCenter based on the *new*, untouched layout
const newInitialCenter = calculateInitialCenter();
// 5. Update state variables
initialCenter = newInitialCenter;
// Adjust 'center' to maintain the same visual delta relative to the *new* initialCenter
center.x = initialCenter.x + currentDeltaX;
center.y = initialCenter.y + currentDeltaY;
// rotation, velocity, angularVelocity remain unchanged
// 6. Reapply the transform immediately before the next paint
// Use the *stored* delta and rotation to put it back visually where it was
card.style.transform = `translate(${currentDeltaX}px, ${currentDeltaY}px) rotate(${rotation}rad)`;
// The render loop will continue from this adjusted state.
}, RESIZE_DEBOUNCE_MS); // Apply debouncing
// --- Render Loop ---
function render() {
if (!state.dragging) {
// --- Angular Momentum ---
if (Math.abs(angularVelocity) > 0.001) {
// Simple exponential damping
rotation += angularVelocity;
angularVelocity *= angularVelocityDecay;
} else angularVelocity = 0;
// --- Linear Momentum ---
const speed = Math.sqrt(
velocity.x * velocity.x + velocity.y * velocity.y,
);
if (speed > 0.01) {
// Calculate speed-dependent damping
// Clamp speed influence to avoid excessive damping
const speedInfluence =
Math.min(speed, maxEffectiveSpeed) / maxEffectiveSpeed;
const currentDamping =
baseDamping * (1 - speedInfluence * velocityDecay);
// Ensure damping doesn't go below a minimum or above 1
const effectiveDamping = clamp(currentDamping, 0.8, 0.995); // Adjust min/max clamp
velocity.x *= effectiveDamping;
velocity.y *= effectiveDamping;
center.x += velocity.x;
center.y += velocity.y;
} else velocity = { x: 0, y: 0 };
}
const deltaX = center.x - initialCenter.x;
const deltaY = center.y - initialCenter.y;
card.style.transform = `
translate(${deltaX}px, ${deltaY}px)
rotate(${rotation}rad)
`;
checkPageBounds();
animationFrameId = requestAnimationFrame(render);
}
card.style.cursor = "grab";
card.style.touchAction = "none";
card.style.transform = `translate(0px, 0px) rotate(${rotation}rad)`;
card.addEventListener("pointerdown", down, { passive: true });
window.addEventListener("pointermove", move, { passive: true });
window.addEventListener("pointerup", up, { passive: true });
window.addEventListener("pointercancel", up, { passive: true });
window.addEventListener("blur", up, { passive: true });
window.addEventListener("keydown", up, { passive: true });
window.addEventListener("resize", handleResize);
render();
return function cleanup() {
if (animationFrameId !== null) cancelAnimationFrame(animationFrameId);
card.removeEventListener("pointerdown", down);
window.removeEventListener("pointermove", move);
window.removeEventListener("pointerup", up);
window.removeEventListener("pointercancel", up);
window.removeEventListener("blur", up);
window.removeEventListener("keydown", up);
window.removeEventListener("resize", handleResize);
card.style.cursor = "";
card.style.touchAction = "";
card.style.userSelect = "";
};
}

55
src/draggable.attempts/6/Draggable2.tsx

@ -0,0 +1,55 @@
import React, { forwardRef, useEffect, useRef } from "react";
import { makeDraggable } from "./Draggable.ts";
import { composeRefs } from "../../util/index.ts";
import { css, cx } from "@emotion/css";
export type DraggableProps = React.HtmlHTMLAttributes<any> & {
as?: React.ElementType;
onPageEnter?: () => void;
onPageExit?: () => void;
children: React.ReactNode;
initialRotation?: number;
};
export const Draggable = forwardRef<HTMLElement, DraggableProps>(
(
{
as: Comp = "div",
children,
className,
onPageEnter,
onPageExit,
initialRotation,
...props
}: DraggableProps,
ref,
) => {
const cardRef = useRef<HTMLElement>(null);
useEffect(() => {
if (!cardRef.current) return;
return makeDraggable(cardRef.current, {
onPageEnter,
onPageExit,
initialRotation,
});
}, []);
return (
<Comp
className={cx(
className,
"draggable",
css`
cursor: grab;
`,
)}
ref={composeRefs(cardRef, ref)}
{...props}>
{children}
</Comp>
);
},
);
Draggable.displayName = "Draggable";

72
src/draggable.attempts/6/index.html

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
<style>
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
width: 100vw;
height: 100vh;
background: #111;
overflow: hidden;
}
#card {
width: 24rem;
height: 16rem;
background: linear-gradient(135deg, #ff9a9e, #fad0c4);
border-radius: 20px;
position: absolute;
left: 200px;
/* top: 200px; */
bottom: 0;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.3);
transform-origin: center center;
cursor: grab;
/* touch-action: none; */
}
.container {
display: flex;
width: 100%;
height: 100%;
padding: 4rem;
overflow: hidden;
}
.sidebar {
width: 20rem;
height: 100%;
background: #222;
}
main {
flex: 1;
background: #333;
position: relative;
overflow: hidden;
}
</style>
</head>
<body>
<div class="container">
<div class="sidebar"></div>
<main>
<div id="card"></div>
</main>
</div>
<script type="module">
import { makeDraggable } from "./Draggable.ts";
makeDraggable(document.getElementById("card"));
</script>
</body>
</html>

15
src/draggable.attempts/6/vite.config.ts

@ -0,0 +1,15 @@
import { defineConfig } from "vite";
import { resolve } from "path";
// https://vitejs.dev/config/
export default defineConfig({
server: { port: 10000, allowedHosts: ["dev.mkr.thefeathers.co"] },
plugins: [],
build: {
rollupOptions: {
input: {
main: resolve(__dirname, "index.html"),
},
},
},
});

24
src/index.css

@ -1,11 +1,12 @@
:root {
--bg-colour: rgb(0, 0, 0);
--card-bg: rgb(18, 18, 18);
--card-tags: rgb(34, 34, 34);
--card-tags-hover: rgb(25, 25, 25);
--card-tags: rgb(35, 35, 35);
--card-tags-hover: rgb(30, 30, 30);
--primary-colour: rgb(255, 85, 85);
--text-colour: rgb(210, 210, 210);
--text-subdued: rgb(150, 150, 150);
--table-border: rgb(54, 54, 54);
--card-active: rgb(45, 45, 45);
--card-active-border: rgb(60, 60, 60);
--card-hover: rgb(15, 15, 15);
@ -46,22 +47,18 @@ h2,
h3,
h4,
h5,
h6,
p {
h6 {
margin: 0;
line-height: 1.5em;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 800;
color: var(--primary-colour);
}
p {
margin: 0;
line-height: 1.5em;
}
h1,
h2 {
line-height: 1.2em;
@ -69,6 +66,7 @@ h2 {
h1 {
font-size: min(15vw, 6rem);
line-height: 0.8em;
}
h2 {
@ -97,4 +95,6 @@ a:hover {
button {
cursor: pointer;
border: none;
text-align: left;
}

254
src/pages/main/Contact.tsx

@ -2,6 +2,11 @@ import React from "react";
import { css } from "@emotion/css";
import { useEffect, useState } from "react";
import Container from "../../components/Container";
import { setupCursorTracking } from "../../util/index.ts";
import { ReactComponent as Logo } from "../../assets/logo.svg";
import { Flippable } from "../../components/Flippable.tsx";
import { AnimateEntry } from "../../components/AnimateEntry.tsx";
import { Draggable } from "../../draggable.attempts/6/Draggable2.tsx";
const A = css`
text-decoration: none;
@ -16,17 +21,18 @@ type Contact = {
};
const CONTACT: Contact = {
"Twitter/𝕏": { value: "MKRhere", link: "https://twitter.com/MKRhere" },
"GitHub": { value: "MKRhere", link: "https://github.com/MKRhere" },
"Email": {
value: "mυthυkυmαr@thεfεαthεrs.in",
link: "mailto:mυthυkυmαr@thεfεαthεrs.in",
value: "һі@mκr.рw",
link: "mailto:һі@mκr.рw",
replacer: {
υ: "u",
ε: "e",
α: "a",
һ: "h",
і: "i",
κ: "k",
р: "p",
},
},
"GitHub": { value: "MKRhere", link: "https://github.com/MKRhere" },
"Twitter/𝕏": { value: "MKRhere", link: "https://twitter.com/MKRhere" },
"Phone": {
value: "+9Ι Γ8Δ5 Γ9 8Δ88",
link: "tel:+91Γ8Δ5Γ98Δ88",
@ -39,8 +45,19 @@ const CONTACT: Contact = {
"Blog": { value: "→", link: "https://MKRhere.com" },
};
const Home: React.FC = () => {
const CARD_COUNT = 5;
// slightly random rotations within -20 to 20 degrees
const CARD_ROTATION_VARIANCE = 20 * (Math.PI / 180);
const contactCards = Array.from({ length: CARD_COUNT }, () => {
const rotation =
Math.random() * CARD_ROTATION_VARIANCE - CARD_ROTATION_VARIANCE / 2;
return rotation;
});
const Contact: React.FC = () => {
const [contact, setContact] = useState<Contact>(CONTACT);
const [visible, setVisible] = useState(contactCards.length);
useEffect(() => {
const deob = () => {
@ -67,91 +84,170 @@ const Home: React.FC = () => {
document.addEventListener("scroll", deob, { once: true });
document.addEventListener("click", deob, { once: true });
document.addEventListener("touchstart", deob, { once: true });
document.addEventListener("keydown", deob, { once: true });
return () => {
document.removeEventListener("mousemove", deob);
document.removeEventListener("scroll", deob);
document.removeEventListener("click", deob);
document.removeEventListener("touchstart", deob);
document.removeEventListener("keydown", deob);
};
}, []);
return (
<Container
className={css`
min-height: 50vh;
display: flex;
flex-direction: column;
`}>
<Container>
<h1>MKRhere</h1>
<div
{visible < 1 && (
<AnimateEntry as="article" delay={500}>
<p>Great, You've distributed all the cards!</p>
<p>What now?</p>
<br />
<a href="/">Start over?</a>
</AnimateEntry>
)}
<AnimateEntry
as="main"
delay={200}
className={css`
margin-top: auto;
display: flex;
flex-shrink: 1;
gap: 1rem;
ul {
padding: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
max-width: 50vw;
li {
list-style: none;
min-width: 5rem;
max-width: 100%;
}
li a {
display: block;
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
/* Blog entry */
li:last-child {
margin-block-start: 1rem;
}
}
width: 100%;
min-height: max(40vh, 11rem);
height: 100%;
position: relative;
`}>
<ul
className={css`
text-align: right;
`}>
{Object.keys(contact).map(key => (
<li key={key}>
<b>{key}.</b>
</li>
))}
</ul>
<ul>
{Object.keys(contact).map(key => {
const value = contact[key];
return (
<li key={key}>
{value.link ? (
<a
className={A}
href={value.link}
target="_blank"
rel="noreferrer">
{value.value}
</a>
) : (
value.value
)}
</li>
);
})}
</ul>
</div>
{contactCards.map((rot, i) => (
<Draggable
key={i}
onPageExit={() => setVisible(v => v - 1)}
onPageEnter={() => setVisible(v => v + 1)}
initialRotation={rot}
className={css`
width: 21rem;
height: 13rem;
font-size: 1rem;
@media screen and (max-width: 40rem) {
width: 18rem;
height: 11rem;
font-size: 0.85rem;
}
position: absolute;
bottom: 0;
left: 0;
padding: 0;
background: transparent;
`}
ref={setupCursorTracking}>
<Flippable
defaultFlipped={i !== contactCards.length - 1}
front={
<main
className={css`
height: 100%;
width: 100%;
overflow: hidden;
border-radius: 0.5rem;
background: var(--card-bg);
box-shadow: 0 0 6rem 0 rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
font-size: inherit;
padding: 1rem 2.8em;
ul {
padding: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
max-width: 50vw;
li {
list-style: none;
min-width: 4rem;
max-width: 100%;
}
li a {
display: block;
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
/* Blog entry */
li:last-child {
margin-block-start: 1rem;
}
}
`}>
<div className="dynamic-gradient" />
<ul
className={css`
text-align: right;
`}>
{Object.keys(contact).map(key => (
<li key={key}>
<b>{key}.</b>
</li>
))}
</ul>
<ul>
{Object.keys(contact).map(key => {
const value = contact[key];
return (
<li key={key}>
{value.link ? (
<a
className={A}
href={value.link}
target="_blank"
rel="noreferrer"
style={{ width: "fit-content" }}>
{value.value}
</a>
) : (
value.value
)}
</li>
);
})}
</ul>
</main>
}
back={
<main
className={css`
width: 100%;
height: 100%;
overflow: hidden;
border-radius: 0.5rem;
background: var(--card-active);
border: 1px solid var(--card-active-border);
display: flex;
align-items: center;
justify-content: center;
`}>
<Logo width={100} />
</main>
}
/>
</Draggable>
))}
</AnimateEntry>
</Container>
);
};
export default Home;
export default Contact;

13
src/pages/main/Home.tsx

@ -10,7 +10,7 @@ const Home: React.FC = () => {
return (
<Container
className={css`
--distance: 2rem;
--gap: 2.2rem;
`}>
<section>
<h1
@ -23,7 +23,7 @@ const Home: React.FC = () => {
<FlickerList
style={{
// fiddle
marginTop: "calc(-1.7rem - 2px + var(--distance))",
marginTop: "calc(-1rem + var(--gap))",
marginLeft: "-0.1rem",
fontSize: "0.9rem",
}}
@ -63,11 +63,11 @@ const Home: React.FC = () => {
<main
className={css`
/* fiddle */
margin-top: calc(-2.4rem + var(--distance));
margin-top: calc(-2.4rem + var(--gap));
display: flex;
flex-wrap: wrap;
gap: var(--distance);
gap: var(--gap);
& img {
image-rendering: pixelated;
@ -92,6 +92,7 @@ const Home: React.FC = () => {
margin-top: -0.4rem;
display: flex;
flex-direction: column;
gap: 0.2rem;
`}>
<p>
Welcome to the web home of{" "}
@ -138,7 +139,7 @@ const Home: React.FC = () => {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem 2rem;
padding: 0.6rem 0.9rem;
}
& a:hover {
@ -148,7 +149,7 @@ const Home: React.FC = () => {
ref={setupCursorTracking}>
<div className="dynamic-gradient" />
<a href="https://mkr.pw/resume" target="_blank">
Download Resume
Download my resume
<Arrow />
</a>
</button>

220
src/pages/main/Work.tsx

@ -1,58 +1,88 @@
import React from "react";
import { css } from "@emotion/css";
import { css, cx } from "@emotion/css";
import Container from "../../components/Container";
import { projects } from "./data/project";
type Project = {
title: string;
url?: string;
description: string;
cat: string;
tags: string[];
import { otherProjects, projects, type Project } from "./data/project";
const styles = {
project: css`
position: relative;
background: var(--card-bg);
padding: 1.2rem;
cursor: default;
border-radius: 0.5rem;
display: flex;
flex-direction: column;
transition: all 200ms;
:hover {
filter: invert(0.08);
transform: translateY(-0.2rem);
}
header {
display: flex;
justify-content: space-between;
align-items: center;
}
header {
margin-bottom: 0.5rem;
}
`,
tag: css`
display: inline-block;
padding: 0.1rem 0.4rem;
background: var(--card-tags);
color: var(--text-colour);
border-radius: 0.2rem;
transition: all 200ms;
:hover {
background: var(--card-tags-hover);
}
& + & {
margin-left: 0.6rem;
}
`,
};
const ProjectUnit: React.FC<Project> = ({
title,
url,
description,
cat,
tags,
}) => {
const ProjectUnit: React.FC<Project> = unit => {
return (
<div
className={css`
position: relative;
background: var(--card-bg);
padding: 1.5rem;
cursor: default;
border-radius: 0.5rem;
display: flex;
flex-direction: column;
transition: all 200ms;
:hover {
filter: hue-rotate(30deg) invert(0.04);
transform: translateY(-0.2rem);
}
`}>
className={styles.project}
title={unit.title + (unit.wip ? " (WIP)" : "")}>
<a
className={css`
display: block;
display: flex;
flex-direction: column;
height: 100%;
text-decoration: none;
font-weight: 500;
cursor: ${unit.wip ? "default" : "pointer"};
`}
href={url}
href={unit.wip ? undefined : unit.url}
target="_blank"
rel="noreferrer">
<h4>{title}</h4>
<header>
<h4>{unit.title}</h4>
<span
className={css`
color: var(--text-subdued);
font-size: 0.8rem;
font-family: monospace;
`}>
{"{"} {unit.cat} {"}"}
</span>
</header>
<p
className={css`
color: #bdbdbd;
margin-bottom: 0.8rem;
font-size: 0.9rem;
`}>
{description}
{unit.description}
</p>
<p
className={css`
@ -61,49 +91,56 @@ const ProjectUnit: React.FC<Project> = ({
font-size: 0.8rem;
margin-top: auto;
`}>
{tags.map(tag => (
<span
key={tag}
className={css`
display: inline-block;
padding: 0.2rem 0.4rem;
background: var(--card-tags);
color: white;
border-radius: 0.2rem;
transition: all 200ms;
:hover {
background: var(--card-tags-hover);
}
& + & {
margin-left: 0.6rem;
}
`}>
{unit.tags.map(tag => (
<span key={tag} className={styles.tag}>
{tag}
</span>
))}
</p>
<span
className={css`
position: absolute;
right: 1rem;
bottom: 1rem;
color: #bbbbbb;
font-size: 0.8rem;
`}>
{cat}
</span>
</a>
</div>
);
};
const otherProjectsStyle = css`
width: 100%;
border-collapse: collapse;
border-radius: 0.5rem;
overflow: hidden;
color: var(--text-colour);
* {
border-collapse: collapse;
}
th {
color: var(--text-subdued);
}
th,
td {
padding: 0.9rem 1rem;
text-align: left;
line-height: 1.6;
}
td {
border-top: 1px solid var(--table-border);
}
/* border-bottom: 1px solid var(--table-border); */
td a {
display: block;
min-width: max-content;
}
`;
const Exp: React.FC = () => {
return (
<Container>
<h2>Things I've built</h2>
<p>Some tools, libraries, and apps over time:</p>
<p>A few projects I'm proud of:</p>
<div
className={css`
display: grid;
@ -115,6 +152,57 @@ const Exp: React.FC = () => {
<ProjectUnit {...unit} key={unit.title} />
))}
</div>
<hr />
<p>
Apart from the above, I've also built some other interesting stuff over
time using a variety of technologies:
</p>
<table className={otherProjectsStyle}>
<thead>
<tr>
<th>Project</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{otherProjects.map(unit => (
<tr key={unit.title}>
<td
className={css`
vertical-align: top;
`}>
<a
className={cx(
unit.wip &&
css`
color: var(--text-subdued);
cursor: default;
`,
)}
href={unit.wip ? undefined : unit.url}
target="_blank"
rel="noreferrer"
title={unit.title + (unit.wip ? " (WIP)" : "")}>
{unit.title}
</a>
</td>
<td>
{unit.description}
<span
className={css`
margin-top: 0.4rem;
display: block;
color: var(--text-subdued);
font-size: 0.9rem;
font-family: monospace;
`}>
# {unit.tags.join(", ")}
</span>
</td>
</tr>
))}
</tbody>
</table>
</Container>
);
};

87
src/pages/main/data/project.ts

@ -1,22 +1,32 @@
export const projects = [
export type Project = {
title: string;
url?: string;
description: string;
cat: string;
tags: string[];
wip?: boolean;
};
export const projects: Project[] = [
{
title: window.location.hostname,
description: "This website.",
title: window.location.hostname.split(".").slice(0, 2).join("."),
description:
"This website. You've probably missed some things. Look around.",
url: "https://github.com/MKRhere/pw2",
cat: "web",
tags: ["react", "vite"],
},
{
title: "hyperactive",
description: "Suite of web-app development libraries.",
description: "Suite of fast, reactive web-app development libraries.",
url: "https://github.com/codefeathers/hyperactive",
cat: "lib",
tags: ["reactive", "ui-framework"],
},
{
title: "denoland/node_shims",
title: "deno shims",
description:
"Node shims for Deno’s runtime API. Contributed repo into official denoland.",
"Node shims for Deno’s runtime API. Transferred to official denoland.",
url: "https://github.com/denoland/node_shims",
cat: "lib",
tags: ["deno", "shims"],
@ -24,31 +34,74 @@ export const projects = [
{
title: "Telegraf",
description:
"Active maintainer of one of the most popular Telegram Bot API libraries for Node.",
"Active maintainer of one of the most popular Telegram Bot API libraries for TypeScript.",
url: "https://github.com/telegraf/telegraf",
cat: "lib",
tags: ["typescript", "telegram", "bot-api"],
},
{
title: "runtype",
description: "Safely bring runtime values into TypeScript.",
url: "https://codefeathers.github.io/runtype",
cat: "lib",
tags: ["typescript", "runtime"],
title: "mkr/cal",
description:
"A complete calendar application with invites, task management, notetaking, and more.",
url: "https://github.com/MKRhere/cal",
cat: "web",
wip: true,
tags: ["hyperactive", "calendar"],
},
{
title: "Telecraft",
description: "Pluggable Minecraft server administration toolkit.",
url: "https://github.com/MadrasMC/telecraft",
cat: "tool",
cat: "cli",
tags: ["minecraft", "node"],
},
];
export const otherProjects: Project[] = [
{
title: "true-pg",
description:
"The most complete PostgreSQL schema generator for TypeScript, Kysely, Zod, and others.",
url: "https://github.com/feathers-studio/true-pg",
cat: "lib",
tags: ["postgresql", "schema", "typescript", "kysely", "zod"],
},
{
title: "wiretap",
description:
"Extremely tiny debug logging utility for all JavaScript runtimes. Published as npm/yarn.",
url: "https://github.com/feathers-studio/wiretap",
cat: "lib",
tags: ["debug", "logging", "typescript"],
},
{
title: "Storymap (WIP)",
title: "storymap",
description:
"Reverse-engineered thirdparty map renderer for Vintage Story in Zig ⚡️",
// url: "https://github.com/MadrasMC/storymap",
cat: "tool",
tags: ["vintage-story", "zig", "wip"],
url: "https://github.com/MadrasMC/storymap",
cat: "cli",
tags: ["vintage-story", "zig"],
wip: true,
},
{
title: "i3-ts",
description: "TypeScript bindings for the i3 window manager.",
url: "https://github.com/feathers-studio/i3-ts",
cat: "lib",
tags: ["i3", "typescript", "bindings"],
},
{
title: "pg-extract",
description: "Extract data from PostgreSQL tables into a JSON array.",
url: "https://github.com/feathers-studio/pg-extract",
cat: "lib",
tags: ["postgresql", "json", "data-extraction"],
},
{
title: window.location.hostname.split(".").slice(0, 2).join("."),
description: "Did you find all the easter eggs? Keep looking.",
url: "https://github.com/MKRhere/pw2",
cat: "web",
tags: ["react", "vite"],
},
];

68
src/util/index.ts

@ -3,6 +3,20 @@ import useLocation from "wouter/use-location";
export const sleep = (t: number) => new Promise(r => setTimeout(r, t));
type Ref<T> =
| React.MutableRefObject<T | null>
| React.RefCallback<T | null>
| React.ForwardedRef<T>;
export const composeRefs = <T>(...refs: Ref<T | null>[]) => {
return (el: T) => {
refs.forEach(ref => {
if (typeof ref === "function") ref(el);
else if (ref) ref.current = el;
});
};
};
export function* intersperse<T, U>(
xs: T[],
delim: (index: number) => U,
@ -21,7 +35,7 @@ export function* intersperse<T, U>(
}
export const getTimeout = () => {
const clearables = new Set<number>();
const clearables = new Set<ReturnType<typeof setTimeout>>();
const timeout = (f: (...attr: any[]) => any, t: number) => {
const self = setTimeout(() => (f(), clearables.delete(self)), t);
@ -36,6 +50,46 @@ export const getTimeout = () => {
return [timeout, clearTimers] as const;
};
export function debounce<Fn extends (...args: any[]) => void>(
func: Fn,
wait: number,
): Fn {
let timeoutId: number | null = null;
return function (this: ThisParameterType<Fn>, ...args: Parameters<Fn>) {
if (timeoutId !== null) clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
func.apply(this, args);
timeoutId = null;
}, wait);
} as Fn;
}
export const throttle = <Fn extends (...args: any[]) => void>(
fn: Fn,
wait: number,
): Fn => {
let inThrottle = false;
let lastFn: ReturnType<typeof setTimeout> | undefined = undefined;
let lastTime = 0;
return function (this: ThisParameterType<Fn>, ...args: Parameters<Fn>) {
const context = this;
if (!inThrottle) {
fn.apply(context, args);
lastTime = Date.now();
inThrottle = true;
} else {
clearTimeout(lastFn);
lastFn = setTimeout(function () {
if (Date.now() - lastTime >= wait) {
fn.apply(context, args);
lastTime = Date.now();
}
}, Math.max(wait - (Date.now() - lastTime), 0));
}
} as Fn;
};
export const ellipses = (text: string, length: number = 100) =>
text.length > length ? text.slice(0, length - 3) + "..." : text;
@ -90,3 +144,15 @@ export function setupCursorTracking(el: HTMLElement | null) {
el.style.setProperty("--y", y + "px");
});
}
export function clamp(value: number, min: number, max: number) {
return Math.min(Math.max(value, min), max);
}
export function normaliseAngleDifference(delta: number): number {
// Bring into range (-2PI, 2PI)
delta = delta % (2 * Math.PI);
if (delta > Math.PI) delta -= 2 * Math.PI;
else if (delta <= -Math.PI) delta += 2 * Math.PI;
return delta;
}

2
tsconfig.json

@ -3,7 +3,7 @@
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"types": ["vite/client"],
"skipLibCheck": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"allowImportingTsExtensions": true,

2
vite.config.ts

@ -6,7 +6,7 @@ import { visualizer as visualiser } from "rollup-plugin-visualizer";
// https://vitejs.dev/config/
export default defineConfig({
server: { port: 10000 },
server: { port: 10000, allowedHosts: ["dev.mkr.thefeathers.co"] },
plugins: [
react(),
Object.assign(svgr({ ref: true, svgo: false }), {

Loading…
Cancel
Save