diff --git a/.gitattributes b/.gitattributes index 70284736..36484585 100644 --- a/.gitattributes +++ b/.gitattributes @@ -26,3 +26,5 @@ *.obj filter=lfs diff=lfs merge=lfs -text *.fbx filter=lfs diff=lfs merge=lfs -text *.blend filter=lfs diff=lfs merge=lfs -text +*.woff filter=lfs diff=lfs merge=lfs -text +*.woff2 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index fb85a6b7..ad53a3f1 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ next-env.d.ts .env *.local.* +.gstack/ +.claude/ +/website-nextjs/ diff --git a/bun.lock b/bun.lock index 67e70aca..56a37bc2 100644 --- a/bun.lock +++ b/bun.lock @@ -7,6 +7,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.948.0", "@calcom/embed-react": "^1.5.3", + "@chenglou/pretext": "^0.0.6", "@hookform/resolvers": "^5.2.2", "@mdx-js/loader": "^3.1.1", "@mdx-js/react": "^3.1.1", @@ -39,6 +40,7 @@ "@radix-ui/react-toggle": "^1.1.10", "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", + "@react-three/fiber": "^9.6.1", "@t3-oss/env-core": "^0.13.8", "@t3-oss/env-nextjs": "^0.13.8", "@tailwindcss/postcss": "^4.1.18", @@ -46,6 +48,7 @@ "@types/mdx": "^2.0.13", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", + "@xyflow/react": "^12.10.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -96,6 +99,7 @@ "@types/node": "^24.10.3", "@types/ramda": "^0.31.1", "@types/react-syntax-highlighter": "^15.5.13", + "@types/three": "^0.184.0", "typescript": "^5.9.3", }, }, @@ -213,6 +217,8 @@ "@calcom/embed-snippet": ["@calcom/embed-snippet@1.3.3", "", { "dependencies": { "@calcom/embed-core": "1.5.3" } }, "sha512-pqqKaeLB8R6BvyegcpI9gAyY6Xyx1bKYfWvIGOvIbTpguWyM1BBBVcT9DCeGe8Zw7Ujp5K56ci7isRUrT2Uadg=="], + "@chenglou/pretext": ["@chenglou/pretext@0.0.6", "", {}, "sha512-U10s4tFeyu3oVHfXuNWwZSKqHXefhaigpcBkGj60qQFRJ+yUoQ+ez3cGJelP7BWDAB58HCgjcTSmOcg+77afBQ=="], + "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@11.0.3", "", { "dependencies": { "@chevrotain/gast": "11.0.3", "@chevrotain/types": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ=="], "@chevrotain/gast": ["@chevrotain/gast@11.0.3", "", { "dependencies": { "@chevrotain/types": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q=="], @@ -225,6 +231,8 @@ "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="], + "@dimforge/rapier3d-compat": ["@dimforge/rapier3d-compat@0.12.0", "", {}, "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow=="], + "@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], @@ -453,6 +461,8 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + "@react-three/fiber": ["@react-three/fiber@9.6.1", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-use-measure": "^2.1.7", "scheduler": "^0.27.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": ">=19 <19.3", "react-dom": ">=19 <19.3", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-zF0rsKcVYpcJwbFEnv2HkHX9cvOEgsfQo/X8lwmR2dn13S4qEQJXir9fxf5js2LQFoXqxOY7MDkOkYx2uZ4gSg=="], + "@smithy/abort-controller": ["@smithy/abort-controller@4.2.7", "", { "dependencies": { "@smithy/types": "^4.11.0", "tslib": "^2.6.2" } }, "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw=="], "@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA=="], @@ -603,7 +613,7 @@ "@turf/invariant": ["@turf/invariant@7.3.1", "", { "dependencies": { "@turf/helpers": "7.3.1", "@types/geojson": "^7946.0.10", "tslib": "^2.8.1" } }, "sha512-IdZJfDjIDCLH+Gu2yLFoSM7H23sdetIo5t4ET1/25X8gi3GE2XSqbZwaGjuZgNh02nisBewLqNiJs2bo+hrqZA=="], - "@tweenjs/tween.js": ["@tweenjs/tween.js@25.0.0", "", {}, "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A=="], + "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="], @@ -699,12 +709,20 @@ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + "@types/react-reconciler": ["@types/react-reconciler@0.28.9", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg=="], + "@types/react-syntax-highlighter": ["@types/react-syntax-highlighter@15.5.13", "", { "dependencies": { "@types/react": "*" } }, "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA=="], + "@types/stats.js": ["@types/stats.js@0.17.4", "", {}, "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA=="], + + "@types/three": ["@types/three@0.184.0", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": ">=0.5.17", "fflate": "~0.8.2", "meshoptimizer": "~1.1.1" } }, "sha512-4mY2tZAu0y0B0567w7013BBXSpsP0+Z48NJvmNo4Y/Pf76yCyz6Jw4P3tUVs10WuYNXXZ+wmHyGWpCek3amJxA=="], + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], @@ -741,6 +759,10 @@ "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="], + "@xyflow/react": ["@xyflow/react@12.10.2", "", { "dependencies": { "@xyflow/system": "0.0.76", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-CgIi6HwlcHXwlkTpr0fxLv/0sRVNZ8IdwKLzzeCscaYBwpvfcH1QFOCeaTCuEn1FQEs/B8CjnTSjhs8udgmBgQ=="], + + "@xyflow/system": ["@xyflow/system@0.0.76", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-interpolate": "^3.0.4", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-interpolate": "^3.0.1", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-hvwvnRS1B3REwVDlWexsq7YQaPZeG3/mKo1jv38UmnpWmxihp14bW6VtEOuHEwJX2FvzFw8k77LyKSk/wiZVNA=="], + "accessor-fn": ["accessor-fn@1.5.3", "", {}, "sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], @@ -769,6 +791,8 @@ "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.9.10", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-2VIKvDx8Z1a9rTB2eCkdPE5nSe28XnA+qivGnWHoB40hMMt/h1hSz0960Zqsn6ZyxWXUie0EBdElKv8may20AA=="], "bezier-easing": ["bezier-easing@2.1.0", "", {}, "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig=="], @@ -777,6 +801,8 @@ "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], @@ -803,6 +829,8 @@ "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + "classcat": ["classcat@5.0.5", "", {}, "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="], + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], @@ -1021,7 +1049,7 @@ "feed": ["feed@4.2.2", "", { "dependencies": { "xml-js": "^1.6.11" } }, "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ=="], - "fflate": ["fflate@0.4.8", "", {}, "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="], + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], "float-tooltip": ["float-tooltip@1.7.5", "", { "dependencies": { "d3-selection": "2 - 3", "kapsule": "^1.16", "preact": "10" } }, "sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg=="], @@ -1081,6 +1109,8 @@ "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "index-array-by": ["index-array-by@1.4.2", "", {}, "sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw=="], "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], @@ -1101,6 +1131,8 @@ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "its-fine": ["its-fine@2.0.0", "", { "dependencies": { "@types/react-reconciler": "^0.28.9" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng=="], + "jerrypick": ["jerrypick@1.1.2", "", {}, "sha512-YKnxXEekXKzhpf7CLYA0A+oDP8V0OhICNCr5lv96FvSsDEmrb0GKM776JgQvHTMjr7DTTPEVv/1Ciaw0uEWzBA=="], "jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], @@ -1215,6 +1247,8 @@ "mermaid": ["mermaid@11.12.2", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.1", "@mermaid-js/parser": "^0.6.3", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.13", "dayjs": "^1.11.18", "dompurify": "^3.2.5", "katex": "^0.16.22", "khroma": "^2.1.0", "lodash-es": "^4.17.21", "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0" } }, "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w=="], + "meshoptimizer": ["meshoptimizer@1.1.1", "", {}, "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g=="], + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], @@ -1407,6 +1441,8 @@ "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], + "react-use-measure": ["react-use-measure@2.1.7", "", { "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13" }, "optionalPeers": ["react-dom"] }, "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg=="], + "recharts": ["recharts@2.15.4", "", { "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", "lodash": "^4.17.21", "react-is": "^18.3.1", "react-smooth": "^4.0.4", "recharts-scale": "^0.4.4", "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw=="], "recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="], @@ -1495,6 +1531,8 @@ "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "suspend-react": ["suspend-react@0.1.3", "", { "peerDependencies": { "react": ">=17.0" } }, "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ=="], + "tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="], "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], @@ -1617,6 +1655,8 @@ "zod": ["zod@4.2.1", "", {}, "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw=="], + "zustand": ["zustand@5.0.12", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g=="], + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], @@ -1671,6 +1711,8 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@xyflow/react/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], + "chevrotain/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], "cmdk/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], @@ -1687,6 +1729,8 @@ "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + "globe.gl/@tweenjs/tween.js": ["@tweenjs/tween.js@25.0.0", "", {}, "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A=="], + "hastscript/@types/hast": ["@types/hast@2.3.10", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw=="], "hastscript/comma-separated-tokens": ["comma-separated-tokens@1.0.8", "", {}, "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw=="], @@ -1701,6 +1745,8 @@ "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + "posthog-js/fflate": ["fflate@0.4.8", "", {}, "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="], + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "refractor/prismjs": ["prismjs@1.27.0", "", {}, "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="], @@ -1711,6 +1757,10 @@ "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "three-globe/@tweenjs/tween.js": ["@tweenjs/tween.js@25.0.0", "", {}, "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A=="], + + "three-render-objects/@tweenjs/tween.js": ["@tweenjs/tween.js@25.0.0", "", {}, "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], diff --git a/docs/design-system/DESIGN.md b/docs/design-system/DESIGN.md new file mode 100644 index 00000000..9508c416 --- /dev/null +++ b/docs/design-system/DESIGN.md @@ -0,0 +1,380 @@ +# Phala v3 — Style Reference + +> Schematic confidential-compute. Bauhaus + CLI lineage. + +**Theme:** light-default with parity dark mode. + +The v3 voice is *schematic*, not decorative. Where the old marketing voice leaned on illustration, v3 reads like a system diagram: sharp corners, hairline borders, monospaced metadata, lots of negative space, and one phala-lime accent reserved for primary state. Body type uses **ABCDiatype**; display headlines use **ABCArizonaFlare** at 400 (regular) — large sizes, modest weight; the contrast comes from scale, not heaviness. Code, eyebrows, and metadata use **SuisseIntlMono**. Icons (lucide-react) are restyled globally — square caps, miter joins, 1.25 stroke. Animation is reserved for proof / verification moments (count-ups, scan-line seals, ASCII anime). + +## Tokens — Colors + +### Base scale (greige / near-neutral) +OKLCH-defined; reads as warm gray with a faint green hue (chroma ~0.005). + +| Name | Value | Token | Role | +|---|---|---|---| +| base-50 | `oklch(0.983 0.0034 145.55)` | `--base-50` | Lightest neutral; marketing section bg (#fbfcf8 visual) | +| base-100 | `oklch(0.969 0.0037 146.57)` | `--base-100` | Muted surface, hover states | +| base-200 | `oklch(0.926 0.0048 147.01)` | `--base-200` | Borders + secondary surface | +| base-300 | `oklch(0.869 0.0054 148)` | `--base-300` | Input borders, disabled | +| base-400 | `oklch(0.707 0.0061 149.29)` | `--base-400` | Faded text | +| base-500 | `oklch(0.553 0.0066 150.55)` | `--base-500` | Tertiary text | +| base-600 | `oklch(0.444 0.0065 151.33)` | `--base-600` | `--muted-foreground` | +| base-700 | `oklch(0.373 0.0059 150.75)` | `--base-700` | Body alternate | +| base-800 | `oklch(0.273 0.0051 150.35)` | `--base-800` | `--foreground` (default body) | +| base-900 | `oklch(0.212 0.0048 151.01)` | `--base-900` | Dark card, pre-black | +| base-950 | `oklch(0.139 0.0044 150.49)` | `--base-950` | Dark mode background | +| base-1000 | `oklch(0.091 0.0041 150.95)` | `--base-1000` | Pure-near-black, dark CVM panels | + +### Primary (phala lime) +This is the brand accent. Reserve for proof / live / sealed / verified states. Never for body text. + +| Name | Value | Token | Role | +|---|---|---|---| +| primary-50 | `oklch(0.986 0.031 118.52)` | `--primary-50` | Cream tint background | +| primary-100 | `oklch(0.968 0.068 119.72)` | `--primary-100` | | +| primary-200 | `oklch(0.939 0.129 121.44)` | `--primary-200` | | +| primary-300 | `oklch(0.896 0.197 123.29)` | **`--primary`** | The default phala-green chip / pulse / live indicator | +| primary-400 | `oklch(0.842 0.237 125.02)` | `--primary-400` | | +| primary-500 | `oklch(0.771 0.231 126.52)` | `--primary-500` | | +| primary-600 | `oklch(0.651 0.197 127.14)` | `--primary-600` | | +| primary-700 | `oklch(0.534 0.157 126.91)` | `--primary-700` | **Hover/active text-primary on light theme** | +| primary-800 | `oklch(0.455 0.125 126.16)` | `--primary-800` | | +| primary-900 | `oklch(0.407 0.102 125.95)` | `--primary-900` | | +| primary-950 | `oklch(0.275 0.072 126.79)` | `--primary-950` | | +| primary-1000 | `oklch(0.190 0.053 127.24)` | `--primary-1000` | Deep cream (dark mode) | + +### Phala Blue (periwinkle) — secondary accent +Default text accent on light surfaces for everything that isn't the lime. The "exa blue" of v3. + +| Name | Value | Token | Role | +|---|---|---|---| +| phala-blue-50 | `#f0f2ff` | `--phala-blue-50` | | +| phala-blue-100 | `#d5dbf8` | `--phala-blue-100` | Soft tint surface | +| phala-blue-200 | `#bfc8f0` | `--phala-blue-200` | | +| phala-blue-300 | `#aabbff` | `--phala-blue-300` | Filled accent | +| phala-blue-400 | `#8b9fe0` | `--phala-blue-400` | | +| phala-blue-500 | `#6b80cc` | **`--phala-blue-500`** | **Default text accent for ASCII anime / code chips on light theme** | +| phala-blue-900 | `#2d3250` | `--phala-blue-900` | | + +### Phala Purple — tertiary accent (Memory / RTMR / KMS chrome) +| Name | Value | Token | +|---|---|---| +| phala-purple-50 | `#f5f0f8` | `--phala-purple-50` | +| phala-purple-100 | `#e7e1eb` | `--phala-purple-100` | +| phala-purple-200 | `#d4c0e8` | `--phala-purple-200` | +| phala-purple-300 | `#b88fd0` | `--phala-purple-300` | +| phala-purple-400 | `#9b6bbf` | `--phala-purple-400` | +| phala-purple-500 | `#7e3daf` | `--phala-purple-500` | +| phala-purple-900 | `#3d2055` | `--phala-purple-900` | + +### Phala Orange — alert / receipt / signature accent +Used for `x-phala-receipt-sig` headers, signing flows, KMS attestation arrows. + +| Name | Value | Token | +|---|---|---| +| phala-orange-50 | `#fff5ec` | `--phala-orange-50` | +| phala-orange-100 | `#f8e7d5` | `--phala-orange-100` | +| phala-orange-200 | `#f0cca0` | `--phala-orange-200` | +| phala-orange-300 | `#f5902c` | `--phala-orange-300` | +| phala-orange-400 | `#d87a20` | `--phala-orange-400` | +| phala-orange-500 | `#a07830` | `--phala-orange-500` | +| phala-orange-900 | `#4a3520` | `--phala-orange-900` | + +### Semantic tokens + +| Token | Light | Dark | Role | +|---|---|---|---| +| `--background` | `--base-50` | `--base-950` | Page background | +| `--foreground` | `--base-800` | `--base-200` | Body text | +| `--card` | `#fff` | `--base-900` | Card surface | +| `--card-foreground` | `--base-800` | `--base-200` | Card text | +| `--muted` | `--base-100` | `--base-800` | Muted block | +| `--muted-foreground` | `--base-600` | `--base-300` | Muted text | +| `--border` | `--base-200` | `--base-800` | Hairline divider | +| `--input` | `--base-300` | `--base-700` | Input border | +| `--primary` | `--primary-300` | `--primary-300` | Lime — same in both modes | +| `--primary-foreground` | `#000` | `#000` | Text on lime | +| `--ring` | `--primary-300` | `--primary-300` | Focus ring | +| `--destructive` | `oklch(0.577 0.245 27.325)` | `oklch(0.704 0.191 22.216)` | Red | + +## Tokens — Typography + +### `ABCArizonaFlare` — Display headlines · `--v3-heading` +- **Substitute:** Georgia, serif +- **Weight:** 400 (regular only — no bold) +- **Sizes used:** 38 / 58 / 64 / 68 / 76 px (hero claims), `clamp(30, 2.8vw, 46)` (section titles) +- **Line height:** 0.96–1.10 +- **Letter spacing:** 0 +- **Role:** All h1, h2, `.font-display`, `.exa-section-title`, `.exa-hero-claim`, `.dstack-heading`, `.cvm-section-title`. Light weight at large size is the signature. + +### `ABCDiatype` — Body, UI, navigation · `--v3-body` / `--v3-ui` +- **Substitute:** "Trebuchet MS", sans-serif +- **Weights:** 400 (regular), 500 (medium), 600 (semibold) +- **Sizes:** 12 / 13 / 14 / 15 / 16 / 18 / 20 px +- **Line height:** 1.18–1.7 +- **Letter spacing:** 0 +- **Role:** All `

`, ``, ` +``` + +### Outline / secondary CTA +Card bg, border, foreground text. +```tsx + + Read docs + + +``` + +### Eyebrow + title pair +The standard section header rhythm. +```tsx +

+ GPU TEE proof path +

+

+ What Phala handles for the CVM path. +

+``` + +### Status pill (live / sealed / verified) +```tsx + + + live + +``` + +### Hairline grid (n cards in a row) +```tsx +
+ + + +
+``` +The `gap-px` creates 1px gutters that read as the `bg-border` color showing through. + +### Code block (Sign-RPC / cURL idiom) +```tsx +
+  $ phala deploy
+  x-phala-receipt-sig: 0x9c..
+  x-phala-compose-hash: 0xa1..
+
+``` +Use emerald for shell prompts, amber for receipt/signature, cyan for compose-hash, white/85 for body. + +### Card hover +The card+icon coordinated hover: card border darkens to `primary-700`, icon turns same color. +```tsx +
+ +

{title}

+

{body}

+
+``` + +### Footer / sitemap +Footer is a structured navigation surface, not a full sitemap dump. + +- Use the phala-blue tint family for footer chrome: `bg-phala-blue-100` outer wash, `bg-phala-blue-50` cells, `border-phala-blue-300` gutters. +- Container target: `max-w-[1440px] px-5 sm:px-8 lg:px-12`. +- Group links into decision buckets, usually `Build`, `Platform`, `Solutions`, `Proof`, `Learn`, `Company`. +- Avoid duplicated Blog/Learn/docs links across multiple groups. +- Use `gap-px border bg-phala-blue-300` grid gutters, matching the menu/card system. +- Keep footer text compact: group headings use mono `text-[11px] uppercase tracking-[0.14em]`; links use body `text-[14px]`. +- Social/status/legal are a separate bottom grid, not mixed into navigation columns. + +### Report cards +Success-story and report cards should read like documents, not poster ads. + +- Keep images in a fixed media region (`grid-rows-[150px_1fr]` or equivalent), with text on a clean card surface. +- Do not place long descriptions directly over variable imagery. +- Use max 3 columns for report grids (`sm:grid-cols-2 lg:grid-cols-3`) so category, title, and stats remain legible. +- Show only the strongest 1–2 stat rows on cards. Full detail belongs on the slug page. +- Use a direct CTA (`Talk to expert`) on success-story list/detail pages when the page is evidence-led. + +### PDF report embed +PDF reports are document content. Keep the viewer quiet. + +- Put actions above the embed: `Open in new tab`, `Download PDF`, and any sales CTA. +- Embed the PDF itself without redundant filename/status/helper chrome. +- Use page-fit anchors for A4 portrait reports: `#page=1&view=Fit&zoom=page-fit&pagemode=none&toolbar=0&navpanes=0`. +- Constrain wide pages with a document frame such as `max-w-[980px]` so portrait PDFs do not become clipped landscape canvases. + +## Do's and Don'ts + +### Do +- Reserve `text-primary` (lime) for *proof states* — verified, sealed, live, attested. Not body copy. +- Use `text-phala-blue-500 dark:text-primary` for the secondary accent (ASCII anime, code-comment chips, charts). +- Use ABCArizonaFlare at 400 weight for h1/h2 — light weight, big size, modest tracking. +- Use SuisseIntlMono uppercase tracking-wider for eyebrows, status pills, log rows, terminal output. +- Use `gap-px border bg-border` to produce hairline grids; the gutter IS the border color. +- Use `0` border radius by default. `rounded-[4px]` for buttons / chips. +- Use `lucideRestyle` (square caps, miter joins, 1.25 stroke) for every lucide icon — already enforced globally. +- Use ASCII anime for proof moments (CVM boot, RA-TLS handshake, GPU CC seal). Reserve for hero / large illustration slots. +- Use 1px hairline borders + slight bg shifts for elevation. Never `box-shadow` for marketing. +- Match heights with `lg:items-stretch` + `mt-auto` to bottom-align CTAs. + +### Don't +- Don't use rounded-full / pill buttons. Sharp corners only. +- Don't use heavy display weights (>500) for hero claims. +- Don't introduce shadows for depth — use color shifts. +- Don't introduce new saturated palettes; stick to lime + phala-blue + phala-purple + phala-orange + base. +- Don't use the lime accent for body text on light bg — too pale. Use `primary-700` if you must. +- Don't put body content inside `
`/`
` with hover effects unless it's a real link — clickable affordances must be `` or ``. +- Don't add PDF filename/status/helper chrome when the page already has report actions and context. + +## Layout + +- **Container max-width:** target **1280px** (with `px-5 sm:px-8 lg:px-12` horizontal padding). Wider hero pages can use `1440px`. Avoid `max-w-7xl` (= 1280) without padding. +- **Section padding:** `py-12 md:py-16` is the default. Heroes slightly larger (`md:py-20+`); explainer sections can drop to `py-10`. +- **Section dividers:** `border-border border-b` between sections, or alternating bg colors (white → `#f7f8f3` → `#fbfcf8`). +- **Grid systems:** Cards in 2-4 columns via `lg:grid-cols-[1.12fr_0.88fr]` or `sm:grid-cols-2 lg:grid-cols-3` — fractional ratios reserved for asymmetric layouts. +- **Mobile:** stack vertically with `gap-6` to `gap-8`. Most grids use `lg:` breakpoint to switch to multi-column. + +## Voice + +The brand is *security-by-construction*, not *security-by-claim*. Copy reads like a system spec rather than a sales pitch: +- Concrete primitives ("compose-hash IS the policy") +- Hardware names + spec values ("Intel TDX + H100", "288GB HBM3e") +- Verifiable receipts ("x-phala-receipt-sig", "Sign-RPC") +- Schematic over decorative ("Two-hop RA-TLS, all the way to the model") + +Avoid: "revolutionary", "world-class", "AI-powered", "next-generation", "cutting-edge". +Prefer: "verified", "sealed", "attested", "verifiable offline", "compose-hash bound". + +## Quick reference + +| Need | Token / Class | +|---|---| +| Page bg | `bg-background` | +| Card bg | `bg-card` | +| Body text | `text-foreground` | +| Muted text | `text-muted-foreground` | +| Primary accent | `text-primary` (chips/states) · `text-primary-700 dark:text-primary` (text on light) | +| Secondary accent | `text-phala-blue-500 dark:text-primary` | +| Hairline divider | `border-border` | +| Section gutter | `gap-px bg-border` (inside grid) | +| Display font | `font-display` (ABCArizonaFlare) | +| Body font | `font-sans` / inherited (ABCDiatype) | +| Mono font | `font-mono` (SuisseIntlMono) | +| Standard radius | `rounded-[4px]` (buttons) — `0` everywhere else | +| Button height | `h-11` | +| Section padding | `py-12 md:py-16` | +| Container | `mx-auto w-full max-w-[1280px] px-5 sm:px-8 lg:px-12` | + +## Files of record + +- Color tokens: `src/app/theme/colors.css` +- Type tokens: `src/app/theme/typography.css` (font CSS vars), `src/app/globals.css` (`@font-face`) +- Global icon restyle: `src/app/globals.css` (`.lucide` rule) +- Custom domain icons: `src/components/icons/` +- ASCII anime renderer: `src/components/ascii-anime/` +- Exa typography component (per-page font scope): `src/components/product/exa-typography.tsx` diff --git a/docs/design-system/theme.css b/docs/design-system/theme.css new file mode 100644 index 00000000..197cd3e3 --- /dev/null +++ b/docs/design-system/theme.css @@ -0,0 +1,110 @@ +/* + * Phala v3 — Tailwind v4 @theme block. + * + * Drop into src/app/globals.css after Tailwind import to expose tokens as + * utilities (text-primary, bg-phala-blue-500, font-display, etc.). + * + * This is a flat reference; the production site sources values from + * src/app/theme/colors.css via `@theme inline` so the CSS vars are the + * single source of truth. + */ + +@theme { + /* ─── Base scale ─────────────────────────────────────────────────── */ + --color-base-50: oklch(0.983 0.0034 145.55); + --color-base-100: oklch(0.9691 0.0037 146.57); + --color-base-200: oklch(0.9258 0.0048 147.01); + --color-base-300: oklch(0.869 0.0054 148); + --color-base-400: oklch(0.7067 0.0061 149.29); + --color-base-500: oklch(0.5535 0.0066 150.55); + --color-base-600: oklch(0.4449 0.0065 151.33); + --color-base-700: oklch(0.3731 0.0059 150.75); + --color-base-800: oklch(0.2731 0.0051 150.35); + --color-base-900: oklch(0.2123 0.0048 151.01); + --color-base-950: oklch(0.1386 0.0044 150.49); + --color-base-1000: oklch(0.0909 0.0041 150.95); + + /* ─── Primary scale ──────────────────────────────────────────────── */ + --color-primary-50: oklch(0.9861 0.0309 118.52); + --color-primary-100: oklch(0.9676 0.0683 119.72); + --color-primary-200: oklch(0.9387 0.1289 121.44); + --color-primary-300: oklch(0.8962 0.1971 123.29); + --color-primary-400: oklch(0.8421 0.2371 125.02); + --color-primary-500: oklch(0.7708 0.2308 126.52); + --color-primary-600: oklch(0.6514 0.1967 127.14); + --color-primary-700: oklch(0.5343 0.1568 126.91); + --color-primary-800: oklch(0.4554 0.1246 126.16); + --color-primary-900: oklch(0.4067 0.1017 125.95); + --color-primary-950: oklch(0.2752 0.0724 126.79); + --color-primary-1000: oklch(0.1899 0.0531 127.24); + + /* ─── Phala Blue ─────────────────────────────────────────────────── */ + --color-phala-blue-50: #f0f2ff; + --color-phala-blue-100: #d5dbf8; + --color-phala-blue-200: #bfc8f0; + --color-phala-blue-300: #aabbff; + --color-phala-blue-400: #8b9fe0; + --color-phala-blue-500: #6b80cc; + --color-phala-blue-900: #2d3250; + + /* ─── Phala Purple ───────────────────────────────────────────────── */ + --color-phala-purple-50: #f5f0f8; + --color-phala-purple-100: #e7e1eb; + --color-phala-purple-200: #d4c0e8; + --color-phala-purple-300: #b88fd0; + --color-phala-purple-400: #9b6bbf; + --color-phala-purple-500: #7e3daf; + --color-phala-purple-900: #3d2055; + + /* ─── Phala Orange ───────────────────────────────────────────────── */ + --color-phala-orange-50: #fff5ec; + --color-phala-orange-100: #f8e7d5; + --color-phala-orange-200: #f0cca0; + --color-phala-orange-300: #f5902c; + --color-phala-orange-400: #d87a20; + --color-phala-orange-500: #a07830; + --color-phala-orange-900: #4a3520; + + /* ─── Typography families ────────────────────────────────────────── */ + --font-display: "ABCArizonaFlare", Georgia, serif; + --font-sans: "ABCDiatype", "Trebuchet MS", Arial, sans-serif; + --font-mono: "SuisseIntlMono", "SFMono-Regular", Consolas, monospace; + + /* ─── Type-step utilities (Phala v3 sizing) ──────────────────────── */ + --text-caption: 11px; + --leading-caption: 1.2; + --text-eyebrow: 11px; + --leading-eyebrow: 1.2; + --tracking-eyebrow: 0.08em; + --text-body-sm: 13px; + --leading-body-sm: 1.5; + --text-body: 15px; + --leading-body: 1.65; + --text-body-lg: 18px; + --leading-body-lg: 1.4; + --text-ui: 15px; + --leading-ui: 1.2; + --text-card-title: 24px; + --leading-card-title: 1.1; + --text-section-title-min: 30px; + --text-section-title-pref: 2.8vw; + --text-section-title-max: 46px; + --leading-section-title: 1.08; + --text-hero-claim-mobile: 38px; + --text-hero-claim-tablet: 58px; + --text-hero-claim-desktop: 68px; + --leading-hero-claim: 0.96; + + /* ─── Spacing rhythm ─────────────────────────────────────────────── */ + --spacing-section-y: 48px; + --spacing-section-y-md: 64px; + --spacing-section-y-lg: 96px; + + /* ─── Border radii (mostly sharp) ────────────────────────────────── */ + --radius-sm: 0px; + --radius-md: 2px; + --radius: 4px; + --radius-lg: 4px; + --radius-xl: 8px; + /* No --radius-full: pill buttons are not part of v3. */ +} diff --git a/docs/design-system/tokens.json b/docs/design-system/tokens.json new file mode 100644 index 00000000..b2157a51 --- /dev/null +++ b/docs/design-system/tokens.json @@ -0,0 +1,174 @@ +{ + "$schema": "https://schemas.dtcg.org/design-tokens", + "$description": "Phala v3 design tokens — extracted from src/app/theme/colors.css and src/app/theme/typography.css.", + "color": { + "base": { + "50": { "$value": "oklch(0.983 0.0034 145.55)", "$type": "color", "$description": "Lightest neutral, marketing section bg tone" }, + "100": { "$value": "oklch(0.9691 0.0037 146.57)", "$type": "color", "$description": "Muted surface" }, + "200": { "$value": "oklch(0.9258 0.0048 147.01)", "$type": "color", "$description": "Border default" }, + "300": { "$value": "oklch(0.869 0.0054 148)", "$type": "color" }, + "400": { "$value": "oklch(0.7067 0.0061 149.29)", "$type": "color" }, + "500": { "$value": "oklch(0.5535 0.0066 150.55)", "$type": "color" }, + "600": { "$value": "oklch(0.4449 0.0065 151.33)", "$type": "color", "$description": "Muted foreground" }, + "700": { "$value": "oklch(0.3731 0.0059 150.75)", "$type": "color" }, + "800": { "$value": "oklch(0.2731 0.0051 150.35)", "$type": "color", "$description": "Default foreground (body text)" }, + "900": { "$value": "oklch(0.2123 0.0048 151.01)", "$type": "color" }, + "950": { "$value": "oklch(0.1386 0.0044 150.49)", "$type": "color", "$description": "Dark mode background" }, + "1000": { "$value": "oklch(0.0909 0.0041 150.95)", "$type": "color", "$description": "Pre-black" } + }, + "primary": { + "$description": "Phala lime — proof / live / sealed / verified states. Never body text.", + "50": { "$value": "oklch(0.9861 0.0309 118.52)", "$type": "color" }, + "100": { "$value": "oklch(0.9676 0.0683 119.72)", "$type": "color" }, + "200": { "$value": "oklch(0.9387 0.1289 121.44)", "$type": "color" }, + "300": { "$value": "oklch(0.8962 0.1971 123.29)", "$type": "color", "$description": "Default primary chip" }, + "400": { "$value": "oklch(0.8421 0.2371 125.02)", "$type": "color" }, + "500": { "$value": "oklch(0.7708 0.2308 126.52)", "$type": "color" }, + "600": { "$value": "oklch(0.6514 0.1967 127.14)", "$type": "color" }, + "700": { "$value": "oklch(0.5343 0.1568 126.91)", "$type": "color", "$description": "Hover/active text-primary on light theme" }, + "800": { "$value": "oklch(0.4554 0.1246 126.16)", "$type": "color" }, + "900": { "$value": "oklch(0.4067 0.1017 125.95)", "$type": "color" }, + "950": { "$value": "oklch(0.2752 0.0724 126.79)", "$type": "color" }, + "1000": { "$value": "oklch(0.1899 0.0531 127.24)", "$type": "color" } + }, + "phala-blue": { + "$description": "Periwinkle — secondary accent for ASCII anime, code chips, charts.", + "50": { "$value": "#f0f2ff", "$type": "color" }, + "100": { "$value": "#d5dbf8", "$type": "color" }, + "200": { "$value": "#bfc8f0", "$type": "color" }, + "300": { "$value": "#aabbff", "$type": "color" }, + "400": { "$value": "#8b9fe0", "$type": "color" }, + "500": { "$value": "#6b80cc", "$type": "color", "$description": "Default text accent for v3 secondary surfaces" }, + "900": { "$value": "#2d3250", "$type": "color" } + }, + "phala-purple": { + "$description": "Memory / RTMR / KMS chrome.", + "50": { "$value": "#f5f0f8", "$type": "color" }, + "100": { "$value": "#e7e1eb", "$type": "color" }, + "200": { "$value": "#d4c0e8", "$type": "color" }, + "300": { "$value": "#b88fd0", "$type": "color" }, + "400": { "$value": "#9b6bbf", "$type": "color" }, + "500": { "$value": "#7e3daf", "$type": "color" }, + "900": { "$value": "#3d2055", "$type": "color" } + }, + "phala-orange": { + "$description": "Receipt / signature / Sign-RPC alert accent.", + "50": { "$value": "#fff5ec", "$type": "color" }, + "100": { "$value": "#f8e7d5", "$type": "color" }, + "200": { "$value": "#f0cca0", "$type": "color" }, + "300": { "$value": "#f5902c", "$type": "color" }, + "400": { "$value": "#d87a20", "$type": "color" }, + "500": { "$value": "#a07830", "$type": "color" }, + "900": { "$value": "#4a3520", "$type": "color" } + }, + "semantic-light": { + "background": { "$value": "{color.base.50}", "$type": "color" }, + "foreground": { "$value": "{color.base.800}", "$type": "color" }, + "card": { "$value": "#ffffff", "$type": "color" }, + "card-foreground": { "$value": "{color.base.800}", "$type": "color" }, + "primary": { "$value": "{color.primary.300}", "$type": "color" }, + "primary-foreground": { "$value": "#000000", "$type": "color" }, + "muted": { "$value": "{color.base.100}", "$type": "color" }, + "muted-foreground": { "$value": "{color.base.600}", "$type": "color" }, + "border": { "$value": "{color.base.200}", "$type": "color" }, + "ring": { "$value": "{color.primary.300}", "$type": "color" } + }, + "semantic-dark": { + "background": { "$value": "{color.base.950}", "$type": "color" }, + "foreground": { "$value": "{color.base.200}", "$type": "color" }, + "card": { "$value": "{color.base.900}", "$type": "color" }, + "muted": { "$value": "{color.base.800}", "$type": "color" }, + "muted-foreground": { "$value": "{color.base.300}", "$type": "color" }, + "border": { "$value": "{color.base.800}", "$type": "color" } + }, + "surface": { + "$description": "Section background tones used inline across v3 pages.", + "marketing": { "$value": "#f7f8f3", "$type": "color", "$description": "Beige section bg (hero-adjacent)" }, + "marketing-cool": { "$value": "#f0f1ec", "$type": "color", "$description": "Cooler section bg" }, + "marketing-light": { "$value": "#fbfcf8", "$type": "color", "$description": "Lightest section bg" }, + "trust-path": { "$value": "#070908", "$type": "color", "$description": "Inverted dark band (Proof path / Sign-RPC sections)" }, + "trust-card": { "$value": "#101310", "$type": "color", "$description": "Dark card on trust-path bg" } + } + }, + "font": { + "display": { + "$value": "ABCArizonaFlare", + "$type": "fontFamily", + "$description": "Display headlines — h1, h2, hero claims. Use 400 weight at large sizes; the contrast comes from scale, not heaviness." + }, + "body": { + "$value": "ABCDiatype", + "$type": "fontFamily", + "$description": "Body, UI, navigation, links, h3." + }, + "mono": { + "$value": "SuisseIntlMono", + "$type": "fontFamily", + "$description": "Eyebrows, status pills, code, ASCII anime, terminal mockups." + } + }, + "typography": { + "caption": { "$value": { "fontFamily": "{font.mono}", "fontSize": "11px", "fontWeight": 400, "lineHeight": 1.2, "letterSpacing": "0.08em", "textTransform": "uppercase" }, "$type": "typography" }, + "eyebrow": { "$value": { "fontFamily": "{font.mono}", "fontSize": "12px", "fontWeight": 400, "lineHeight": 1.2, "letterSpacing": "0.08em", "textTransform": "uppercase" }, "$type": "typography" }, + "body-sm": { "$value": { "fontFamily": "{font.body}", "fontSize": "13px", "fontWeight": 400, "lineHeight": 1.5 }, "$type": "typography" }, + "body": { "$value": { "fontFamily": "{font.body}", "fontSize": "15px", "fontWeight": 400, "lineHeight": 1.65 }, "$type": "typography" }, + "body-lg": { "$value": { "fontFamily": "{font.body}", "fontSize": "18px", "fontWeight": 400, "lineHeight": 1.4 }, "$type": "typography" }, + "ui": { "$value": { "fontFamily": "{font.body}", "fontSize": "15px", "fontWeight": 500, "lineHeight": 1.2 }, "$type": "typography" }, + "card-title": { "$value": { "fontFamily": "{font.display}", "fontSize": "24px", "fontWeight": 400, "lineHeight": 1.1 }, "$type": "typography" }, + "section-title": { "$value": { "fontFamily": "{font.display}", "fontSize": "clamp(30px,2.8vw,46px)", "fontWeight": 400, "lineHeight": 1.08 }, "$type": "typography" }, + "hero-claim": { "$value": { "fontFamily": "{font.display}", "fontSize": "68px", "fontWeight": 400, "lineHeight": 0.98, "$description": "Mobile 38px, sm 58px, lg 64-68px" }, "$type": "typography" } + }, + "spacing": { + "0": { "$value": "0px", "$type": "dimension" }, + "px": { "$value": "1px", "$type": "dimension", "$description": "Hairline gutter inside `gap-px bg-border` grids" }, + "1": { "$value": "4px", "$type": "dimension" }, + "2": { "$value": "8px", "$type": "dimension" }, + "3": { "$value": "12px", "$type": "dimension" }, + "4": { "$value": "16px", "$type": "dimension" }, + "5": { "$value": "20px", "$type": "dimension" }, + "6": { "$value": "24px", "$type": "dimension" }, + "8": { "$value": "32px", "$type": "dimension" }, + "10": { "$value": "40px", "$type": "dimension" }, + "12": { "$value": "48px", "$type": "dimension", "$description": "Default section py minimum" }, + "16": { "$value": "64px", "$type": "dimension", "$description": "Default section py md" }, + "20": { "$value": "80px", "$type": "dimension" }, + "24": { "$value": "96px", "$type": "dimension", "$description": "Generous section py" } + }, + "radius": { + "none": { "$value": "0", "$type": "dimension", "$description": "Default — sharp corners" }, + "default": { "$value": "4px", "$type": "dimension", "$description": "Buttons, chips" }, + "sm": { "$value": "0", "$type": "dimension" }, + "md": { "$value": "2px", "$type": "dimension" }, + "lg": { "$value": "4px", "$type": "dimension" }, + "xl": { "$value": "8px", "$type": "dimension" } + }, + "layout": { + "container-max": { "$value": "1280px", "$type": "dimension", "$description": "Default max-width for v3 pages" }, + "container-max-wide": { "$value": "1440px", "$type": "dimension", "$description": "Wider hero pages" } + }, + "icon": { + "$description": "Phala v3 icons use a global stroke restyle: square caps, miter joins, 1.25 stroke. Applied via .lucide CSS rule in globals.css.", + "stroke-width": { "$value": "1.25", "$type": "number" }, + "stroke-linecap": { "$value": "square", "$type": "string" }, + "stroke-linejoin": { "$value": "miter", "$type": "string" }, + "size-xs": { "$value": "12px", "$type": "dimension" }, + "size-sm": { "$value": "16px", "$type": "dimension" }, + "size-md": { "$value": "20px", "$type": "dimension" }, + "size-lg": { "$value": "24px", "$type": "dimension", "$description": "Default icon size" }, + "size-xl": { "$value": "32px", "$type": "dimension" }, + "size-2xl": { "$value": "48px", "$type": "dimension" } + }, + "$extensions": { + "phala.network": { + "designSystemVersion": "v3", + "extractedFrom": [ + "src/app/theme/colors.css", + "src/app/theme/typography.css", + "src/app/globals.css" + ], + "designLanguage": "schematic / Bauhaus / CLI lineage", + "iconLibrary": "lucide-react (restyled)", + "customIconPattern": "Composition family: [base] + [Lock corner badge]. Frame family: [base] in sharp registry square." + } + } +} diff --git a/docs/design-system/variables.css b/docs/design-system/variables.css new file mode 100644 index 00000000..44608900 --- /dev/null +++ b/docs/design-system/variables.css @@ -0,0 +1,149 @@ +/* + * Phala v3 — Design tokens as plain CSS custom properties. + * + * Source of truth in the live site: + * - src/app/theme/colors.css (full :root + .dark) + * - src/app/theme/typography.css (font CSS vars) + * - src/app/globals.css (.lucide global rule + @font-face) + * + * This file is a flat export for reference / external tools. + */ + +:root { + /* ─── Base scale (greige, OKLCH) ─────────────────────────────────── */ + --base-50: oklch(0.983 0.0034 145.55); + --base-100: oklch(0.9691 0.0037 146.57); + --base-200: oklch(0.9258 0.0048 147.01); + --base-300: oklch(0.869 0.0054 148); + --base-400: oklch(0.7067 0.0061 149.29); + --base-500: oklch(0.5535 0.0066 150.55); + --base-600: oklch(0.4449 0.0065 151.33); + --base-700: oklch(0.3731 0.0059 150.75); + --base-800: oklch(0.2731 0.0051 150.35); + --base-900: oklch(0.2123 0.0048 151.01); + --base-950: oklch(0.1386 0.0044 150.49); + --base-1000: oklch(0.0909 0.0041 150.95); + + /* ─── Primary scale (phala lime) ─────────────────────────────────── */ + --primary-50: oklch(0.9861 0.0309 118.52); + --primary-100: oklch(0.9676 0.0683 119.72); + --primary-200: oklch(0.9387 0.1289 121.44); + --primary-300: oklch(0.8962 0.1971 123.29); + --primary-400: oklch(0.8421 0.2371 125.02); + --primary-500: oklch(0.7708 0.2308 126.52); + --primary-600: oklch(0.6514 0.1967 127.14); + --primary-700: oklch(0.5343 0.1568 126.91); + --primary-800: oklch(0.4554 0.1246 126.16); + --primary-900: oklch(0.4067 0.1017 125.95); + --primary-950: oklch(0.2752 0.0724 126.79); + --primary-1000: oklch(0.1899 0.0531 127.24); + + /* ─── Brand accent palettes ──────────────────────────────────────── */ + /* Phala Blue (periwinkle) */ + --phala-blue-50: #f0f2ff; + --phala-blue-100: #d5dbf8; + --phala-blue-200: #bfc8f0; + --phala-blue-300: #aabbff; + --phala-blue-400: #8b9fe0; + --phala-blue-500: #6b80cc; + --phala-blue-900: #2d3250; + + /* Phala Purple */ + --phala-purple-50: #f5f0f8; + --phala-purple-100: #e7e1eb; + --phala-purple-200: #d4c0e8; + --phala-purple-300: #b88fd0; + --phala-purple-400: #9b6bbf; + --phala-purple-500: #7e3daf; + --phala-purple-900: #3d2055; + + /* Phala Orange */ + --phala-orange-50: #fff5ec; + --phala-orange-100: #f8e7d5; + --phala-orange-200: #f0cca0; + --phala-orange-300: #f5902c; + --phala-orange-400: #d87a20; + --phala-orange-500: #a07830; + --phala-orange-900: #4a3520; + + /* ─── Semantic tokens (light) ────────────────────────────────────── */ + --background: var(--base-50); + --foreground: var(--base-800); + --card: #ffffff; + --card-foreground: var(--base-800); + --popover: #ffffff; + --popover-foreground: var(--base-800); + --primary: var(--primary-300); + --primary-foreground: #000000; + --secondary: var(--base-200); + --secondary-foreground: var(--base-950); + --muted: var(--base-100); + --muted-foreground: var(--base-600); + --accent: var(--base-100); + --accent-foreground: var(--base-800); + --destructive: oklch(0.577 0.245 27.325); + --border: var(--base-200); + --input: var(--base-300); + --ring: var(--primary-300); + --cream: var(--primary-50); + + /* ─── Typography — families ──────────────────────────────────────── */ + --v3-heading: "ABCArizonaFlare", Georgia, serif; + --v3-body: "ABCDiatype", "Trebuchet MS", Arial, sans-serif; + --v3-ui: "ABCDiatype", "Trebuchet MS", Arial, sans-serif; + --v3-mono: "SuisseIntlMono", "SFMono-Regular", Consolas, monospace; + --display-weight: 600; + + /* ─── Surfaces (used inline across v3 sections) ──────────────────── */ + --surface-page: var(--background); + --surface-card: var(--card); + --surface-marketing: #f7f8f3; + --surface-marketing-cool: #f0f1ec; + --surface-marketing-light: #fbfcf8; + --surface-trust-path: #070908; + --surface-trust-card: #101310; + + /* ─── Borders & radii ────────────────────────────────────────────── */ + --radius: 4px; + --radius-sm: 0; + --radius-md: 2px; + --radius-lg: 4px; + --radius-xl: 8px; + /* Default: every other element is sharp (radius 0). */ + + /* ─── Section rhythm (used across v3 pages) ──────────────────────── */ + --container-max: 1280px; + --container-max-wide: 1440px; + --section-py-default: clamp(48px, 6vw, 64px); + --section-py-large: clamp(64px, 8vw, 96px); + --hero-py: clamp(40px, 5vw, 80px); +} + +.dark { + --background: var(--base-950); + --foreground: var(--base-200); + --card: var(--base-900); + --card-foreground: var(--base-200); + --popover: var(--base-900); + --popover-foreground: var(--base-200); + --primary: var(--primary-300); + --primary-foreground: #000000; + --secondary: var(--base-700); + --secondary-foreground: var(--base-50); + --muted: var(--base-800); + --muted-foreground: var(--base-300); + --accent: var(--base-800); + --accent-foreground: var(--base-200); + --destructive: oklch(0.704 0.191 22.216); + --border: var(--base-800); + --input: var(--base-700); + --ring: var(--primary-300); + --cream: var(--primary-1000); +} + +/* ─── Global icon rule (Phala v3 schematic look) ───────────────────── */ +.lucide { + stroke-width: 1.25; + stroke-linecap: square; + stroke-linejoin: miter; +} diff --git a/docs/icon-design-brief.md b/docs/icon-design-brief.md new file mode 100644 index 00000000..b215ebda --- /dev/null +++ b/docs/icon-design-brief.md @@ -0,0 +1,444 @@ +# Phala v3 Icon Design Brief + +**For:** Claude Design (or human illustrator) producing the unified icon batch +**Site:** phala.network — v3 design system +**Owner:** Marvin +**Date:** 2026-05-05 + +--- + +## 1. Brand foundations (the v3 design tokens already in the codebase) + +### 1.1 Colors (OKLCH, defined in `src/app/theme/colors.css`) + +#### Primary scale — Phala lime +| Token | Value (OKLCH) | Hex equiv | Use | +|---|---|---|---| +| `--primary-300` | `oklch(0.8962 0.1971 123.29)` | `#c5ff2e` | Brand accent / "ours" | +| `--primary-400` | `oklch(0.8421 0.2371 125.02)` | `#bef631` | Heightened accent | +| `--primary-500` | `oklch(0.7708 0.2308 126.52)` | `#a3d124` | Body-on-primary | + +#### Base scale — paper / charcoal (greenish-neutral) +| Token | Hex equiv | Use | +|---|---|---| +| `--base-50` | `#f7f8f3` | Cream paper | +| `--base-100` | `#fbfcf8` | Card paper | +| `--base-300` | `#d8d6cc` | Muted divider | +| `--base-600` | `#6b6d67` | Muted-foreground | +| `--base-800` | `#2d2f29` | Foreground (primary text) | +| `--base-1000` | `#090b0a` | Trust black | + +#### Phala blue (periwinkle) — system "secured" / "data" tone +| Token | Hex | +|---|---| +| `--phala-blue-300` | `#aabbff` | +| `--phala-blue-400` | `#8b9fe0` | +| `--phala-blue-500` | `#6b80cc` | + +#### Phala orange — output / receipt tone +| Token | Hex | +|---|---| +| `--phala-orange-300` | `#f5902c` | +| `--phala-orange-400` | `#d87a20` | + +#### Phala purple — model / weight tone +| Token | Hex | +|---|---| +| `--phala-purple-300` | `#b88fd0` | +| `--phala-purple-400` | `#9b6bbf` | + +#### Semantic colors +| Concept | Token | Hex | +|---|---|---| +| verified / attested | emerald-600 | `#059669` | +| denied / revoked | red-500 | `#ef4444` | +| sealed / data | phala-blue-500 | `#6b80cc` | +| signed / output | phala-orange-300 / amber-500 | `#f5902c` | +| brand / trust | primary-300 | `#c5ff2e` | + +### 1.2 Typography + +| Family | CSS var | Used for | +|---|---|---| +| **ABCArizonaFlare** (serif display) | `--v3-heading` | Headlines, big numbers | +| **ABCDiatype** (sans body) | `--v3-body` / `--v3-ui` | All body copy, buttons, labels | +| **SuisseIntlMono** (mono) | `--v3-mono` | Kickers, code, status pills, hash labels | + +Icons should pair with these — none of the icons should compete with the type. Treat icons as "punctuation," not as primary visual elements. + +### 1.3 Geometry + +- **Border radius:** `0` (sharp corners everywhere on solution pages). Icon boxes/frames must follow this. +- **Strokes:** site uses 1px and 1.5px hairline borders almost universally. +- **Shadows:** soft `0_8-22px_rgba(0,0,0,0.12-0.18)` drop shadows. Icons should not have built-in shadows; rely on container. +- **Grid:** site is built on 4px / 8px spacing grid. Icons must align to it. + +--- + +## 2. Icon design language + +### 2.1 Visual rules (must hold across the whole batch) + +1. **Frame size:** `24 × 24` pixel canvas (artboard). +2. **Stroke weight:** `1.5px` for outlines. No thicker strokes anywhere. Filled marks may have `0.75px` inner detail strokes. +3. **Stroke caps:** `square` (no round caps). No round joins. +4. **Sharp corners only.** No rounded box corners. No tapered ends. The site is hard-edged. +5. **No perspective / 3-D.** Icons are flat orthographic. No isometric, no drop shadows. +6. **No gradients in static icons.** Single solid color (`currentColor` in SVG). Animated icons may transition between tokens but must hold solid at any frame. +7. **Optical alignment** at 24 px. Reads at 16 px without losing the silhouette. +8. **Negative space:** ≥ 2 px padding from artboard edge to outermost ink. Most icons should occupy a 20×20 inner box. +9. **Stroke vs. fill mix:** prefer outlined glyphs. Use solid fill only for emphasis points (e.g., "filled dot = signed; empty dot = pending" in `multi-sig`). +10. **Square / box drawing aesthetic:** the site already leans on box-drawing characters and rectangular tiles. Icons should echo that — rectangles, right angles, modular grids preferred over organic blobs. + +### 2.2 What to avoid + +- ❌ Gradients, glows, soft shadows +- ❌ Rounded corners (the site is sharp) +- ❌ Gradient meshes, translucent overlays +- ❌ Decorative flourishes (the site is utilitarian) +- ❌ Anthropomorphic faces / characters +- ❌ Photo-realism +- ❌ Color outside the listed tokens + +### 2.3 Reference visual feel + +- **Bauhaus modular** — strict grid, primary forms (square / circle / triangle), no embellishment +- **Schematic / diagrammatic** — like a circuit symbol or industrial-control diagram +- **CLI / terminal lineage** — many of these icons live next to mono text, so they should feel like glyphs you could imagine being drawn with `─ │ ┌ ┐ ▓ ░` + +Closest mood references: SuisseInt typography specimens, the Telos Health Atlas, Nothing OS dot-matrix marks, classic Otl Aicher transport pictograms. + +--- + +## 3. Sizing scale (the canonical 6 sizes) + +Currently the site has 11 different icon sizes scattered across components. **Snap everything to these 6 only.** + +| Token | Pixel | When to use | +|---|---:|---| +| `xs` | 12 | Inline glyph in body text, status pill prefix, mono kicker prefix | +| `sm` | 16 | Mode chip headers, table cell glyphs, action log Tool column | +| `md` | 20 | Default — navbar dropdown items, button glyphs, list bullets | +| `lg` | 24 | Section eyebrows, major card labels, footer column heads | +| `xl` | 32 | `MajorFeature` 2-up card icon, hero CTA glyph | +| `2xl` | 48 | Hero sub-illustrations, big proof card glyph | + +Each icon is designed once at 24×24 (the `lg` size) and scales to all others — must read at 12px without becoming muddy. + +--- + +## 4. Color application rules + +| Surface | Color treatment | +|---|---| +| Inline next to body text | `currentColor` — inherits | +| `StatusPill: live` | `text-emerald-600` | +| `StatusPill: beta` | `text-phala-blue-500` | +| `StatusPill: forming` | `text-amber-600` | +| `StatusPill: ready` | `text-emerald-600` | +| `StatusPill: busy` | `text-phala-orange-300` | +| `StatusPill: denied` | `text-red-500` | +| Brand highlight (Phala-only feature) | `text-primary` (lime) | +| Trust accent (sealed / data) | `text-phala-blue-500` | +| Output / receipt accent | `text-phala-orange-300` | +| Muted | `text-muted-foreground` | +| On dark trust panel (`bg-base-1000`) | `text-primary` for highlight, `text-base-50` for body | + +**Rule:** every static icon must be designed in pure `currentColor` (single-color SVG, no fills). Color is applied via the parent's `color:` property at the use site. + +--- + +## 5. File output specs + +### 5.1 SVG static icons + +```xml + + +``` + +- File name pattern: `kebab-case.svg` — e.g., `vault.svg`, `compose-hash.svg`, `multi-sig.svg` +- No inline `style` attributes +- No `class` attributes (they're applied at consumer site) +- Single root ``, no wrappers +- Optimize with SVGO (`removeViewBox: false`, `removeDimensions: false`) + +### 5.2 Animated icons (Lottie OR ASCII frames) + +Two formats accepted: + +**Format A — Lottie JSON** (for content surfaces, `MajorFeature` cards, hero sub-illustrations): +- 24×24 native, exportable from After Effects or Lottielab +- Loop length: 2.0 s ± 0.4 s +- Easing: `cubic-bezier(0.4, 0, 0.2, 1)` (ease-out-quart) +- ≤ 4 KB JSON each, no raster +- Single solid color via `currentColor`-equivalent (export as a tinted shape layer) +- Pause on `prefers-reduced-motion` + +**Format B — ASCII frame array** (for mono surfaces — terminals, action logs, mode chips): +- Output as a JSON file: `[{"frame": "●··", "duration": 240}, {"frame": "·●·", "duration": 240}, ...]` +- Each frame is a fixed-width string (3 / 4 / 5 / 6 chars wide depending on glyph) +- Frame duration in milliseconds +- Total loop ~1.5–2.5 s + +### 5.3 Naming convention + +``` +public/glyphs/ +├── static/ +│ ├── vault.svg +│ ├── compose-hash.svg +│ ├── multi-sig.svg +│ └── ... +├── animated/ +│ ├── multi-sig.lottie.json +│ ├── ra-tls.lottie.json +│ ├── status-live.ascii.json +│ └── ... +└── menu/ + ├── confidential-vm.svg + ├── confidential-ai-models.svg + └── ... +``` + +--- + +## 6. Static icon batch — 58 glyphs to design + +All at 24×24, single-color (`currentColor`), 1.5px stroke unless marked. + +### 6.1 Architecture & primitives (8) + +| ID | Brief | Visual cue | +|---|---|---| +| `vault` | Sealed data container | Rectangle box with shaded interior + lock dot at top-center | +| `compose-hash` | Hash-as-identity | `0x` prefix glyph fused with 6 dots/dashes representing hash bytes | +| `attested-launch` | Boot + TDX quote | Square CVM block with up-arrow "boot" + a dotted ring around quote stamp | +| `key-derive` | HKDF flow | Key glyph → arrow → smaller key (parent → derived) | +| `ra-tls` | Mutual handshake | Two rectangles facing each other with a `⇄` certificate exchange between | +| `multi-sig` | Co-approval | Three filled circles + one open circle in a row, with a tally bracket above | +| `kill-switch` | On-chain revoke | Rectangle with a strong diagonal X stamped over it; chain-link below | +| `signed-receipt` | Sign-RPC envelope | Document outline with a wax-seal-style 4-pointed star at corner | + +### 6.2 Outputs / artifacts (4) + +| ID | Brief | Visual cue | +|---|---|---| +| `signed-manifest` | Training manifest | Stacked-document glyph with a hash row + seal mark | +| `dp-aggregate` | Differential-privacy aggregate output | Sigma symbol over a cluster of dots, with a single dot exiting through a slit | +| `action-log` | Tamper-evident log entry | Horizontal lines (log rows) with a tiny seal at right margin | +| `sign-rpc` | Generic signing call | Pen tip touching a square, with a small chain link below | + +### 6.3 Training-stack phases (7) — for `PhasePill` + +These are tighter than 24×24; design at 16×16 native, with a 24×24 viewBox padded. + +| ID | Brief | Visual cue | +|---|---|---| +| `phase-sft` | Supervised fine-tuning | Prompt arrow → response (input → output) | +| `phase-dpo` | Preference optimization | Two thumbs (one up, one down) | +| `phase-rlhf` | Reward + PPO | Loop arrow with a `+/-` reward node | +| `phase-lora` | Low-rank adapter | Small block on a larger block (adapter on base) | +| `phase-qlora` | 4-bit QLoRA | LoRA block with `4` bit marks | +| `phase-continued-pt` | Continued pre-training | Stream of tokens flowing into a cylinder | +| `phase-multimodal` | Vision + text | Image rectangle + text rectangle merged | + +### 6.4 Status states (6) — for `StatusPill`, both static and as live-pulse animation + +| ID | Brief | Visual cue | +|---|---|---| +| `status-live` | Running, healthy | Filled circle with a faint pulse ring around it | +| `status-beta` | In-test | Half-filled circle (vertical division) | +| `status-forming` | Pre-launch | Dashed/dotted circle outline | +| `status-ready` | Ready, not running | Solid checkmark in a square | +| `status-busy` | In-use, capacity-bound | Two arrows in a tight rotation | +| `status-denied` | Denied / revoked | Filled circle with a horizontal bar through it | + +### 6.5 Compliance badges (6) — for compliance strips + +Stylized as 24×24 hexagonal seals (not photographic logos). They are *abstractions of* the standards, not the official marks. + +| ID | Brief | +|---|---| +| `compliance-hipaa` | Hexagon with a medical cross inside | +| `compliance-gdpr` | Hexagon with EU-flag stars dot pattern | +| `compliance-pci` | Hexagon with a card chip silhouette | +| `compliance-soc2` | Hexagon with a checkmark + audit trail line | +| `compliance-iso-27001` | Hexagon with a globe + lock | +| `compliance-ffiec` | Hexagon with a balance/scale | + +### 6.6 Hardware-backed concepts (4) — abstract, not vendor logos + +| ID | Brief | Visual cue | +|---|---|---| +| `tdx-cvm` | Confidential VM block | Square outline + interior "memory rows" + dotted border indicating isolation | +| `gpu-confidential` | GPU in CC mode | Stylized GPU silhouette (rectangular die + outputs) with lock overlay top-right | +| `enclave` | Encrypted memory | Chip silhouette with a key inside | +| `attested-mem` | Memory + quote | 4×4 dot grid with a small seal stamp at corner | + +### 6.7 Agent surfaces (7) — left rail of agents page categories + +| ID | Brief | +|---|---| +| `cat-personal` | Phone outline with a small "you" silhouette | +| `cat-coding` | Terminal `>_` prompt in a rectangle | +| `cat-security` | Shield + on-chain revoke combined | +| `cat-financial` | Wallet outline with a coin | +| `cat-social` | Broadcast tower with two ripples | +| `cat-memory` | Stack of three sealed shards (small rectangles) | +| `cat-mcp` | Plug + socket icon (MCP connector) | + +### 6.8 Tool-class glyphs (5) — for action-log Tool column + +| ID | Visual cue | +|---|---| +| `tool-read` | Document with a read-arrow exiting | +| `tool-write` | Document with a pen tip entering | +| `tool-sign` | Document with a wax-seal mark | +| `tool-search` | Document with a magnifier overlapping | +| `tool-delete` | Document with a strikethrough | + +### 6.9 Trust inset glyphs (3) — for "0 by construction" rows + +These are intentional **negation** marks. Design as the positive icon with a clear strikethrough. + +| ID | Visual cue | +|---|---| +| `inset-no-oauth-on-host` | Key glyph with diagonal strike | +| `inset-no-plaintext` | Memory grid with strike | +| `inset-no-kms-access` | Two-people glyph with strike | + +### 6.10 Reusable arrow / connector glyphs (3) + +| ID | Visual cue | +|---|---| +| `compute-to-data` | Arrow flowing INTO a vault (data page motif) | +| `data-stays` | Vault glyph with anchor underneath | +| `signed-out` | Vault glyph with a seal-stamped output arrow exiting | + +### 6.11 Menu / navbar replacements (5) + +The navbar currently uses generic lucides for the **product family** that should become domain-specific glyphs. (Other navbar items keep their lucides — these are the only swaps.) + +| Current item | Current lucide | Replace with new glyph | +|---|---|---| +| `Confidential VM` | `Server` | `confidential-vm` (custom: dotted-border CVM tile) | +| `Confidential AI Models` | `Brain` | `confidential-ai-models` (custom: brain-in-a-box, filled) | +| `GPU TEE` | `Gpu` | `gpu-tee` (custom: GPU silhouette + dotted enclave outline) | +| `dStack` | `Layers` | `dstack` (custom: 3 stacked tiles with bottom one in primary lime) | +| `Trust Center` | `ShieldCheck` | `trust-center` (custom: shield with on-chain dot pattern inside) | + +### 6.12 Other (5) + +| ID | Brief | +|---|---| +| `attested` | Single check-stamped seal mark — used in section eyebrows | +| `verified-offline` | Document with a check + "no-cloud" cross above | +| `cross-chain` | Two interlocked chain links | +| `oauth-token` | Token glyph with rotating refresh ring | +| `rate-limit` | Gauge / dial glyph | + +--- + +## 7. Animated icon specs (12 total) + +These are the icons that benefit most from motion. **Each animation must be derived from the matching static icon — same shapes, just transitioning between states.** + +| ID | Source state | End state | Notes | +|---|---|---|---| +| `multi-sig` | `○○○○` (no signers) | `●●●●` (quorum) | Step through one filled dot at a time, ~280ms each, then hold quorum 800ms | +| `ra-tls` | Two boxes apart | Two boxes joined by a sealed line | Box 1 flickers a pulse first, then box 2 receives, then line locks. ~1800ms loop | +| `key-derive` | One key glyph | Key + derived key (smaller, child) | Parent emits a particle that morphs into child key | +| `attested-launch` | Empty CVM | CVM with quote stamp | CVM "fills" then stamp drops in from above | +| `revoke-onchain` | Live compose-hash | Strikethrough + denied | Strike sweeps left to right ~600ms, then the underlying glyph fades to muted | +| `compute-to-data` | Arrow at left | Arrow inside vault | Arrow travels right into vault, vault closes | +| `dp-aggregate` | Cluster of dots | Single dot exiting through slit | Dots shuffle/merge then one exits, ~1600ms | +| `signed-receipt` | Document, no seal | Document with seal + chain | Seal drops, chain reveals beneath | +| `status-live` | (single state) | Heartbeat pulse | Two-frame pulse: opacity 0.6 → 1 → 0.6, 1.4s loop | +| `status-busy` | (single state) | Rotating arrows | 360° rotation over 1.6s, linear | +| `status-forming` | (single state) | Dotted circle rotation | Dashes rotate around the circle, 2.4s linear | +| `kill-switch` | Compose-hash glyph | Strikethrough version | Diagonal strike paints in over 500ms | + +### Animation timing standards + +- **Loop length:** 1.5–2.5 s +- **Easing:** `cubic-bezier(0.4, 0, 0.2, 1)` (ease-out-quart) for content motion; `linear` for spinners +- **Stagger between elements:** 80–120 ms +- **Pause on `prefers-reduced-motion`:** show end-state static frame only + +--- + +## 8. Navbar menu icon swap-map + +Current navbar icons use generic `lucide-react` shapes. The brief in §6.11 lists 5 to replace. **All other navbar items keep their lucide icons unchanged** — these are content-shape icons, not Phala-specific concepts, so they don't need custom design. + +For reference, the navbar items NOT being replaced (kept as lucide): +`H100/H200/B200` (`Gpu`), `vs AWS Nitro / vs GCP / vs Tinfoil` (`ChartBar`), `Private AI Data` (`Lock`), `Private AI Inference` (`Brain`), `Private Training` (`Sparkles`), `AI Agents` (`Bot`), `Financial AI` (`ChartBar`), `Legal AI` (`Briefcase`), `Healthcare AI` (`ShieldCheck`), `AI SaaS` (`Zap`), `Decentralized AI` (`Globe`), `Documentation` (`Book`), `Learn` (`BookOpen`), `Guides / Templates` (`FileCode`), `Service Status` (`ChartBar`), `Startup Program` (`Rocket`), `Blog` (`Newspaper`), `Compliance` (`ShieldCheck`), `Ecosystem/Partnerships` (`Users`), `Ambassador Program` (`Award`). + +Note: in a follow-up phase we may swap `Private AI Data → vault`, `Private AI Inference → enclave`, `Private Training → key-derive`, `AI Agents → category-mcp` (or similar), once the domain glyph batch is delivered. **For this brief, only the 5 product-family swaps in §6.11 are in scope.** + +--- + +## 9. Deliverable structure + +When the batch is delivered, place files in: + +``` +public/glyphs/ +├── static/ ← all 58 static SVGs from §6 +├── animated/ ← all 12 animated artifacts from §7 +│ (.lottie.json or .ascii.json per item) +└── menu/ ← the 5 navbar replacements from §6.11 + +src/components/icons/ +├── DomainGlyph.tsx ← +├── PhasePillIcon.tsx ← maps PhasePill id → glyph +├── StatusPillIcon.tsx ← maps StatusPill id → glyph (with anim) +└── registry.ts ← single map: { vault: '/glyphs/static/vault.svg', ... } +``` + +### Per-icon output + +For each glyph, deliver: +1. The `.svg` (or `.lottie.json`) at native 24×24 +2. A 1× PNG preview at 64×64 (for design review only) +3. (Optional) a one-line note on what it depicts, in case naming becomes ambiguous + +### Final review pass + +Before delivery, do a **shrink test**: paste all icons at 16 × 16 in a row on a `bg-base-50` paper background. If two icons read as the same silhouette at that size, redesign one of them. The icons must be mutually-distinguishable at thumbnail scale. + +--- + +## 10. References & inspiration + +- The site's own **GPU comparison columns** in `/gpu-tee/sections/comparison.tsx` — note the bar/box vocabulary +- The **brain-assembly animation** on `/solutions/private-training` — note how everything is a 14×9 pixel-art grid; icons should feel like glyphs from that same grid +- The **mockup chrome** (Mac terminal, iPhone, Browser frames) — the icon language must be consistent with the chrome these mockups draw with +- The page screenshots in `/Users/marvin/website-nextjs/docs/plans/` for visual context + +--- + +## 11. Hand-off checklist + +- [ ] All 58 static SVGs at 24×24 +- [ ] All 12 animations as Lottie JSON or ASCII-frame JSON +- [ ] All 5 navbar replacements +- [ ] Shrink-test passed (icons readable at 16 px, distinct from each other) +- [ ] All files use `currentColor` only +- [ ] Per-token color demo (lime, phala-blue, emerald, red) on each icon to confirm tinting works +- [ ] `prefers-reduced-motion` static fallback for every animation + +Total: **75 deliverables** (58 static + 12 animated + 5 menu). diff --git a/docs/plans/ai-solutions-redesign-issues.md b/docs/plans/ai-solutions-redesign-issues.md new file mode 100644 index 00000000..1f9f0e55 --- /dev/null +++ b/docs/plans/ai-solutions-redesign-issues.md @@ -0,0 +1,375 @@ +# AI Solutions Pages — Redesign Issue List + +Created: 2026-05-03 +Survey screenshots: `/tmp/redesign-survey/` (5 solution pages + 1 reference) +Reference design: `/confidential-vm`, `/confidential-ai-models`, `/gpu-tee`, `/` + +## Scope + +Five solution pages live under `src/app/(main)/(solutions)/solutions/`: + +1. `private-ai-inference` +2. `confidential-training` *(currently throws a runtime error — see issue T-1)* +3. `fine-tuned-models` +4. `ai-agents` +5. `private-ai-data` + +The new design tokens (Exa typography, DNA proof rails, sharp `border border-border bg-card` panels, lime green accent, mono labels) are already in production on the home/CVM/models/GPU pages. The solutions pages still run on V2 components (Hero225/Hero74/Hero216/Hero219/Hero230, Feature206/282/284/22/44/64/76/245/251/280/95, Codeexample1/3/5/5-finetune, Casestudies3/1-agents, Compliance5, Cta4, Faq14, SolutionsCTA). + +The cards I added (`HowItWorksSection` + per-solution flow card) are the only V3-aligned blocks on these pages today, and they look out of place sandwiched between V2 components. + +## Executive Summary + +| Page | Status | Severity | +|---|---|---| +| confidential-training | **Crashes on load** (Globe/WebGL in Hero216) | P0 | +| private-ai-inference | Works but visually V2 (orbiting-circles hero, gradient feature cards) | P1 | +| fine-tuned-models | Works but visually V2 (Hero74 pink/orange gradient + 3D box) | P1 | +| ai-agents | Works but visually V2 (Hero230 purple-orange agent character art) | P1 | +| private-ai-data | Works but visually V2 (Hero219 pink/orange gradient + marketing cards) | P1 | + +## Global Issues (apply to all 5 pages) + +### G-1. Hero pattern doesn't match +**What**: each page uses a unique decorative hero (orbiting circles, 3D boxes, character art, globe) on top of pink/orange/purple gradient backgrounds. +**Target**: `/confidential-vm`-style hero — `bg-[#f7f8f3]`, two-column grid, editorial serif headline (clamp 38–76px), supporting line, three-button CTA group (command + docs + sales), platform/integration strip, single Lottie or static product visual on the right inside `border border-border bg-[#f7f8f3]` with subtle grid. +**Action**: replace each route's existing `Hero*` import with a route-local `hero.tsx` that follows the CVM pattern. + +### G-2. CTAs aren't command-first +**What**: all five pages bottom out at "Deploy on Phala" / "Talk to Sales" buttons with an arrow icon. No CLI/API copy affordance. +**Target**: `CopyCommandButton` (the `$ phala …` mono-pill from `confidential-vm/sections/shared`) as the primary CTA, "Read X docs" as secondary, "Talk to sales" as text-link tertiary. +**Standard CTA labels per page**: +- Inference: `Copy OpenAI-compatible request` · `Read inference docs` · `Talk to experts` +- Fine-tuning: `Copy fine-tune command` · `Read fine-tune docs` · `Talk to sales` +- Training: `Copy training launch` · `Read training docs` · `Talk to sales` +- Agents: `Copy agent deploy` · `Read agent docs` · `Talk to sales` +- Data: `Copy compute-to-data recipe` · `Read data docs` · `Talk to sales` + +### G-3. Feature blocks use V2 marketing pattern +**What**: Feature206 (Why-it-matters), Feature282 (encryption showcase), Feature245/251 (deeper feature), Feature280/284 (use cases) all use rounded panels, decorative images, generic copy. +**Target**: editorial section pattern from `confidential-vm/sections/benefits.tsx`: +- Section title in `cvm-section-title` (clamp 30–46px) +- 2-col grid: title left, lead paragraph right +- Below: `grid gap-px border border-border bg-border` of square benefit cells +- Numbered (`font-mono text-primary`), short claim, 2-line body, optional small icon +- Black/lime trust panels for proof-heavy content; off-white for everything else +**Action**: per page, build 2–3 route-local section files (`why.tsx`, `architecture.tsx`, `code.tsx`, etc.) and retire the imported V2 features. + +### G-4. Code examples should be the hero artifact +**What**: `Codeexample1/3/5/5-finetune` are tucked mid-page in styled cards; the page never makes the API call the headline visual. +**Target**: a `CommandPanel` (terminal-style, square border, black fill, mono text, copy affordance) prominently in the hero or right after it — per the design plan: "Code and proof are art assets". Real cURL / TypeScript / Python tabs with one tab visible at a time, clean prompt characters. +**Action**: extract a reusable `` to `src/components/product/` and use it on all five pages. + +### G-5. Case studies / compliance / FAQ wrappers are V2 +**What**: Casestudies3 and Casestudies1Agents render large image hero + side cards; Compliance5 is a colored badge grid; Faq14 uses rounded cards. +**Target**: thinner editorial bands. +- Case studies: one featured row + 2-up cells, square borders, no hero image stretch. +- Compliance: a single horizontal `inline-flex h-11 items-center gap-2 border border-border` strip of badges (matches CVM platform strip style). +- FAQ: `
` style, square dividers, no card chrome. +**Action**: build ``, ``, `` shared components, retire the V2 imports. + +### G-6. Animation idiom is decorative, not explanatory +**What**: the existing motion (orbiting circles, globe, character art) doesn't explain the product mechanism. +**Target**: each hero should have ONE motion that explains the recipe-specific flow (see per-page motion ideas below). Lottie aspect ratio respected per layout. Reduced-motion fallback. + +### G-7. Solution pages don't lead with the dstack mechanism +**What**: Phala-cloud-marketing copy ("zero trust", "compliance grade", "enterprise") leads. The dstack technical primitives (compose-hash, RA-TLS, dstack-kms re-derivation, on-chain DstackApp.sol, signed receipt, Sign RPC manifest) appear only inside my `HowItWorksSection` card. +**Target**: the section above the fold should already reference at least one technical primitive — e.g., the hero supporting line should include "OpenAI-compatible API · TDX + H100 · signed receipt". + +### G-8. SEO content is fine but page architecture isn't V3 +**What**: SEO metadata / keywords are reasonable on all 5 pages. The H1/H2 tree is okay. But the "thin route-local section" composition rule (`page.tsx` is composition only; sections live next to the page) is not followed — every page imports legacy `src/components/solutions/*` blobs. +**Target**: per-route `sections/` folders with `hero.tsx`, `why.tsx`, `architecture.tsx`, `code.tsx`, `evidence.tsx`, `faq.tsx`, `cta.tsx`. The legacy imports retire as each page is migrated. + +## Per-Page Issues + +### Page 1: `/solutions/private-ai-inference` + +**Components in use**: `Hero225`, `Feature206`, `Feature282`, `HowItWorksSection`+`PrivateInferenceCard`, `ModelsList`, `SuccessStoriesSection`, `UnifiedInterfacePhala`, `ApiCodeExamplesPhala`, `SolutionsPhala`, `Casestudies3`, `Compliance5`, `SolutionsCTA`, `Faq14`, `Cta4`. + +**P-1.1** Hero225 is OrbitingCircles of vendor logos centered on a white bg. No serif headline, no command CTA, no dstack mention. — **Replace with route-local `hero.tsx` modeled on `confidential-vm/sections/hero.tsx`**: editorial headline ("Serve LLMs without exposing prompts or weights"), supporting line ("OpenAI-compatible API. Two-hop RA-TLS. Signed receipts."), `CopyCommandButton` ($ curl https://api.redpill.ai/v1/chat/completions …), provider strip (OpenAI-compat · vLLM · TDX + H100), Lottie of `ModelApiFlow` on the right. + +**P-1.2** Feature282 ("Confidential Serving / Zero-Trust Inference / OpenAI-Compatible API") is a marketing 2-col card with image and bullet list. — **Replace with route-local `architecture.tsx`**: editorial title left + lead right, then 4-cell sharp grid (Two-hop RA-TLS · Combined CPU+GPU TEE · Signed receipt · On-chain no-log compose-hash), each cell mono numbered. + +**P-1.3** `UnifiedInterfacePhala`, `ApiCodeExamplesPhala`, `SolutionsPhala` are three separate marketing cards. — **Consolidate**: the API examples become a `CommandPanel` (cURL / TS / Python tabs); the "unified interface" claim becomes one line in the hero subhead; "Phala solutions" pillar grid retires. + +**P-1.4** `ModelsList` works fine (it's already a clean grid from `/confidential-ai-models`) — **Keep, but render below the new `architecture.tsx`** so the user sees the API + flow first, models second. + +**P-1.5** `Casestudies3` shows OODA AI / NEAR AI / OpenRouter — keep partners, retire the wrapper. **Replace with route-local `evidence.tsx`** in CVM evidence-row style. + +**P-1.6** `Compliance5` is unchanged across all pages. — **One shared `ComplianceStrip` component** consumed by every solution page. + +**P-1.7** `Faq14` and `Cta4` both work but use V2 chrome. — **Replace with `FaqList` + a single `FinalCta` that opens with the same `CopyCommandButton`**. + +**Motion idea (hero)**: `ModelApiFlow` Lottie — encrypted prompt particle leaves client → enters gateway CVM → splits into 3 model CVMs → particle returns + signed-receipt token emerges with green proof pulse. + +**SEO**: keep current keywords (private AI inference, confidential LLM API, secure AI predictions, encrypted inference, zero trust AI). Add to body: "TDX + H100", "RA-TLS", "OpenAI-compatible", "no-log compose-hash", "vLLM". + +--- + +### Page 2: `/solutions/confidential-training` 🔥 **P0 BLOCKER** + +**Components in use**: `Hero216`, `Feature206`, `Feature95Training`, `HowItWorksSection`+`PrivateTrainingCard`, `Feature251Training`, `Codeexample3`, `Compliance5`, `SolutionsCTA`, `Faq14`, `Cta4`. + +**T-1** **Page crashes on load**: `TypeError: Cannot read properties of null (reading 'enable')` in `Globe.useEffect` at `src/components/magicui/globe.tsx:87`, called from `Hero216.tsx:31`. The Cobe globe initializes before WebGL context is ready (or fails when GL ctx returns null in some envs). — **Block**. Either fix the globe (null-guard `gl.enable(...)`) OR replace Hero216 with a route-local `hero.tsx` that doesn't render a globe. Recommend the latter, since we're redesigning the hero anyway. + +**T-2** Hero216 design is a globe-centric "global confidential training" hero — off-target for the dstack story. — **Replace** with editorial training hero: H1 "Train on regulated data without giving it up", supporting line "Sealed datasets · TDX + H100 training CVM · signed Training Manifest", `CopyCommandButton` ($ phala train …), Lottie `SealedTrainingFlow` on right. + +**T-3** Feature95Training and Feature251Training are V2 feature blocks — **Replace** with `architecture.tsx` (4-cell grid: Multi-owner sealing · Training CVM attestation · Co-approval gate · Signed manifest) and `provenance.tsx` (deep-dive on the manifest). + +**T-4** `Codeexample3` ("Deploy Multi-GPU Training" code panel) — repurpose as a `CommandPanel` with PyTorch + Unsloth tabs, sealed-disk env vars, and `dstack quote` invocation. + +**Motion idea (hero)**: `SealedTrainingFlow` — two encrypted dataset chips slide into a TDX+GPU CVM, training-loop dots cycle inside the boundary, signed manifest token emerges right with green pulse. + +**SEO**: keep keywords (confidential AI training, private model training, safe fine-tuning, HIPAA AI training). Add: "Training Manifest", "Sign RPC", "multi-owner sealing", "compose-hash". + +--- + +### Page 3: `/solutions/fine-tuned-models` + +**Components in use**: `Hero74`, `Feature206`, `Feature245Finetune`, `HowItWorksSection`+`ModelWeightsCard`, `Codeexample5Finetune`, `Casestudies3`, `Compliance5`, `SolutionsCTA`, `Faq14`, `Cta4`. + +**F-1** Hero74 is a pink/orange gradient hero with a 3D-box visual — completely off-system. **Replace** with `hero.tsx` editorial: H1 "Fine-tune on private data. Keep the weights yours.", supporting line "LoRA + Unsloth · TDX + H100 · weights sealed to your compose-hash", `CopyCommandButton` ($ phala fine-tune …), Lottie `LoRASealFlow` right. + +**F-2** Feature245Finetune is a styled marketing block — **Replace** with `architecture.tsx`: 4-cell grid (Reproducible build · Recipe-bound seal · Attestation-gated re-derive · On-chain revocation). + +**F-3** `Codeexample5Finetune` exists — **Repurpose** as a `CommandPanel` with Python (Unsloth) + JSON-config tabs, then a small `AttestationProofPanel` showing the resulting attested artifact. + +**F-4** Casestudies3 (Medical / SaaS Sales / HR) — keep evidence, retire wrapper, use `EvidenceRow`. + +**Motion idea (hero)**: `LoRASealFlow` — base model + LoRA delta enter a TDX-GPU CVM, sealing animation produces a fine-tuned model artifact with a tiny on-chain compose-hash badge. Green proof pulse. + +**SEO**: keep keywords (private fine tune, customize model data, safe AI tuning, on prem fine-tuning, secure data AI). Add: "LoRA", "Unsloth", "QLoRA", "weight sealing", "BYOVE revocation". + +--- + +### Page 4: `/solutions/ai-agents` + +**Components in use**: `Hero230`, `Feature76Agents`, `HowItWorksSection`+`AIAgentsCard`, `Feature3Frameworks`, `Feature64`, `Feature22`, `Feature44`, `Casestudies1Agents`, `Feature206`, `Compliance5`, `AIAgentsFAQ`, `SolutionsCTA`. + +**A-1** Hero230 features a purple/orange gradient with a 3D agent character ("ELIZA AI"-style). Off-system AND off-brand for a confidential-compute story. **Replace** with `hero.tsx` editorial: H1 "Confidential AI Agents · scopes that change requires a new build", supporting line "Mutual RA-TLS between agent CVMs · sealed credentials · signed action log", `CopyCommandButton` ($ phala agent deploy …), Lottie `AgentSandboxFlow` right. + +**A-2** Feature76Agents, Feature3Frameworks, Feature64, Feature22, Feature44 — five separate V2 feature cards stacked vertically. **Consolidate** into: +- `architecture.tsx` (5-cell grid: Attested launch · Sealed credentials · Mutual RA-TLS · Compose-hash IS scope · Signed action log) +- `frameworks.tsx` (LangChain / Vercel AI / OpenAI Agents / Eliza … as a sharp `border border-border bg-card` chip strip, mono labeled) + +**A-3** Casestudies1Agents (Eliza, autonomous agents, finance agents) — keep evidence, retire wrapper. + +**A-4** `AIAgentsFAQ` is its own custom FAQ — fold into the shared `FaqList`. + +**Motion idea (hero)**: `AgentSandboxFlow` — agent CVM gets a task, briefly handshakes with a delegate CVM (RA-TLS lock icon), calls an external tool (drawn outside the trust boundary), emits a signed action log entry. Two agent CVMs side by side with mutual-attestation pulse on the link. + +**SEO**: keep keywords (private AI agents, payment AI agents, autonomous agents, TEE agents, private LangChain). Add: "mutual RA-TLS", "compose-hash scope", "Sign RPC action log", "outbound tool boundary". + +--- + +### Page 5: `/solutions/private-ai-data` + +**Components in use**: `Hero219`, `Feature206`, `Feature282`, `HowItWorksSection`+`PrivateAIDataCard`, `Codeexample5`, `Feature284`, `Feature280`, `Casestudies3`, `Codeexample1`, `Compliance5`, `Faq14`, `SolutionsCTA`, `Cta4`. Plus a `content.ts` data file. + +**D-1** Hero219 is a pink/orange gradient + marketing image — **Replace** with `hero.tsx` editorial: H1 "Compute travels. Data stays.", supporting line "Sealed datasets · multi-owner approval on-chain · only the agreed aggregate leaves", `CopyCommandButton` ($ phala data run …), Lottie `ComputeToDataFlow` right. + +**D-2** Feature282 reused here for "Encryption Showcase" — **Replace** with `architecture.tsx`: 5-cell grid (Sealing at source · Compute-to-data · Multi-owner co-approval · Sealed computation · Signed aggregate + revocation). + +**D-3** Feature284 ("use cases") + Feature280 ("additional use cases") — two redundant marketing blocks. **Consolidate** into a single `usecases.tsx` (3-up sharp cell grid: Healthcare / Finance / Cross-org analytics, each with a brief recipe). + +**D-4** `Codeexample1` + `Codeexample5` — two separate code blocks. **Consolidate** to one `CommandPanel` with shell / Python / TypeScript tabs. + +**D-5** `content.ts` exists with structured copy — **Keep** as the source of truth for copy; the new sections consume from it. + +**Motion idea (hero)**: `ComputeToDataFlow` — two sealed dataset blocks on the left stay put, a small "Analysis CVM" image arrives from the right, lands between them, runs briefly, and a tiny aggregate token leaves toward the analyst. Green pulse on multi-sig contract below. + +**SEO**: keep keywords (private AI data processing, confidential data analytics, encrypted AI data, GDPR AI). Add: "compute-to-data", "DstackApp multi-sig", "sealed aggregate", "owner co-approval". + +--- + +## Reusable V3 Components Needed (build before page work) + +| Component | Used by | Notes | +|---|---|---| +| `CommandPanel` | all 5 hero + code sections | Black panel, square border, mono, copy affordance, language tabs (cURL / TS / Python / shell) | +| `CopyCommandButton` | already exists in cvm/sections/shared.tsx | Hoist to `src/components/product/` and reuse | +| `EvidenceRow` | inference, fine-tune, agents, data | Replaces Casestudies3 + Casestudies1Agents | +| `ComplianceStrip` | all 5 | Replaces Compliance5 | +| `FaqList` | all 5 | Replaces Faq14 + AIAgentsFAQ | +| `FinalCta` | all 5 | Replaces Cta4, leads with CopyCommandButton | +| `ArchitectureCellGrid` | all 5 | The `grid gap-px border border-border bg-border` pattern from CVM benefits | +| `LottieMotion` wrapper | all 5 hero | Aspect-ratio + reduced-motion handling | + +Lottie assets to source/build (one each, ~6–8 sec loop): +- `ModelApiFlow` — for inference +- `LoRASealFlow` — for fine-tuning +- `SealedTrainingFlow` — for training +- `AgentSandboxFlow` — for agents +- `ComputeToDataFlow` — for data + +If Lottie production is a blocker, each can ship in iteration 1 with a static `ArchitectureDiagram` SVG and upgrade to Lottie in iteration 2. + +## Recommended Redesign Order + +1. **`/solutions/confidential-training`** — P0, must fix the crash. Even a minimal hero replacement (route-local `hero.tsx` that doesn't import Hero216/Globe) unblocks the page. Do this first to get back to a 5-of-5 working state. +2. **`/solutions/private-ai-inference`** — highest-traffic, most-mentioned solution. Treat as the template page; the components built here (CommandPanel, ArchitectureCellGrid, EvidenceRow, etc.) are reused by the others. +3. **`/solutions/fine-tuned-models`** — close cousin of inference; reuse most components. +4. **`/solutions/ai-agents`** — uses more bespoke components (Frameworks chip strip), slightly more work. +5. **`/solutions/private-ai-data`** — content.ts already exists, so once shared components are built this is mostly composition. + +Build the shared `src/components/product/*` components alongside #2 (inference), then #3–#5 are mostly composition. + +## Acceptance Criteria (per page) + +A page is "done" when: + +- [ ] Loads without runtime errors (console clean, including React Flow warnings on the inline cards) +- [ ] Hero matches `/confidential-vm` rhythm: serif H1, supporting line, command CTA, single Lottie/static product visual, optional integration strip +- [ ] No rounded panels (`rounded-2xl`/`rounded-xl`); panels are sharp `border border-border bg-card` (or `bg-[#f7f8f3]` / `bg-[#090b0a]` for trust panels) +- [ ] Primary CTA copies an actual CLI/API command via `CopyCommandButton` +- [ ] At least one section explains the dstack mechanism with technical primitives (compose-hash, RA-TLS, KMS, signed receipt/manifest, on-chain revocation) +- [ ] One motion explaining the recipe (Lottie or static `ArchitectureDiagram` v1) +- [ ] Existing `HowItWorksSection` + per-solution flow card sits visually inside the page rhythm, not as a black box +- [ ] Visual diff vs `/confidential-vm` looks consistent: same typography, same border/shadow language, same accent usage + +## Design Tokens Audit + +The previous sections are about content + structure. This section is about the **actual design tokens** — type scale, color, corner radii, panel patterns, spacing — and which solution-page elements are violating them. + +### Current Token Landscape + +The site has three layers of "design tokens" today: + +**Layer 1 — Theme CSS vars (global, already correct everywhere):** +- `src/app/theme/colors.css`: `--background`, `--foreground`, `--card`, `--border`, `--muted`, `--primary` (lime ≈ `oklch(0.8962 0.1971 123.29)` ≈ `#aabbff`-ish lime green when rendered, surfaced as `#c5ff2e` in CVM panels), base scale `--base-50…--base-1000`, brand accents `--phala-blue/purple/orange-*`. All flow into Tailwind via `@theme inline`. +- `src/app/theme/typography.css`: `--font-display: var(--font-sans)` (Montserrat). Plus the Tailwind `font-mono` default. +- These are the only **truly shared** tokens. + +**Layer 2 — Per-page Exa typography scopes (duplicated, not yet shared):** +| Page | Class scope | Class names | Fonts loaded where | +|---|---|---|---| +| `/` (landing + art-direction-demo) | `
` element | `demo-heading`, `demo-section-title`, `demo-mono`, `demo-sans`, `demo-copy`, `demo-mono-next` (Geist Mono fallback) | `(home)/sections/content.tsx` inline ` + + + + + + + + + + + +
+ ) +} diff --git a/src/app/(main)/(home)/sections/data.ts b/src/app/(main)/(home)/sections/data.ts new file mode 100644 index 00000000..0886ac41 --- /dev/null +++ b/src/app/(main)/(home)/sections/data.ts @@ -0,0 +1,491 @@ +import type { CSSProperties } from 'react' +import type { Metadata } from 'next' + +import { partnersData } from '@/app/(main)/partnerships/partners-data' +import type { Model } from '@/lib/ai-models' + +export const metadata: Metadata = { + title: 'Phala Landing Demo', + description: + 'Phala landing page prototype using Phala color and Exa-inspired structure.', +} + +export const dynamic = 'force-dynamic' + +export const typeVars = { + fontFamily: 'var(--demo-body)', + '--demo-heading': 'var(--v3-heading)', + '--demo-body': 'var(--v3-body)', + '--demo-ui': 'var(--v3-ui)', + '--demo-mono': 'var(--v3-mono)', +} as CSSProperties + +export const products = [ + { + label: 'Runtime sandbox', + title: 'Agent sandbox', + description: + 'Run agent tools, app servers, and Docker services inside TEE-backed runtime sandboxes.', + command: 'phala deploy', + cta: 'Deploy sandbox', + href: '/confidential-vm', + }, + { + label: 'Confidential GPU', + title: 'GPU marketplace', + description: + 'Reserve H200 and B300 confidential GPU capacity for private AI training and inference.', + command: 'nvidia-smi -q', + cta: 'Open GPU marketplace', + href: '/gpu-tee', + }, +] + +export const platformCards = [ + { + title: 'Easy', + subtitle: 'Build in minutes', + copy: 'Write code, dockerize, and deploy it as trustless TEE apps.', + }, + { + title: 'Open', + subtitle: 'Audit everything', + copy: 'Explore the chain of trust, public verification, and open-source infrastructure.', + }, + { + title: 'Private', + subtitle: 'Hardware-level security', + copy: 'Only you can access your data: no one else, not even us.', + }, +] + +export const fallbackModelRows: Model[] = [ + { + id: 1, + name: 'DeepSeek V3.1', + provider: 'deepseek', + slug: 'deepseek/deepseek-chat-v3.1', + description: '', + contextLength: 128000, + promptPrice: '0.00000027', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2026-01-01T00:00:00.000Z', + updatedAt: '2026-01-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 2, + name: 'Qwen3 Coder 480B', + provider: 'qwen', + slug: 'qwen/qwen3-coder-480b-a35b-instruct', + description: '', + contextLength: 256000, + promptPrice: '0.0000004', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-12-01T00:00:00.000Z', + updatedAt: '2025-12-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 3, + name: 'Llama 3.3 70B', + provider: 'meta', + slug: 'meta-llama/llama-3.3-70b-instruct', + description: '', + contextLength: 128000, + promptPrice: '0.00000015', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-11-01T00:00:00.000Z', + updatedAt: '2025-11-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 4, + name: 'GPT OSS 120B', + provider: 'openai', + slug: 'openai/gpt-oss-120b', + description: '', + contextLength: 128000, + promptPrice: '0.0000001', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-10-01T00:00:00.000Z', + updatedAt: '2025-10-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 5, + name: 'Claude Sonnet 4.5', + provider: 'anthropic', + slug: 'anthropic/claude-sonnet-4.5', + description: '', + contextLength: 200000, + promptPrice: '0.000003', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-09-01T00:00:00.000Z', + updatedAt: '2025-09-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 6, + name: 'Gemini 2.5 Pro', + provider: 'google', + slug: 'google/gemini-2.5-pro', + description: '', + contextLength: 1000000, + promptPrice: '0.00000125', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-08-01T00:00:00.000Z', + updatedAt: '2025-08-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 7, + name: 'Mistral Large', + provider: 'mistral', + slug: 'mistralai/mistral-large', + description: '', + contextLength: 128000, + promptPrice: '0.000002', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-07-01T00:00:00.000Z', + updatedAt: '2025-07-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 8, + name: 'Kimi K2', + provider: 'moonshot', + slug: 'moonshotai/kimi-k2-instruct', + description: '', + contextLength: 128000, + promptPrice: '0.0000006', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-06-01T00:00:00.000Z', + updatedAt: '2025-06-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 9, + name: 'Gemma 3 27B', + provider: 'google', + slug: 'google/gemma-3-27b-it', + description: '', + contextLength: 128000, + promptPrice: '0.00000008', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-05-01T00:00:00.000Z', + updatedAt: '2025-05-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 10, + name: 'Llama 4 Scout', + provider: 'meta', + slug: 'meta-llama/llama-4-scout', + description: '', + contextLength: 10000000, + promptPrice: '0.00000011', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-04-01T00:00:00.000Z', + updatedAt: '2025-04-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 11, + name: 'Qwen Max', + provider: 'qwen', + slug: 'qwen/qwen-max', + description: '', + contextLength: 128000, + promptPrice: '0.0000016', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-03-01T00:00:00.000Z', + updatedAt: '2025-03-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, + { + id: 12, + name: 'DeepSeek R1', + provider: 'deepseek', + slug: 'deepseek/deepseek-r1', + description: '', + contextLength: 128000, + promptPrice: '0.00000055', + completionPrice: '0', + imagePrice: '0', + requestPrice: '0', + createdAt: '2025-02-01T00:00:00.000Z', + updatedAt: '2025-02-01T00:00:00.000Z', + enabled: true, + verifiable: true, + teeProviders: ['phala'], + }, +] + +export const modelIcons: Record = { + deepseek: '/confidential-ai-models/deepseek.svg', + qwen: '/confidential-ai-models/qwen.svg', + meta: '/confidential-ai-models/meta.svg', + openai: '/confidential-ai-models/openai.svg', + anthropic: '/confidential-ai-models/anthropic.svg', + google: '/confidential-ai-models/google.svg', + mistral: '/confidential-ai-models/mistral.svg', + moonshot: + 'https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://www.moonshot.cn/&size=32', +} + +export type OpenRouterUsageMetric = { + latestDate: string | null + latestTokens: number | null + modelCount: number + series: Array<{ date: string; total: number }> + source: string +} + +export const openRouterProviderUrl = 'https://openrouter.ai/provider/phala' + +export function formatCompactNumber(value: number | null) { + if (value === null) return 'Live source' + return new Intl.NumberFormat('en-US', { + compactDisplay: 'short', + maximumFractionDigits: value >= 1_000_000_000 ? 1 : 0, + notation: 'compact', + }).format(value) +} + +export function extractOpenRouterUsage( + html: string, +): OpenRouterUsageMetric | null { + const markerIndex = html.indexOf('Tokens processed on OpenRouter') + if (markerIndex < 0) return null + + const dataIndex = html.indexOf('\\"data\\":[', markerIndex) + if (dataIndex < 0) return null + + const start = html.indexOf('[', dataIndex) + if (start < 0) return null + + let depth = 0 + let end = -1 + for (let index = start; index < html.length; index += 1) { + const character = html[index] + if (character === '[') depth += 1 + if (character === ']') { + depth -= 1 + if (depth === 0) { + end = index + break + } + } + } + + if (end < 0) return null + + try { + const rawRows = JSON.parse( + html.slice(start, end + 1).replace(/\\"/g, '"'), + ) as Array<{ + x?: string + ys?: Record + }> + const series = rawRows + .map((row) => ({ + date: row.x?.slice(0, 10) ?? '', + total: Object.values(row.ys ?? {}).reduce( + (sum, value) => sum + Number(value ?? 0), + 0, + ), + })) + .filter((row) => row.date && row.total > 0) + const latest = series.at(-1) + + return { + latestDate: latest?.date ?? null, + latestTokens: latest?.total ?? null, + modelCount: rawRows.at(-1)?.ys + ? Object.keys(rawRows.at(-1)?.ys ?? {}).length + : 0, + series: series.slice(-18), + source: openRouterProviderUrl, + } + } catch { + return null + } +} + +export async function getOpenRouterUsage(): Promise { + try { + const response = await fetch(openRouterProviderUrl, { + cache: 'no-store', + headers: { + accept: 'text/html', + 'user-agent': 'PhalaWebsite/1.0 (+https://phala.network)', + }, + }) + if (!response.ok) throw new Error(`OpenRouter responded ${response.status}`) + + const metric = extractOpenRouterUsage(await response.text()) + if (metric) return metric + } catch { + // Keep rendering if OpenRouter is unavailable; the source link remains visible. + } + + return { + latestDate: null, + latestTokens: null, + modelCount: 0, + series: [], + source: openRouterProviderUrl, + } +} + +export const partnerNames = [ + 'Nvidia', + 'OpenRouter', + 'Z.AI', + 'OPPO', + 'Venice AI', + 'Intel', + 'Near', + 'Uniswap', + 'Flashbots', + 'Crossmint', +] + +export const partnerLogos = partnerNames + .map((name) => partnersData.find((partner) => partner.name === name)) + .filter((partner): partner is NonNullable => Boolean(partner)) + +export const featureShowcases = [ + { + eyebrow: 'Confidential VM', + title: 'Confidential AI cloud', + description: + 'Move existing Docker Compose workloads into CPU or GPU confidential machines. Keep the deploy path familiar; make the runtime verifiable.', + cta: 'phala deploy -c docker-compose.yml -n myapp', + secondaryCta: 'Check detail page', + ctaTitle: 'Deploy a confidential VM', + ctaCopy: + 'Use your existing Compose file, then inspect the running CVM from Phala Cloud.', + ctaHref: '/confidential-vm', + secondaryHref: '/confidential-vm', + visual: 'cvm', + dark: true, + }, + { + eyebrow: 'Attestation', + title: 'Every result can carry proof', + description: + 'Instead of asking users to trust a cloud claim, Phala emits runtime measurements that software can verify.', + cta: 'phala cvms attestation ', + secondaryCta: 'Read attestation docs', + ctaTitle: 'Verify the runtime', + ctaCopy: + 'Fetch and verify the CVM attestation before trusting workload output.', + ctaHref: 'https://docs.phala.com/phala-cloud/getting-started/attestation', + secondaryHref: + 'https://docs.phala.com/phala-cloud/getting-started/attestation', + visual: 'attestation', + }, +] + +export const metrics = [ + { + value: 5000, + suffix: '+', + label: 'Users', + description: 'Building with confidential AI', + }, + { + value: 10000, + suffix: '+', + label: 'Daily Attestations', + description: 'Runtime proofs generated and checked', + }, + { + value: 95, + suffix: '%', + label: 'TEE Performance', + description: 'Near-native confidential GPU execution', + }, +] + +export const compliance = [ + 'SOC 2 Type I Certified', + 'HIPAA Compliant', + 'ISO 27001 In Progress', + '99.9% Uptime SLA', + 'GDPR Compliant Processing', + '24/7 Enterprise Support', +] + +export const faqs = [ + [ + 'What is Trusted Execution Environment (TEE)?', + 'TEE is a secure area inside a processor that protects code and data from the operating system, hypervisor, and other applications.', + ], + [ + 'How does confidential AI protect sensitive data?', + 'Sensitive data and AI models remain private during processing by running inside hardware-backed secure environments.', + ], + [ + 'Is Phala compatible with existing AI frameworks?', + 'Yes. Phala supports existing Docker services and popular AI frameworks including TensorFlow, PyTorch, and Hugging Face.', + ], + [ + 'What are the performance implications?', + 'Confidential GPU workloads typically target near-native performance, with roughly 5-10% overhead depending on workload and hardware.', + ], + [ + 'How can I verify the security of my AI workloads?', + 'Phala exposes cryptographic attestations so users and systems can verify the workload and runtime state.', + ], + [ + 'How do I get started?', + 'Install the Phala CLI, deploy a Docker workload, then inspect status, logs, and attestation from the command line.', + ], +] diff --git a/src/app/(main)/(home)/sections/faq-section.tsx b/src/app/(main)/(home)/sections/faq-section.tsx new file mode 100644 index 00000000..2cea9049 --- /dev/null +++ b/src/app/(main)/(home)/sections/faq-section.tsx @@ -0,0 +1,43 @@ +import { faqs } from './data' + +export function FAQSection() { + return ( +
+
+
+

+ FAQ +

+

+ Common Questions & Answers +

+

+ Find out all the essential details about our platform and how it can + serve your needs. +

+
+ +
+ {faqs.map(([question, answer], index) => ( +
+ + {index + 1} + +
+

+ {question} +

+

+ {answer} +

+
+
+ ))} +
+
+
+ ) +} diff --git a/src/app/(main)/(home)/sections/feature-showcases.tsx b/src/app/(main)/(home)/sections/feature-showcases.tsx new file mode 100644 index 00000000..e9ed468f --- /dev/null +++ b/src/app/(main)/(home)/sections/feature-showcases.tsx @@ -0,0 +1,333 @@ +import type { CSSProperties } from 'react' +import Link from 'next/link' + +import { TypingAnimation } from '@/components/magicui/terminal' +import { CopyCliButton } from '../../art-direction-demo/demo-interactions' +import { featureShowcases } from './data' + +const TERMINAL_TYPE_DURATION = 14 +const TERMINAL_LINE_GAP = 140 + +function typedLineDelay(lines: string[], index: number) { + return lines + .slice(0, index) + .reduce( + (delay, line) => + delay + line.length * TERMINAL_TYPE_DURATION + TERMINAL_LINE_GAP, + 0, + ) +} + +export function FeatureShowcases() { + return ( +
+ {featureShowcases.map((feature, index) => ( +
+
+ + +
+

+ {feature.eyebrow} +

+

+ {feature.title} +

+

+ {feature.description} +

+ +
+
+
+ ))} +
+ ) +} + +function FeatureCtaPanel({ + command, + secondaryHref, + secondaryLabel, +}: { + command: string + dark?: boolean + secondaryHref: string + secondaryLabel: string +}) { + return ( +
+ + + {secondaryLabel} + +
+ ) +} + +function FeatureVisual({ type, dark }: { type: string; dark?: boolean }) { + return ( +
+
+ + {type === 'fleet' && } + {type === 'proof' && } + {type === 'cvm' && } + {type === 'attestation' && } +
+ ) +} + +function CvmVisual() { + const lines = [ + '$ phala deploy -c docker-compose.yml -n myapp', + 'building compose plan', + 'selecting CPU TEE: Intel TDX', + 'selecting GPU TEE: NVIDIA CC', + 'injecting encrypted env', + 'cvm ready: https://myapp.phala.network', + ] + + return ( + <> +
+
+
+
+ + + +
+
+ + Phala + + + Google + + + AWS + +
+
+
+ {lines.map((line, index) => ( + + {line} + + ))} +
+
+ +
+
+
+ {Array.from({ length: 24 }).map((_, node) => ( + + ))} +
+

CPU machine

+
+
+
+ {Array.from({ length: 9 }).map((_, node) => ( + + ))} +
+

GPU machine

+
+
+ + ) +} + +function AttestationTerminalVisual() { + const fields = [ + ['quote', 'AgABAL8LAAAMAAsA...'], + ['mrenclave', 'a7f2c8d9e1b4...'], + ['tcb_level', 'UpToDate'], + ['signature', 'Intel/NVIDIA signed'], + ] + const command = '$ curl https://api.phala.network/attest/' + const fieldLines = fields.map(([key, value]) => `"${key}": "${value}",`) + const fieldsStart = + command.length * TERMINAL_TYPE_DURATION + TERMINAL_LINE_GAP + const finalDelay = + fieldsStart + + fieldLines.reduce( + (delay, line) => + delay + line.length * TERMINAL_TYPE_DURATION + TERMINAL_LINE_GAP, + 0, + ) + + return ( + <> +
+
+ {['hardware quote', 'runtime measurement', 'verifier report'].map( + (label, index) => ( +
+ {label} + +
+ ), + )} +
+
+
+ terminal · attestation.json +
+
+ + {command} + +

{'{'}

+ {fields.map(([key, value], index) => ( + + {`"${key}": "${value}",`} + + ))} +

{'}'}

+ + ✓ TEE signature valid · code integrity verified + +
+
+ + ) +} + +function FleetVisual() { + return ( + <> +
+ {Array.from({ length: 25 }).map((_, index) => ( + + ))} +
+
+ {Array.from({ length: 8 }).map((_, index) => ( + + ))} +
+
+

+ phala deploy -c docker-compose.yml -n ai-workers +
+ sealed: 48 workloads · proofs streaming +

+
+ + ) +} + +function ProofVisual() { + return ( + <> +
+
+
+

+ + Attestation report +

+ {[ + 'measurement: 0x8f2a...', + 'runtime: expected', + 'secrets: sealed', + 'result: signed', + ].map((line, index) => ( +
+

{line}

+
+
+ ))} +
+
+ Verify on +
+ + ) +} diff --git a/src/app/(main)/(home)/sections/final-cta-section.tsx b/src/app/(main)/(home)/sections/final-cta-section.tsx new file mode 100644 index 00000000..a3b1b651 --- /dev/null +++ b/src/app/(main)/(home)/sections/final-cta-section.tsx @@ -0,0 +1,57 @@ +import Link from 'next/link' + +import { + CommandPanel, + InlineAgentPromptButton, +} from '@/components/product/marketing' +import { CLI_QUICKSTART_PROMPT } from '@/lib/skills' + +export function FinalCTASection() { + return ( +
+ +
+ ) +} diff --git a/src/app/(main)/(home)/sections/hero-section.tsx b/src/app/(main)/(home)/sections/hero-section.tsx new file mode 100644 index 00000000..8e487866 --- /dev/null +++ b/src/app/(main)/(home)/sections/hero-section.tsx @@ -0,0 +1,48 @@ +import Link from 'next/link' + +import { CopyInstallButton } from '../../art-direction-demo/demo-interactions' +import { ComputeGenomeHeroLoader } from './compute-genome-hero-loader' + +export function HeroSection() { + return ( +
+ +
+
+
+
+

+ + Trusted AI + +

+ +

+ Private execution. Verifiable results. +

+ +

+ Run agents, private LLM models, and GPU jobs inside hardware-backed + TEEs. Keep secrets private, and prove what ran. +

+ +
+ + + Start building + + + Talk to sales + +
+
+
+
+ ) +} diff --git a/src/app/(main)/(home)/sections/logo-band.tsx b/src/app/(main)/(home)/sections/logo-band.tsx new file mode 100644 index 00000000..7cacf0f0 --- /dev/null +++ b/src/app/(main)/(home)/sections/logo-band.tsx @@ -0,0 +1,37 @@ +import { partnerLogos } from './data' + +export function LogoBand() { + return ( +
+
+
+
+

+ Trusted by 5,000+ users +

+

+ Trusted by industry leaders and developers worldwide. +

+
+
+ {partnerLogos.map((partner) => ( + + {`${partner.name} + + ))} +
+
+
+
+ ) +} diff --git a/src/app/(main)/(home)/sections/platform-section.tsx b/src/app/(main)/(home)/sections/platform-section.tsx new file mode 100644 index 00000000..84251b65 --- /dev/null +++ b/src/app/(main)/(home)/sections/platform-section.tsx @@ -0,0 +1,18 @@ +import { PlatformFeatureSwitch } from '../../art-direction-demo/demo-interactions' +import { platformCards } from './data' + +export function PlatformSection() { + return ( +
+
+
+

+ All-in-one confidential compute platform for AI workloads. +

+
+ + +
+
+ ) +} diff --git a/src/app/(main)/(home)/sections/product-section.tsx b/src/app/(main)/(home)/sections/product-section.tsx new file mode 100644 index 00000000..e779e52e --- /dev/null +++ b/src/app/(main)/(home)/sections/product-section.tsx @@ -0,0 +1,219 @@ +import type { CSSProperties } from 'react' +import Link from 'next/link' + +import { TypingAnimation } from '@/components/magicui/terminal' +import { CopyCliButton } from '../../art-direction-demo/demo-interactions' +import { ModelCatalogGrid } from '@/components/product/model-card' +import { getModelProviderIcon, type Model } from '@/lib/ai-models' +import { fallbackModelRows, products } from './data' + +export function ProductSection({ + models = fallbackModelRows, +}: { + models?: Model[] +}) { + const modelRows = models.length > 0 ? models.slice(0, 12) : fallbackModelRows + + return ( +
+
+
+

+ Products +

+

+ Full service for AI privacy: agent sandbox, LLM, and GPU. +

+
+ +
+ {products.map((product) => ( +
+ +
+ {product.label} +
+

+ {product.title} +

+

+ {product.description} +

+
+ + + {product.cta} + +
+
+ ))} +
+ + +
+
+ ) +} + +function ProductArt({ label }: { label: string }) { + const mode = + label === 'Confidential AI models' + ? 'models' + : label === 'Confidential GPU' + ? 'gpu' + : 'cloud' + const chipSrc = + mode === 'gpu' + ? '/chips_final_webp/nvidia_h200.webp' + : mode === 'models' + ? '/chips_final_webp/nvidia_b300.webp' + : '/chips_final_webp/intel_xeon.webp' + + return ( +
+
+
+ +
+ + {mode === 'models' && ( +
+ {[24, 54, 36, 72, 44, 64].map((height, index) => ( + + ))} +
+ )} + {mode === 'gpu' && ( +
+ {[ + ['H200', '141GB VRAM', '$2.56/GPU/hr', 'US · 24 vCPU'], + ['B300', '288GB VRAM', '$5.63/GPU/hr', 'US · 12 vCPU'], + ].map(([name, memory, price, status], index) => ( +
+
+

{name}

+

{status}

+
+
+
+

{memory}

+

+ Intel TDX + NVIDIA CC +

+
+

+ {price} +

+
+
+ ))} +
+ )} + {mode === 'cloud' && ( +
+ {Array.from({ length: 48 }).map((_, index) => ( + + ))} +
+ + phala deploy -c docker-compose.yml -n myapp + +
+
+ )} +
+ proof path +
+
+ {mode} +
+
+ ) +} + +function ModelListPanel({ models }: { models: Model[] }) { + return ( +
+
+

+ Confidential models +

+

+ Private LLM models with real model choice. +

+

+ OpenAI-compatible LLM endpoints, private prompts, and verifiable + runtime state. +

+ + Explore LLM models + +
+
+ {[...models, ...models].map((model, index) => ( +
+ + {model.provider} +
+ ))} +
+
+
+ + +
+ ) +} diff --git a/src/app/(main)/(home)/sections/scale-section.tsx b/src/app/(main)/(home)/sections/scale-section.tsx new file mode 100644 index 00000000..677b2a83 --- /dev/null +++ b/src/app/(main)/(home)/sections/scale-section.tsx @@ -0,0 +1,150 @@ +import type { CSSProperties } from 'react' + +import { JumpNumber } from '../../art-direction-demo/demo-interactions' +import { formatCompactNumber, getOpenRouterUsage, metrics } from './data' + +export function ScaleSection() { + return ( +
+
+
+

Proven at Scale

+

+ Built for enterprise security and regulatory requirements. +

+
+ +
+ {metrics.map((metric, index) => ( +
+

+ {metric.description} +

+

+ +

+
+
+
+

+ {metric.label} +

+
+ ))} +
+ +
+
+ ) +} + +async function NetworkChartPanel() { + const openRouterUsage = await getOpenRouterUsage() + const maxTokens = Math.max( + ...openRouterUsage.series.map((point) => point.total), + 1, + ) + const chartPoints = openRouterUsage.series + + return ( +
+
+
+
+

Total VMs

+

+ Live network source from Dune +

+
+ + Open source + +
+
+