cinematic-web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/assets/CLAUDE.md +150 -0
  3. package/assets/presets/3d-immersive/README.md +30 -0
  4. package/assets/presets/3d-immersive/preset.json +45 -0
  5. package/assets/presets/antigravity-lift/README.md +24 -0
  6. package/assets/presets/antigravity-lift/preset.json +38 -0
  7. package/assets/presets/brutalist-signal/README.md +24 -0
  8. package/assets/presets/brutalist-signal/preset.json +36 -0
  9. package/assets/presets/midnight-luxe/README.md +24 -0
  10. package/assets/presets/midnight-luxe/preset.json +36 -0
  11. package/assets/presets/organic-tech/README.md +24 -0
  12. package/assets/presets/organic-tech/preset.json +37 -0
  13. package/assets/presets/vapor-clinic/README.md +24 -0
  14. package/assets/presets/vapor-clinic/preset.json +36 -0
  15. package/assets/prompts/product-development/Guided-MVP-Concept.md +67 -0
  16. package/assets/prompts/product-development/Guided-MVP.md +65 -0
  17. package/assets/prompts/product-development/Guided-PRD-Creation.md +51 -0
  18. package/assets/prompts/product-development/Guided-Test-Plan.md +57 -0
  19. package/assets/prompts/product-development/Guided-UX-User-Flow.md +93 -0
  20. package/assets/prompts/product-development/README.md +21 -0
  21. package/assets/prompts/product-development/v0-design-prompt.md +107 -0
  22. package/assets/templates/base-react/index.html +18 -0
  23. package/assets/templates/base-react/package.json +26 -0
  24. package/assets/templates/base-react/postcss.config.js +6 -0
  25. package/assets/templates/base-react/src/App.jsx +33 -0
  26. package/assets/templates/base-react/src/index.css +90 -0
  27. package/assets/templates/base-react/src/main.jsx +10 -0
  28. package/assets/templates/base-react/src/sections/Features.jsx +238 -0
  29. package/assets/templates/base-react/src/sections/Footer.jsx +120 -0
  30. package/assets/templates/base-react/src/sections/Hero.jsx +96 -0
  31. package/assets/templates/base-react/src/sections/Navbar.jsx +119 -0
  32. package/assets/templates/base-react/src/sections/Philosophy.jsx +67 -0
  33. package/assets/templates/base-react/src/sections/Pricing.jsx +135 -0
  34. package/assets/templates/base-react/src/sections/Protocol.jsx +123 -0
  35. package/assets/templates/base-react/tailwind.config.js +26 -0
  36. package/assets/templates/base-react/vite.config.js +6 -0
  37. package/assets/templates/three-fiber/eslint.config.js +21 -0
  38. package/assets/templates/three-fiber/index.html +16 -0
  39. package/assets/templates/three-fiber/package.json +36 -0
  40. package/assets/templates/three-fiber/postcss.config.js +6 -0
  41. package/assets/templates/three-fiber/src/App.jsx +61 -0
  42. package/assets/templates/three-fiber/src/components/CameraRig.jsx +42 -0
  43. package/assets/templates/three-fiber/src/components/NetworkGraph.jsx +120 -0
  44. package/assets/templates/three-fiber/src/components/ParticleSystem.jsx +77 -0
  45. package/assets/templates/three-fiber/src/components/Scene.jsx +39 -0
  46. package/assets/templates/three-fiber/src/components/SocialProofBillboards.jsx +56 -0
  47. package/assets/templates/three-fiber/src/context/SceneContext.jsx +21 -0
  48. package/assets/templates/three-fiber/src/index.css +37 -0
  49. package/assets/templates/three-fiber/src/main.jsx +21 -0
  50. package/assets/templates/three-fiber/src/sections/CTA.jsx +41 -0
  51. package/assets/templates/three-fiber/src/sections/Hero.jsx +66 -0
  52. package/assets/templates/three-fiber/src/sections/HowItWorks.jsx +55 -0
  53. package/assets/templates/three-fiber/src/sections/Navbar.jsx +40 -0
  54. package/assets/templates/three-fiber/src/sections/SocialProof.jsx +50 -0
  55. package/assets/templates/three-fiber/src/sections/TheOldWay.jsx +28 -0
  56. package/assets/templates/three-fiber/src/sections/ValueProps.jsx +50 -0
  57. package/assets/templates/three-fiber/tailwind.config.js +21 -0
  58. package/assets/templates/three-fiber/vite.config.js +7 -0
  59. package/dist/cli.js +539 -0
  60. package/dist/cli.js.map +1 -0
  61. package/package.json +44 -0
@@ -0,0 +1,39 @@
1
+ import { Canvas } from '@react-three/fiber'
2
+ import { AdaptiveDpr, AdaptiveEvents } from '@react-three/drei'
3
+ import { EffectComposer, Bloom } from '@react-three/postprocessing'
4
+ import NetworkGraph from './NetworkGraph'
5
+ import CameraRig from './CameraRig'
6
+ import ParticleSystem from './ParticleSystem'
7
+ import SocialProofBillboards from './SocialProofBillboards'
8
+
9
+ // Detect low-end device: fewer nodes, no Bloom
10
+ const isLowEnd = typeof navigator !== 'undefined' && navigator.hardwareConcurrency <= 2
11
+
12
+ export default function Scene() {
13
+ return (
14
+ <Canvas
15
+ camera={{ position: [0, 0, 20], fov: 60, near: 0.1, far: 100 }}
16
+ gl={{ antialias: !isLowEnd, alpha: false }}
17
+ dpr={[1, isLowEnd ? 1 : 2]}
18
+ style={{ background: '{{palette.background}}' }}
19
+ >
20
+ <fog attach="fog" args={['{{palette.background}}', 20, 60]} />
21
+ <ambientLight intensity={0.3} />
22
+ <pointLight position={[0, 0, 10]} intensity={1.5} color="{{palette.accent}}" />
23
+
24
+ <CameraRig />
25
+ <NetworkGraph lowEnd={isLowEnd} />
26
+ <ParticleSystem />
27
+ <SocialProofBillboards />
28
+
29
+ {!isLowEnd && (
30
+ <EffectComposer>
31
+ <Bloom luminanceThreshold={0.3} luminanceSmoothing={0.9} intensity={0.8} />
32
+ </EffectComposer>
33
+ )}
34
+
35
+ <AdaptiveDpr pixelated />
36
+ <AdaptiveEvents />
37
+ </Canvas>
38
+ )
39
+ }
@@ -0,0 +1,56 @@
1
+ import { Html } from '@react-three/drei'
2
+ import { useScene } from '../context/SceneContext'
3
+
4
+ const TESTIMONIALS = [
5
+ {
6
+ text: "{{brand}} delivered results in the first week. Nothing else came close.",
7
+ author: "Priya K., Founder",
8
+ position: [-4, 2, 2],
9
+ },
10
+ {
11
+ text: "Finally a product that doesn't feel like every other AI tool out there.",
12
+ author: "Marcus T., Director",
13
+ position: [4, -1, 1],
14
+ },
15
+ {
16
+ text: "I've tried everything. {{brand}} is the only one that actually works.",
17
+ author: "Alex M., Consultant",
18
+ position: [0, -3, 4],
19
+ },
20
+ ]
21
+
22
+ export default function SocialProofBillboards() {
23
+ const { sceneIndex } = useScene()
24
+
25
+ if (sceneIndex !== 4) return null
26
+
27
+ return (
28
+ <>
29
+ {TESTIMONIALS.map((t, i) => (
30
+ <Html
31
+ key={i}
32
+ position={t.position}
33
+ center
34
+ distanceFactor={8}
35
+ style={{ pointerEvents: 'none' }}
36
+ >
37
+ <div style={{
38
+ background: 'rgba(10,10,20,0.85)',
39
+ border: '1px solid {{palette.accent}}66',
40
+ borderRadius: '12px',
41
+ padding: '16px 20px',
42
+ width: '220px',
43
+ backdropFilter: 'blur(12px)',
44
+ color: '#e0e0ff',
45
+ fontFamily: '{{typography.heading0}}, sans-serif',
46
+ fontSize: '12px',
47
+ lineHeight: 1.6,
48
+ }}>
49
+ <p style={{ margin: '0 0 8px', color: '#ccc' }}>"{t.text}"</p>
50
+ <p style={{ margin: 0, color: '{{palette.accent}}', fontWeight: 600, fontSize: '11px' }}>— {t.author}</p>
51
+ </div>
52
+ </Html>
53
+ ))}
54
+ </>
55
+ )
56
+ }
@@ -0,0 +1,21 @@
1
+ import { createContext, useContext, useState, useCallback } from 'react'
2
+
3
+ const SceneContext = createContext({ progress: 0, sceneIndex: 0, setProgress: () => {} })
4
+
5
+ export function SceneProvider({ children }) {
6
+ const [progress, setProgressRaw] = useState(0)
7
+ const [sceneIndex, setSceneIndex] = useState(0)
8
+
9
+ const setProgress = useCallback((p) => {
10
+ setProgressRaw(p)
11
+ setSceneIndex(Math.min(5, Math.floor(p * 6)))
12
+ }, [])
13
+
14
+ return (
15
+ <SceneContext.Provider value={{ progress, sceneIndex, setProgress }}>
16
+ {children}
17
+ </SceneContext.Provider>
18
+ )
19
+ }
20
+
21
+ export const useScene = () => useContext(SceneContext)
@@ -0,0 +1,37 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* Base reset */
6
+ *, *::before, *::after { box-sizing: border-box; }
7
+ html, body { margin: 0; padding: 0; background: {{palette.background}}; overflow-x: hidden; }
8
+ #root { width: 100%; }
9
+
10
+ /* Noise overlay — eliminates flat digital gradients */
11
+ body::before {
12
+ content: '';
13
+ position: fixed;
14
+ inset: 0;
15
+ z-index: 9999;
16
+ pointer-events: none;
17
+ opacity: 0.04;
18
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
19
+ background-size: 200px 200px;
20
+ }
21
+
22
+ /* Scrollbar */
23
+ ::-webkit-scrollbar { width: 4px; }
24
+ ::-webkit-scrollbar-track { background: {{palette.background}}; }
25
+ ::-webkit-scrollbar-thumb { background: {{palette.accent}}; border-radius: 2px; }
26
+
27
+ /* Scene section utility — positioned absolute inside the 600vh container */
28
+ .scene-section {
29
+ position: absolute;
30
+ width: 100%;
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ height: 100vh;
35
+ pointer-events: none;
36
+ }
37
+ .scene-section > * { pointer-events: auto; }
@@ -0,0 +1,21 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import Lenis from '@studio-freight/lenis'
4
+ import { gsap } from 'gsap'
5
+ import { ScrollTrigger } from 'gsap/ScrollTrigger'
6
+ import './index.css'
7
+ import App from './App.jsx'
8
+
9
+ gsap.registerPlugin(ScrollTrigger)
10
+
11
+ // Lenis smooth scroll wired into GSAP ticker
12
+ const lenis = new Lenis()
13
+ gsap.ticker.add((time) => lenis.raf(time * 1000))
14
+ gsap.ticker.lagSmoothing(0)
15
+ lenis.on('scroll', ScrollTrigger.update)
16
+
17
+ createRoot(document.getElementById('root')).render(
18
+ <StrictMode>
19
+ <App />
20
+ </StrictMode>
21
+ )
@@ -0,0 +1,41 @@
1
+ export default function CTA({ style }) {
2
+ return (
3
+ <div className="scene-section" style={style}>
4
+ <div className="max-w-2xl px-8 text-center">
5
+ <h2 className="text-5xl md:text-6xl font-extrabold text-white leading-tight mb-6">
6
+ Ready to experience<br />
7
+ <span
8
+ className="text-transparent bg-clip-text"
9
+ style={{ backgroundImage: 'linear-gradient(135deg, {{palette.accent}} 0%, #22D3EE 100%)' }}
10
+ >
11
+ {{brand}}?
12
+ </span>
13
+ </h2>
14
+ <p className="text-gray-400 text-xl mb-10">
15
+ {{purpose}}
16
+ </p>
17
+ <a
18
+ href="#"
19
+ className="inline-block text-white font-bold text-xl px-12 py-5 rounded-full transition-all duration-200"
20
+ style={{
21
+ background: '{{palette.accent}}',
22
+ boxShadow: '0 0 60px {{palette.accent}}80',
23
+ }}
24
+ onMouseEnter={e => {
25
+ e.currentTarget.style.transform = 'scale(1.03)'
26
+ e.currentTarget.style.boxShadow = '0 0 80px {{palette.accent}}b3'
27
+ e.currentTarget.style.opacity = '0.85'
28
+ }}
29
+ onMouseLeave={e => {
30
+ e.currentTarget.style.transform = 'scale(1)'
31
+ e.currentTarget.style.boxShadow = '0 0 60px {{palette.accent}}80'
32
+ e.currentTarget.style.opacity = '1'
33
+ }}
34
+ >
35
+ {{cta}} →
36
+ </a>
37
+ <p className="text-gray-600 text-sm mt-5">No commitment required · Get started today</p>
38
+ </div>
39
+ </div>
40
+ )
41
+ }
@@ -0,0 +1,66 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { gsap } from 'gsap'
3
+
4
+ export default function Hero({ style }) {
5
+ const ref = useRef()
6
+
7
+ useEffect(() => {
8
+ const ctx = gsap.context(() => {
9
+ gsap.from(ref.current.children, {
10
+ y: 40,
11
+ opacity: 0,
12
+ duration: 1,
13
+ stagger: 0.12,
14
+ ease: 'power3.out',
15
+ delay: 0.8,
16
+ })
17
+ }, ref)
18
+ return () => ctx.revert()
19
+ }, [])
20
+
21
+ return (
22
+ <div className="scene-section" style={style}>
23
+ <div
24
+ ref={ref}
25
+ className="max-w-3xl px-8"
26
+ style={{ marginLeft: 'min(-10vw, -40px)' }}
27
+ >
28
+ <p className="text-accent text-sm font-semibold tracking-widest uppercase mb-4">
29
+ {{preset.name}}
30
+ </p>
31
+ <h1 className="text-5xl md:text-7xl font-extrabold text-white leading-none mb-6">
32
+ {{heroLine1}}<br />
33
+ <span
34
+ className="text-transparent bg-clip-text"
35
+ style={{ backgroundImage: 'linear-gradient(135deg, {{palette.accent}} 0%, #22D3EE 100%)' }}
36
+ >
37
+ {{heroLine2}}
38
+ </span>
39
+ </h1>
40
+ <p className="text-gray-400 text-lg md:text-xl max-w-xl mb-8 leading-relaxed">
41
+ {{purpose}}
42
+ </p>
43
+ <div className="flex flex-wrap gap-4">
44
+ <a
45
+ href="#"
46
+ className="text-white font-semibold px-8 py-4 rounded-full transition-all duration-200"
47
+ style={{ background: '{{palette.accent}}', boxShadow: '0 0 30px {{palette.accent}}66' }}
48
+ onMouseEnter={e => { e.currentTarget.style.transform = 'scale(1.03)'; e.currentTarget.style.opacity = '0.85' }}
49
+ onMouseLeave={e => { e.currentTarget.style.transform = 'scale(1)'; e.currentTarget.style.opacity = '1' }}
50
+ >
51
+ {{cta}}
52
+ </a>
53
+ <a
54
+ href="#"
55
+ className="text-gray-400 font-medium px-8 py-4 rounded-full border border-gray-700 hover:text-white transition-all duration-200"
56
+ style={{ '--tw-border-opacity': 1 }}
57
+ onMouseEnter={e => { e.currentTarget.style.borderColor = '{{palette.accent}}' }}
58
+ onMouseLeave={e => { e.currentTarget.style.borderColor = '' }}
59
+ >
60
+ Learn more
61
+ </a>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ )
66
+ }
@@ -0,0 +1,55 @@
1
+ const STEPS = [
2
+ {
3
+ n: '01',
4
+ title: '{{protocolStep0Title}}',
5
+ desc: '{{protocolStep0Desc}}',
6
+ },
7
+ {
8
+ n: '02',
9
+ title: '{{protocolStep1Title}}',
10
+ desc: '{{protocolStep1Desc}}',
11
+ },
12
+ {
13
+ n: '03',
14
+ title: '{{protocolStep2Title}}',
15
+ desc: '{{protocolStep2Desc}}',
16
+ },
17
+ ]
18
+
19
+ export default function HowItWorks({ style }) {
20
+ return (
21
+ <div className="scene-section" style={style}>
22
+ <div className="max-w-3xl px-8 w-full">
23
+ <p className="text-cyan text-sm font-semibold tracking-widest uppercase mb-4 text-center">
24
+ How it works
25
+ </p>
26
+ <h2 className="text-4xl md:text-5xl font-extrabold text-white text-center mb-12">
27
+ Three steps. Real results.
28
+ </h2>
29
+ <div className="flex flex-col gap-5">
30
+ {STEPS.map((s, i) => (
31
+ <div
32
+ key={i}
33
+ className="flex items-start gap-6"
34
+ style={{
35
+ padding: '20px 24px',
36
+ borderRadius: '16px',
37
+ background: 'rgba(10,10,20,0.65)',
38
+ border: '1px solid rgba(34,211,238,0.15)',
39
+ backdropFilter: 'blur(10px)',
40
+ }}
41
+ >
42
+ <span className="text-cyan font-mono font-bold text-2xl opacity-60 flex-shrink-0">
43
+ {s.n}
44
+ </span>
45
+ <div>
46
+ <h3 className="text-white font-bold text-xl mb-1">{s.title}</h3>
47
+ <p className="text-gray-400 text-sm leading-relaxed">{s.desc}</p>
48
+ </div>
49
+ </div>
50
+ ))}
51
+ </div>
52
+ </div>
53
+ </div>
54
+ )
55
+ }
@@ -0,0 +1,40 @@
1
+ import { useEffect, useRef } from 'react'
2
+ import { gsap } from 'gsap'
3
+
4
+ export default function Navbar() {
5
+ const ref = useRef()
6
+
7
+ useEffect(() => {
8
+ const ctx = gsap.context(() => {
9
+ gsap.from(ref.current, { y: -40, opacity: 0, duration: 1, ease: 'power3.out', delay: 0.5 })
10
+ })
11
+ return () => ctx.revert()
12
+ }, [])
13
+
14
+ return (
15
+ <nav
16
+ ref={ref}
17
+ className="fixed top-6 left-1/2 -translate-x-1/2 z-50 flex items-center gap-8 px-6 py-3 rounded-full"
18
+ style={{
19
+ background: 'rgba(10,10,20,0.6)',
20
+ backdropFilter: 'blur(20px)',
21
+ border: '1px solid {{palette.accent}}33',
22
+ }}
23
+ >
24
+ <span className="text-white font-bold tracking-wider text-sm">{{brand}}</span>
25
+ <div className="hidden md:flex gap-6 text-sm text-gray-400">
26
+ <a href="#" className="hover:text-white transition-colors duration-200">How it works</a>
27
+ <a href="#" className="hover:text-white transition-colors duration-200">Pricing</a>
28
+ </div>
29
+ <a
30
+ href="#"
31
+ className="text-white text-sm font-semibold px-4 py-2 rounded-full transition-all duration-200"
32
+ style={{ background: '{{palette.accent}}', boxShadow: '0 0 20px {{palette.accent}}4d' }}
33
+ onMouseEnter={e => { e.currentTarget.style.transform = 'scale(1.03)'; e.currentTarget.style.opacity = '0.85' }}
34
+ onMouseLeave={e => { e.currentTarget.style.transform = 'scale(1)'; e.currentTarget.style.opacity = '1' }}
35
+ >
36
+ {{cta}}
37
+ </a>
38
+ </nav>
39
+ )
40
+ }
@@ -0,0 +1,50 @@
1
+ const METRICS = [
2
+ { value: '500+', label: 'Active users' },
3
+ { value: '4×', label: 'Better results' },
4
+ { value: '98%', label: 'Satisfaction rate' },
5
+ { value: '10×', label: 'Industry average' },
6
+ ]
7
+
8
+ export default function SocialProof({ style }) {
9
+ return (
10
+ <div className="scene-section" style={style}>
11
+ <div className="max-w-4xl px-8 w-full">
12
+ <p className="text-glow text-sm font-semibold tracking-widest uppercase mb-4 text-center">
13
+ Social proof
14
+ </p>
15
+ <h2 className="text-3xl md:text-4xl font-extrabold text-white text-center mb-10">
16
+ Numbers don't lie.
17
+ </h2>
18
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-6 mb-8">
19
+ {METRICS.map((m, i) => (
20
+ <div
21
+ key={i}
22
+ className="text-center p-6 rounded-2xl"
23
+ style={{
24
+ background: 'rgba(10,10,20,0.7)',
25
+ border: '1px solid {{palette.accent}}33',
26
+ backdropFilter: 'blur(12px)',
27
+ }}
28
+ >
29
+ <div
30
+ className="text-4xl font-extrabold mb-1"
31
+ style={{
32
+ background: 'linear-gradient(135deg, {{palette.accent}}, #22D3EE)',
33
+ WebkitBackgroundClip: 'text',
34
+ WebkitTextFillColor: 'transparent',
35
+ backgroundClip: 'text',
36
+ }}
37
+ >
38
+ {m.value}
39
+ </div>
40
+ <div className="text-gray-400 text-sm">{m.label}</div>
41
+ </div>
42
+ ))}
43
+ </div>
44
+ <p className="text-gray-600 text-center text-xs tracking-widest uppercase">
45
+ ↑ Testimonials floating in the network above
46
+ </p>
47
+ </div>
48
+ </div>
49
+ )
50
+ }
@@ -0,0 +1,28 @@
1
+ const PAIN_POINTS = [
2
+ 'Slow, manual processes that don\'t scale',
3
+ 'Generic solutions that ignore your context',
4
+ 'Results that disappoint every time',
5
+ ]
6
+
7
+ export default function TheOldWay({ style }) {
8
+ return (
9
+ <div className="scene-section" style={style}>
10
+ <div className="max-w-2xl px-8 text-center">
11
+ <p className="text-danger text-sm font-semibold tracking-widest uppercase mb-4">
12
+ The old way
13
+ </p>
14
+ <h2 className="text-4xl md:text-6xl font-extrabold text-white leading-tight mb-8">
15
+ The status quo<br />is broken.
16
+ </h2>
17
+ <div className="flex flex-col gap-4 text-left max-w-sm mx-auto">
18
+ {PAIN_POINTS.map((item, i) => (
19
+ <div key={i} className="flex items-center gap-3">
20
+ <span className="text-danger text-xl font-bold flex-shrink-0">✕</span>
21
+ <span className="text-gray-400 text-lg">{item}</span>
22
+ </div>
23
+ ))}
24
+ </div>
25
+ </div>
26
+ </div>
27
+ )
28
+ }
@@ -0,0 +1,50 @@
1
+ const VALUE_PROPS = [
2
+ {
3
+ icon: '⚡',
4
+ title: '{{valueProp0}}',
5
+ desc: 'Deep analysis and intelligence applied to your specific context.',
6
+ },
7
+ {
8
+ icon: '📬',
9
+ title: '{{valueProp1}}',
10
+ desc: 'Tailored precisely to your goals — never a one-size-fits-all approach.',
11
+ },
12
+ {
13
+ icon: '🛡',
14
+ title: '{{valueProp2}}',
15
+ desc: 'Delivered reliably and safely, every single time.',
16
+ },
17
+ ]
18
+
19
+ export default function ValueProps({ style }) {
20
+ return (
21
+ <div className="scene-section" style={style}>
22
+ <div className="max-w-4xl px-8 w-full">
23
+ <p className="text-success text-sm font-semibold tracking-widest uppercase mb-4 text-center">
24
+ Why {{brand}}
25
+ </p>
26
+ <h2 className="text-4xl md:text-5xl font-extrabold text-white text-center mb-12">
27
+ Built to{' '}
28
+ <span className="text-success">actually work.</span>
29
+ </h2>
30
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
31
+ {VALUE_PROPS.map((v, i) => (
32
+ <div
33
+ key={i}
34
+ className="rounded-2xl p-6"
35
+ style={{
36
+ background: 'rgba(10,10,20,0.7)',
37
+ border: '1px solid rgba(16,185,129,0.2)',
38
+ backdropFilter: 'blur(12px)',
39
+ }}
40
+ >
41
+ <div className="text-3xl mb-3">{v.icon}</div>
42
+ <h3 className="text-white font-bold text-lg mb-2">{v.title}</h3>
43
+ <p className="text-gray-400 text-sm leading-relaxed">{v.desc}</p>
44
+ </div>
45
+ ))}
46
+ </div>
47
+ </div>
48
+ </div>
49
+ )
50
+ }
@@ -0,0 +1,21 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ['./index.html', './src/**/*.{js,jsx}'],
4
+ theme: {
5
+ extend: {
6
+ colors: {
7
+ void: '{{palette.background}}',
8
+ accent: '{{palette.accent}}',
9
+ glow: '{{palette.accent}}cc',
10
+ cyan: '#22D3EE',
11
+ success: '#10B981',
12
+ danger: '#EF4444',
13
+ node: '#2A2A3A',
14
+ },
15
+ fontFamily: {
16
+ sans: ['{{typography.heading0}}', 'system-ui', 'sans-serif'],
17
+ },
18
+ },
19
+ },
20
+ plugins: [],
21
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ })