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.
- package/LICENSE +21 -0
- package/assets/CLAUDE.md +150 -0
- package/assets/presets/3d-immersive/README.md +30 -0
- package/assets/presets/3d-immersive/preset.json +45 -0
- package/assets/presets/antigravity-lift/README.md +24 -0
- package/assets/presets/antigravity-lift/preset.json +38 -0
- package/assets/presets/brutalist-signal/README.md +24 -0
- package/assets/presets/brutalist-signal/preset.json +36 -0
- package/assets/presets/midnight-luxe/README.md +24 -0
- package/assets/presets/midnight-luxe/preset.json +36 -0
- package/assets/presets/organic-tech/README.md +24 -0
- package/assets/presets/organic-tech/preset.json +37 -0
- package/assets/presets/vapor-clinic/README.md +24 -0
- package/assets/presets/vapor-clinic/preset.json +36 -0
- package/assets/prompts/product-development/Guided-MVP-Concept.md +67 -0
- package/assets/prompts/product-development/Guided-MVP.md +65 -0
- package/assets/prompts/product-development/Guided-PRD-Creation.md +51 -0
- package/assets/prompts/product-development/Guided-Test-Plan.md +57 -0
- package/assets/prompts/product-development/Guided-UX-User-Flow.md +93 -0
- package/assets/prompts/product-development/README.md +21 -0
- package/assets/prompts/product-development/v0-design-prompt.md +107 -0
- package/assets/templates/base-react/index.html +18 -0
- package/assets/templates/base-react/package.json +26 -0
- package/assets/templates/base-react/postcss.config.js +6 -0
- package/assets/templates/base-react/src/App.jsx +33 -0
- package/assets/templates/base-react/src/index.css +90 -0
- package/assets/templates/base-react/src/main.jsx +10 -0
- package/assets/templates/base-react/src/sections/Features.jsx +238 -0
- package/assets/templates/base-react/src/sections/Footer.jsx +120 -0
- package/assets/templates/base-react/src/sections/Hero.jsx +96 -0
- package/assets/templates/base-react/src/sections/Navbar.jsx +119 -0
- package/assets/templates/base-react/src/sections/Philosophy.jsx +67 -0
- package/assets/templates/base-react/src/sections/Pricing.jsx +135 -0
- package/assets/templates/base-react/src/sections/Protocol.jsx +123 -0
- package/assets/templates/base-react/tailwind.config.js +26 -0
- package/assets/templates/base-react/vite.config.js +6 -0
- package/assets/templates/three-fiber/eslint.config.js +21 -0
- package/assets/templates/three-fiber/index.html +16 -0
- package/assets/templates/three-fiber/package.json +36 -0
- package/assets/templates/three-fiber/postcss.config.js +6 -0
- package/assets/templates/three-fiber/src/App.jsx +61 -0
- package/assets/templates/three-fiber/src/components/CameraRig.jsx +42 -0
- package/assets/templates/three-fiber/src/components/NetworkGraph.jsx +120 -0
- package/assets/templates/three-fiber/src/components/ParticleSystem.jsx +77 -0
- package/assets/templates/three-fiber/src/components/Scene.jsx +39 -0
- package/assets/templates/three-fiber/src/components/SocialProofBillboards.jsx +56 -0
- package/assets/templates/three-fiber/src/context/SceneContext.jsx +21 -0
- package/assets/templates/three-fiber/src/index.css +37 -0
- package/assets/templates/three-fiber/src/main.jsx +21 -0
- package/assets/templates/three-fiber/src/sections/CTA.jsx +41 -0
- package/assets/templates/three-fiber/src/sections/Hero.jsx +66 -0
- package/assets/templates/three-fiber/src/sections/HowItWorks.jsx +55 -0
- package/assets/templates/three-fiber/src/sections/Navbar.jsx +40 -0
- package/assets/templates/three-fiber/src/sections/SocialProof.jsx +50 -0
- package/assets/templates/three-fiber/src/sections/TheOldWay.jsx +28 -0
- package/assets/templates/three-fiber/src/sections/ValueProps.jsx +50 -0
- package/assets/templates/three-fiber/tailwind.config.js +21 -0
- package/assets/templates/three-fiber/vite.config.js +7 -0
- package/dist/cli.js +539 -0
- package/dist/cli.js.map +1 -0
- 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
|
+
}
|