diff --git a/astro.config.mjs b/astro.config.mjs index 2953a21..e08abee 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,6 +1,7 @@ import { defineConfig } from 'astro/config'; import tailwindcss from '@tailwindcss/vite'; import sitemap from '@astrojs/sitemap'; +import react from '@astrojs/react'; // COOP/COEP enable Cross-Origin Isolation so the in-browser ZK prover can // use SharedArrayBuffer + Web Workers for multi-threaded proving. Without @@ -17,7 +18,7 @@ export default defineConfig({ build: { inlineStylesheets: 'auto', }, - integrations: [sitemap()], + integrations: [sitemap(), react({ include: ['**/*.tsx'] })], vite: { plugins: [tailwindcss()], server: { headers: crossOriginIsolation }, diff --git a/package.json b/package.json index b3959d2..23f8b67 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "lhci": "lhci autorun" }, "dependencies": { + "@astrojs/react": "^5.0.7", "@astrojs/sitemap": "3.7.3", "@atheonxyz/verity": "0.3.2-alpha", "@fontsource/geist-mono": "^5.1.0", @@ -28,11 +29,16 @@ "@noir-lang/types": "1.0.0-beta.19", "@tailwindcss/vite": "^4.0.0", "astro": "^6.4.6", + "framer-motion": "^11.11.17", "pako": "2.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "tailwindcss": "^4.0.0" }, "devDependencies": { "@astrojs/check": "^0.9.9", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", "@lhci/cli": "^0.14.0", "@playwright/test": "^1.49.0", "@types/node": "^22.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bace859..7de4c88 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@astrojs/react': + specifier: ^5.0.7 + version: 5.0.7(@types/node@22.19.18)(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(yaml@2.8.4) '@astrojs/sitemap': specifier: 3.7.3 version: 3.7.3 @@ -38,9 +41,18 @@ importers: astro: specifier: ^6.4.6 version: 6.4.6(@types/node@22.19.18)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.60.3)(yaml@2.8.4) + framer-motion: + specifier: ^11.11.17 + version: 11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) pako: specifier: 2.1.0 version: 2.1.0 + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) tailwindcss: specifier: ^4.0.0 version: 4.3.0 @@ -57,6 +69,12 @@ importers: '@types/node': specifier: ^22.10.0 version: 22.19.18 + '@types/react': + specifier: ^18.3.12 + version: 18.3.31 + '@types/react-dom': + specifier: ^18.3.1 + version: 18.3.7(@types/react@18.3.31) eslint: specifier: ^9.16.0 version: 9.39.4(jiti@2.7.0) @@ -142,6 +160,15 @@ packages: resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==} engines: {node: '>=22.12.0'} + '@astrojs/react@5.0.7': + resolution: {integrity: sha512-N9cCoxvnLWaP+AK1Fv4e5Mc7ktnVTpSo2nWLwvD9Ohr1dJKygwrTSm9yatqoahgb1A5Kwjg/rT2shRiIVdn3aw==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@types/react': ^17.0.50 || ^18.0.21 || ^19.0.0 + '@types/react-dom': ^17.0.17 || ^18.0.6 || ^19.0.0 + react: ^17.0.2 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.2 || ^18.0.0 || ^19.0.0 + '@astrojs/sitemap@3.7.3': resolution: {integrity: sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==} @@ -163,23 +190,106 @@ packages: '@noir-lang/noir_js': optional: true + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.29.3': resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.29.7': + resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.29.7': + resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + '@bramus/specificity@2.4.2': resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true @@ -842,6 +952,9 @@ packages: engines: {node: '>=18'} hasBin: true + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -1124,6 +1237,18 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/debug@4.1.13': resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} @@ -1154,6 +1279,17 @@ packages: '@types/node@24.13.2': resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.31': + resolution: {integrity: sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==} + '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} @@ -1225,6 +1361,12 @@ packages: '@ungap/structured-clone@1.3.1': resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + '@vitest/expect@2.1.9': resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} @@ -1460,6 +1602,11 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.10.38: + resolution: {integrity: sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==} + engines: {node: '>=6.0.0'} + hasBin: true + basic-ftp@5.3.1: resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} engines: {node: '>=10.0.0'} @@ -1485,6 +1632,11 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -1515,6 +1667,9 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1636,6 +1791,9 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@1.2.3: resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} @@ -1692,6 +1850,9 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + data-uri-to-buffer@6.0.2: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} @@ -1805,6 +1966,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.375: + resolution: {integrity: sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==} + emmet@2.4.11: resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} @@ -2082,6 +2246,20 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + framer-motion@11.18.2: + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -2102,6 +2280,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2368,6 +2550,9 @@ packages: resolution: {integrity: sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==} engines: {node: '>=12'} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@3.14.2: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true @@ -2385,6 +2570,11 @@ packages: canvas: optional: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -2397,6 +2587,11 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + jsonc-parser@2.3.1: resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} @@ -2518,6 +2713,10 @@ packages: lookup-closest-locale@6.2.0: resolution: {integrity: sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -2525,6 +2724,9 @@ packages: resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} @@ -2741,6 +2943,12 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true + motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + + motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -2799,6 +3007,10 @@ packages: node-mock-http@1.0.4: resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + node-releases@2.0.48: + resolution: {integrity: sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==} + engines: {node: '>=18'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -3112,6 +3324,19 @@ packages: resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} engines: {node: '>= 0.8'} + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -3251,6 +3476,9 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -3698,6 +3926,12 @@ packages: uploadthing: optional: true + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -4038,6 +4272,9 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml-language-server@1.20.0: resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==} hasBin: true @@ -4197,6 +4434,31 @@ snapshots: dependencies: prismjs: 1.30.0 + '@astrojs/react@5.0.7(@types/node@22.19.18)(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(yaml@2.8.4)': + dependencies: + '@astrojs/internal-helpers': 0.10.0 + '@types/react': 18.3.31 + '@types/react-dom': 18.3.7(@types/react@18.3.31) + '@vitejs/plugin-react': 5.2.0(vite@7.3.5(@types/node@22.19.18)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4)) + devalue: 5.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + ultrahtml: 1.6.0 + vite: 7.3.5(@types/node@22.19.18)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + '@astrojs/sitemap@3.7.3': dependencies: sitemap: 9.0.1 @@ -4220,19 +4482,131 @@ snapshots: '@noir-lang/acvm_js': 1.0.0-beta.19 '@noir-lang/noir_js': 1.0.0-beta.19 + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + '@babel/parser@7.29.3': dependencies: '@babel/types': 7.29.0 + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@bramus/specificity@2.4.2': dependencies: css-tree: 3.2.1 @@ -4756,6 +5130,8 @@ snapshots: - react-native-b4a - supports-color + '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rollup/pluginutils@5.3.0(rollup@4.60.3)': dependencies: '@types/estree': 1.0.9 @@ -4989,6 +5365,27 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -5021,6 +5418,17 @@ snapshots: dependencies: undici-types: 7.18.2 + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.31)': + dependencies: + '@types/react': 18.3.31 + + '@types/react@18.3.31': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + '@types/sax@1.2.7': dependencies: '@types/node': 22.19.18 @@ -5125,6 +5533,18 @@ snapshots: '@ungap/structured-clone@1.3.1': {} + '@vitejs/plugin-react@5.2.0(vite@7.3.5(@types/node@22.19.18)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.5(@types/node@22.19.18)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.4) + transitivePeerDependencies: + - supports-color + '@vitest/expect@2.1.9': dependencies: '@vitest/spy': 2.1.9 @@ -5456,6 +5876,8 @@ snapshots: base64-js@1.5.1: {} + baseline-browser-mapping@2.10.38: {} + basic-ftp@5.3.1: {} bidi-js@1.0.3: @@ -5494,6 +5916,14 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.38 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.375 + node-releases: 2.0.48 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + buffer-crc32@0.2.13: {} buffer@5.7.1: @@ -5519,6 +5949,8 @@ snapshots: camelcase@5.3.1: {} + caniuse-lite@1.0.30001799: {} + ccount@2.0.1: {} chai@5.3.3: @@ -5658,6 +6090,8 @@ snapshots: content-type@1.0.5: {} + convert-source-map@2.0.0: {} + cookie-es@1.2.3: {} cookie-signature@1.0.7: {} @@ -5708,6 +6142,8 @@ snapshots: dependencies: css-tree: 2.2.1 + csstype@3.2.3: {} + data-uri-to-buffer@6.0.2: {} data-urls@7.0.0: @@ -5799,6 +6235,8 @@ snapshots: ee-first@1.1.1: {} + electron-to-chromium@1.5.375: {} + emmet@2.4.11: dependencies: '@emmetio/abbreviation': 2.3.3 @@ -6171,6 +6609,15 @@ snapshots: forwarded@0.2.0: {} + framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + motion-dom: 11.18.1 + motion-utils: 11.18.1 + tslib: 2.8.1 + optionalDependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + fresh@0.5.2: {} fs.realpath@1.0.0: {} @@ -6183,6 +6630,8 @@ snapshots: function-bind@1.1.2: {} + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} get-intrinsic@1.3.0: @@ -6506,6 +6955,8 @@ snapshots: js-library-detector@6.7.0: {} + js-tokens@4.0.0: {} + js-yaml@3.14.2: dependencies: argparse: 1.0.10 @@ -6541,6 +6992,8 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + jsesc@3.1.0: {} + json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -6549,6 +7002,8 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json5@2.2.3: {} + jsonc-parser@2.3.1: {} jsonc-parser@3.3.1: {} @@ -6683,10 +7138,18 @@ snapshots: lookup-closest-locale@6.2.0: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + loupe@3.2.1: {} lru-cache@11.3.6: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + lru-cache@7.18.3: {} lru_map@0.3.3: {} @@ -7069,6 +7532,12 @@ snapshots: dependencies: minimist: 1.2.8 + motion-dom@11.18.1: + dependencies: + motion-utils: 11.18.1 + + motion-utils@11.18.1: {} + mrmime@2.0.1: {} ms@2.0.0: {} @@ -7103,6 +7572,8 @@ snapshots: node-mock-http@1.0.4: {} + node-releases@2.0.48: {} + normalize-path@3.0.0: {} nth-check@2.1.1: @@ -7369,6 +7840,18 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react-refresh@0.18.0: {} + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + readdirp@4.1.2: {} readdirp@5.0.0: {} @@ -7562,6 +8045,10 @@ snapshots: dependencies: xmlchars: 2.2.0 + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + semver@5.7.2: {} semver@6.3.1: {} @@ -8034,6 +8521,12 @@ snapshots: ofetch: 1.5.1 ufo: 1.6.4 + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -8322,6 +8815,8 @@ snapshots: y18n@5.0.8: {} + yallist@3.1.1: {} + yaml-language-server@1.20.0: dependencies: '@vscode/l10n': 0.0.18 diff --git a/src/components/demo/LiveDemo.tsx b/src/components/demo/LiveDemo.tsx new file mode 100644 index 0000000..681b53b --- /dev/null +++ b/src/components/demo/LiveDemo.tsx @@ -0,0 +1,856 @@ +/* + * LiveDemo — interactive zero-knowledge proof generation widget. + * + * Ported from the design system reference at + * project/mobile/MobileDemo.jsx + * with the desktop two-column layout described in chats/chat7.md + * (left: inputs + CTA, right: live execution trace + KPI strip). + * + * Scenario is locked to "Age verification" per the final iteration in chat7. + * Hash function toggle (Poseidon ↔ SHA-256) controls effective constraint + * count and timing. The proof bytes are simulated — this is a visual + * demonstration, not a real prover. + */ + +import { useCallback, useEffect, useRef, useState } from 'react'; +import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'; + +type Scenario = { + key: string; + badge: string; + label: string; + blurb: string; + statement: string; + privates: { label: string; value: string }[]; + publics: { label: string; value: string }[]; + constraints: number; + estMs: number; +}; + +const SCENARIO: Scenario = { + key: 'age', + badge: '01', + label: 'Age verification', + blurb: 'Prove an attribute about yourself without revealing the data behind it.', + statement: 'I am at least 18 years old.', + privates: [{ label: 'Date of birth', value: '1995-08-14' }], + publics: [ + { label: 'Min age', value: '18' }, + { label: 'Today', value: '2026-05-13' }, + ], + constraints: 8192, + estMs: 1240, +}; + +const STEPS = [ + { key: 'compile', label: 'Compile circuit', weight: 0.1 }, + { key: 'witness', label: 'Build witness', weight: 0.18 }, + { key: 'prove', label: 'Generate proof', weight: 0.6 }, + { key: 'verify', label: 'Verify locally', weight: 0.12 }, +] as const; + +type StepKey = (typeof STEPS)[number]['key']; + +const HASHES = [ + { key: 'poseidon', label: 'Poseidon', sub: 'ZK-friendly', cMul: 1.0, tMul: 1.0 }, + { key: 'sha256', label: 'SHA-256', sub: 'Universal', cMul: 3.4, tMul: 3.0 }, +] as const; + +type Phase = 'idle' | 'running' | 'done'; + +function hex2(): string { + return Math.floor(Math.random() * 256) + .toString(16) + .padStart(2, '0'); +} +function makeProof(n: number): string[] { + return Array.from({ length: n }, hex2); +} + +type DotState = 'idle' | 'active' | 'done'; + +function StepDot({ state }: { state: DotState }) { + const reduce = useReducedMotion(); + const borderColor = state === 'idle' ? 'var(--pk-mute-3, #B7B7B7)' : 'var(--pk-brand)'; + return ( + + {state === 'active' && ( + + ); +} + +type StepRowProps = { + step: (typeof STEPS)[number]; + idx: number; + currentStep: number; + timing: number | undefined; + livePhaseMs: number; + effEstMs: number; + last: boolean; +}; + +function StepRow({ step, idx, currentStep, timing, livePhaseMs, effEstMs, last }: StepRowProps) { + const isCurrent = idx === currentStep; + const isDone = timing != null; + const target = effEstMs * step.weight; + const liveMs = isCurrent ? livePhaseMs : isDone ? (timing as number) : 0; + const pct = isDone ? 100 : isCurrent ? Math.min(100, (livePhaseMs / target) * 100) : 0; + const labelColor = isCurrent || isDone ? 'var(--pk-ink)' : 'var(--pk-mute-2)'; + const dotState: DotState = isDone ? 'done' : isCurrent ? 'active' : 'idle'; + + return ( +
+
+ + + + {String(idx + 1).padStart(2, '0')} + + + {step.label} + + + + {isCurrent ? `${Math.round(liveMs)} ms` : isDone ? `${timing} ms` : '—'} + +
+
+ +
+
+ ); +} + +function KpiCell({ + label, + value, + accent, + br, + bb, +}: { + label: string; + value: string; + accent?: boolean; + br?: boolean; + bb?: boolean; +}) { + return ( +
+
+ {label} +
+
+ {value} +
+
+ ); +} + +const ARROW = 'M5 12h14M13 6l6 6-6 6'; +function ArrowRight() { + return ( + + ); +} + +const SWAP_EASE: [number, number, number, number] = [0.2, 0.8, 0.2, 1]; + +export default function LiveDemo() { + const reduce = useReducedMotion(); + const scenario = SCENARIO; + + const [hashIdx, setHashIdx] = useState(0); + const hash = HASHES[hashIdx]!; + const effConstraints = Math.round(scenario.constraints * hash.cMul); + const effEstMs = scenario.estMs * hash.tMul; + + const [phase, setPhase] = useState('idle'); + const [currentStep, setCurrentStep] = useState(-1); + const [stepTimings, setStepTimings] = useState>>({}); + const [livePhaseMs, setLivePhaseMs] = useState(0); + const [proof, setProof] = useState([]); + const [revealedBytes, setRevealedBytes] = useState(0); + const runIdRef = useRef(0); + + const reset = useCallback(() => { + runIdRef.current += 1; + setPhase('idle'); + setCurrentStep(-1); + setStepTimings({}); + setLivePhaseMs(0); + setProof([]); + setRevealedBytes(0); + }, []); + + const selectHash = useCallback( + (i: number) => { + if (i === hashIdx) return; + runIdRef.current += 1; + setHashIdx(i); + setPhase('idle'); + setCurrentStep(-1); + setStepTimings({}); + setLivePhaseMs(0); + setProof([]); + setRevealedBytes(0); + }, + [hashIdx], + ); + + const start = useCallback(async () => { + if (phase === 'running') { + reset(); + return; + } + const myRun = ++runIdRef.current; + setPhase('running'); + setStepTimings({}); + setProof([]); + setRevealedBytes(0); + + const finalTimings: Partial> = {}; + for (let i = 0; i < STEPS.length; i++) { + const step = STEPS[i]!; + const target = effEstMs * step.weight * (0.92 + Math.random() * 0.16); + setCurrentStep(i); + const startT = performance.now(); + await new Promise((resolve) => { + const tick = () => { + if (runIdRef.current !== myRun) return resolve(); + const elapsed = performance.now() - startT; + setLivePhaseMs(elapsed); + if (elapsed >= target) return resolve(); + requestAnimationFrame(tick); + }; + tick(); + }); + if (runIdRef.current !== myRun) return; + finalTimings[step.key] = Math.round(target); + setStepTimings({ ...finalTimings }); + setLivePhaseMs(0); + } + + setCurrentStep(-1); + const bytes = makeProof(192); + setProof(bytes); + setPhase('done'); + + let r = 0; + const reveal = () => { + if (runIdRef.current !== myRun) return; + r = Math.min(bytes.length, r + 6); + setRevealedBytes(r); + if (r < bytes.length) setTimeout(reveal, 30); + }; + reveal(); + }, [phase, effEstMs, reset]); + + // Cancel any in-flight loop on unmount. + useEffect(() => () => void (runIdRef.current += 1), []); + + const totalMs = + Object.values(stepTimings).reduce((a, b) => a + (b ?? 0), 0) + livePhaseMs; + const statusLabel = phase === 'running' ? 'RUNNING' : phase === 'done' ? 'VERIFIED' : 'READY'; + const statusColor = + phase === 'running' + ? 'var(--pk-brand)' + : phase === 'done' + ? 'var(--pk-brand)' + : 'var(--pk-mute-3, #B7B7B7)'; + + const swapInit = reduce ? { opacity: 0 } : { opacity: 0, y: 8 }; + const swapAnim = reduce ? { opacity: 1 } : { opacity: 1, y: 0 }; + const swapTrans = { duration: 0.36, ease: SWAP_EASE }; + + return ( +
+ {/* LEFT — inputs + CTA */} +
+
+ + Run on this device · no server + +

+ {'Try Provekit right\nin your browser'} +

+

+ Edit the inputs, then watch a zero-knowledge proof generate live. Nothing leaves this + page. +

+
+ + {/* 01 Private witness */} + +
+ + 01 · Private witness + + + +
+
+ {scenario.privates.map((p, i) => ( +
+ + {p.label} + + + {p.value} + +
+ ))} +
+
+ + {/* 02 Public statement */} + +
+ 02 · Public statement +
+
+
+ {scenario.statement} +
+
+ {scenario.publics.map((p) => ( + + {p.label} + · + {p.value} + + ))} +
+
+
+ + {/* 03 Hash function */} +
+
+ 03 · Hash function +
+
+ {HASHES.map((h, i) => { + const active = i === hashIdx; + return ( + + ); + })} +
+ + + ≈ {effConstraints.toLocaleString()} constraints · est {Math.round(effEstMs)} ms + + +
+ + {/* CTA */} +
+ + {phase !== 'idle' && ( + + )} +
+
+ + {/* RIGHT — execution trace + KPI strip */} +
+
+ + Trace · {effConstraints.toLocaleString()} constraints · {hash.label} + + + +
+ +
+ {STEPS.map((step, i) => ( + + ))} +
+ + {/* Proof artifact preview */} +
+
+ + Proof artifact + + + {revealedBytes}/192 bytes + +
+
+ {proof.slice(0, revealedBytes).map((b, i) => ( + + {b} + + ))} + {phase === 'running' && ( +
+
+ + {/* KPI strip — 2x2 grid */} +
+ + + + +
+
+
+ ); +} diff --git a/src/components/demo/LiveDemoSection.astro b/src/components/demo/LiveDemoSection.astro new file mode 100644 index 0000000..bda2e9a --- /dev/null +++ b/src/components/demo/LiveDemoSection.astro @@ -0,0 +1,70 @@ +--- +/* + * LiveDemoSection — panel chrome + React island mount point. + * + * Mirrors the bordered-panel + category-tab structure used everywhere else + * in the design (Hero, Install, Features, etc.) and hosts the LiveDemo + * React island via `client:visible` so the bundle only loads when the + * section scrolls into view. + */ +import LiveDemo from './LiveDemo.tsx'; +--- + +
+
LIVE DEMO
+ +

Run a zero-knowledge proof in your browser

+ + +
+ + diff --git a/src/components/footer/SiteFooter.astro b/src/components/footer/SiteFooter.astro index 4ebe793..df5a0b9 100644 --- a/src/components/footer/SiteFooter.astro +++ b/src/components/footer/SiteFooter.astro @@ -8,7 +8,6 @@ const DOCS_URL = 'https://docs.provekit.org/'; const product = [ { label: 'DOCS', href: DOCS_URL, external: false }, - { label: 'GUIDE', href: DOCS_URL, external: false }, onBenchmarks ? { label: 'HOME', href: '/', external: false } : { label: 'BENCHMARKS', href: '/benchmarks', external: false }, diff --git a/src/components/install/InstallScript.astro b/src/components/install/InstallScript.astro index ade357c..ed1afd8 100644 --- a/src/components/install/InstallScript.astro +++ b/src/components/install/InstallScript.astro @@ -2,7 +2,7 @@ import Panel from '~/components/panel/Panel.astro'; import ArrowRight from '~/components/icons/ArrowRight.astro'; -const DOCS_URL = 'https://docs.provekit.org/'; +const QUICKSTART_URL = 'https://docs.provekit.org/getting-started/quickstart/'; const command = 'cargo install provekit-cli'; --- @@ -34,7 +34,7 @@ const command = 'cargo install provekit-cli';
diff --git a/src/pages/benchmarks.astro b/src/pages/benchmarks.astro index 5c81b6d..10cdcf9 100644 --- a/src/pages/benchmarks.astro +++ b/src/pages/benchmarks.astro @@ -2,6 +2,7 @@ import BaseLayout from '~/layouts/BaseLayout.astro'; import TopBar from '~/components/nav/TopBar.astro'; import BenchmarksHero from '~/components/benchmarks-page/BenchmarksHero.astro'; +import LiveDemoSection from '~/components/demo/LiveDemoSection.astro'; import ProvekitDemo from '~/components/benchmarks-page/ProvekitDemo.astro'; import BenchmarksMethodology from '~/components/benchmarks-page/BenchmarksMethodology.astro'; import BenchmarkDetail from '~/components/benchmarks-page/BenchmarkDetail.astro'; @@ -21,6 +22,8 @@ import SiteFooter from '~/components/footer/SiteFooter.astro'; + + diff --git a/src/styles/global.css b/src/styles/global.css index 84adddc..952f102 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -271,6 +271,56 @@ fill: var(--pk-ink); } + /* Live-demo keyframes (CSS-only counterparts; framer-motion drives the + * primary in-app animations, but these are used by inline byte spans and + * for any consumers that opt out of motion). Mirror of