Files
vibn-frontend/justine/vibn-website.jsx
mawkone 99deb546c8 Rip out Theia, bump submodules, retire platform/ scaffold, snapshot docs + design assets
Theia rip-out (parent):
- Remove theia submodule entry (the local fork, Gitea repo, Coolify app,
  Cloud Run services, and Artifact Registry image are all gone)
- Drop README.md + INFRASTRUCTURE.md (obsolete "Project OS" snapshots
  that also leaked API tokens) and setup.sh (Theia clone bootstrap)
- Delete UI-DESIGN-GUIDE.md, BACKEND_AGENTS_PLAN.md, VIBN_BUILD_PLAN.md,
  VISUAL_EDITOR_PLAN.md, core-packages.md, ai-packages.md, tools-list.md
  (all 100% Theia-specific or superseded)
- Surgical scrubs of remaining Theia mentions in
  AGENT_EXECUTION_ARCHITECTURE.md and TURBOREPO_MIGRATION_PLAN.md

Submodule bumps:
- vibn-agent-runner: Theia rip-out + MCP refactor (api/wrapper/server
  pattern across shell/file/git/memory/prd/search/agent/gitea/coolify)
- vibn-frontend: Theia rip-out + P5.1 attach E2E + Justine UI WIP

Retire platform/ scaffold:
- Remove platform/backend/ (control-plane, executors, mcp-adapter),
  platform/client-ide/ (gcp-productos extension), platform/contracts/,
  platform/infra/terraform/, platform/scripts/templates/turborepo/
  (replaced by vibn-agent-runner + vibn-frontend + Coolify direct)
- Drop architecture.md, technical_spec.md, vision-ext.md,
  "1.Generate Control Plane API scaffold.md" (same era)

Docs / planning snapshots (new):
- AI_CAPABILITIES.md, AI_CAPABILITIES_ROADMAP.md
- AGENT_TELEMETRY_STREAMING_PROJECT.md
- VIBN_PRD.md, product-idea-a.md

Design assets (new):
- branding/{coolify,gitea,ux-testing}/ static brand collateral
- justine/ HTML mockups for the new onboarding/build flows
- preview-assist-ui/ Vite scratch app
- master-ai.code-workspace

Infra helpers (new):
- setup-coolify-montreal.sh provisioner
- gitea-docker-compose.yml
- vibn-coolify-schema.sql for the Coolify Postgres extensions
- prd-agent-prompt.pdf, prompt, root.txt, remixed-9edec9e9.tsx scratch
- flatten.sh helper

.gitignore: ignore **/node_modules, **/.next, **/.turbo, **/coverage

Made-with: Cursor
2026-04-22 18:06:37 -07:00

289 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// vibn — Marketing Website
// Design: Ink & parchment — Lora serif + Inter sans, no colour accent
// Usage: <Website onGetStarted={fn} onLogin={fn} />
import { useState } from "react";
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
};
const F = { serif: "'Lora', Georgia, serif", sans: "'Inter', sans-serif" };
// ─── Primitives ────────────────────────────────────────────────────────────────
function Eyebrow({ children }) {
return (
<div style={{ fontFamily: F.sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.13em", textTransform: "uppercase", color: T.muted, marginBottom: 16 }}>
{children}
</div>
);
}
function PrimaryBtn({ children, onClick, large }) {
return (
<button onClick={onClick} style={{
background: T.ink, color: T.paper, border: "none",
fontFamily: F.sans, fontWeight: 600,
fontSize: large ? 15 : 14,
padding: large ? "14px 34px" : "10px 24px",
borderRadius: 10, cursor: "pointer",
}}>{children}</button>
);
}
// ─── Nav ───────────────────────────────────────────────────────────────────────
function Nav({ onGetStarted, onLogin }) {
return (
<nav style={{
background: T.paper, borderBottom: `1px solid ${T.border}`,
padding: "0 48px", height: 60,
display: "flex", alignItems: "center", justifyContent: "space-between",
position: "sticky", top: 0, zIndex: 50,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 30, height: 30, background: T.ink, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.paper }}>V</span>
</div>
<span style={{ fontFamily: F.serif, fontSize: 19, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", gap: 32 }}>
{["Product", "Pricing", "Stories", "Blog"].map(l => (
<span key={l} style={{ fontFamily: F.sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>{l}</span>
))}
</div>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
<span onClick={onLogin} style={{ fontFamily: F.sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>Log in</span>
<PrimaryBtn onClick={onGetStarted}>Get started free</PrimaryBtn>
</div>
</nav>
);
}
// ─── Hero ──────────────────────────────────────────────────────────────────────
function Hero({ onCta }) {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "88px 48px 72px" }}>
<Eyebrow>For non-technical founders</Eyebrow>
<h1 style={{
fontFamily: F.serif, fontSize: 64, fontWeight: 700, color: T.ink,
letterSpacing: "-0.03em", lineHeight: 1.07, marginBottom: 28, maxWidth: 680,
}}>
You have the idea.<br />
We handle<br />
<em style={{ fontStyle: "italic", color: T.ink3 }}>everything else.</em>
</h1>
<p style={{ fontFamily: F.sans, fontSize: 17.5, color: T.mid, lineHeight: 1.75, maxWidth: 480, marginBottom: 40 }}>
No backend. No DevOps. No marketing agency. Describe your idea and vibn
builds, deploys, and promotes it automatically.
</p>
<div style={{ display: "flex", alignItems: "center", gap: 18, marginBottom: 14 }}>
<PrimaryBtn onClick={onCta} large>Start free no code needed</PrimaryBtn>
<span style={{ fontFamily: F.sans, fontSize: 13.5, color: T.stone }}>&nbsp;&nbsp;280 founders launched</span>
</div>
<p style={{ fontFamily: F.sans, fontSize: 12, color: T.stone }}>No credit card required · Free forever plan</p>
</section>
);
}
// ─── Quote band ────────────────────────────────────────────────────────────────
const QUOTES = [
{ q: "I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing.", by: "Alex K.", role: "Founder, Taskly" },
{ q: "I have zero coding experience. Three weeks in I have 300 paying users. That's entirely because of vibn.", by: "Marcus L.", role: "Founder, Flowmatic" },
{ q: "The marketing autopilot alone saved me ten hours a week. My blog runs itself. I just focus on my product.", by: "Sara R.", role: "Founder, Nudge" },
];
function QuoteBand() {
return (
<section style={{ background: T.ink, padding: "52px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 40 }}>
{QUOTES.map((q, i) => (
<div key={i} style={{ display: "flex", gap: 20 }}>
<div style={{ width: 3, background: T.mid, borderRadius: 2, flexShrink: 0 }} />
<div>
<p style={{ fontFamily: F.serif, fontSize: 15, color: T.parch, lineHeight: 1.72, fontStyle: "italic", marginBottom: 12 }}>"{q.q}"</p>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.muted, fontWeight: 600 }}> {q.by}, {q.role}</span>
</div>
</div>
))}
</div>
</section>
);
}
// ─── How it works ──────────────────────────────────────────────────────────────
const PHASES = [
{ n: "01", id: "Discover", title: "Define your idea", body: "Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon." },
{ n: "02", id: "Design", title: "Choose your style", body: "Pick a visual style and see your exact site and emails live before a single line of code is written." },
{ n: "03", id: "Build", title: "Your app, live", body: "AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English." },
{ n: "04", id: "Grow", title: "Market & automate", body: "AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on your users." },
];
function HowItWorks() {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "80px 48px" }}>
<Eyebrow>How it works</Eyebrow>
<h2 style={{ fontFamily: F.serif, fontSize: 40, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", lineHeight: 1.15, marginBottom: 52, maxWidth: 460 }}>
Four phases.<br />One complete product.
</h2>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{PHASES.map((p, i) => (
<div key={i} style={{
padding: "38px 42px", background: T.white,
borderRight: (i % 2 === 0) ? `1px solid ${T.border}` : "none",
borderBottom: (i < 2) ? `1px solid ${T.border}` : "none",
}}>
<div style={{ fontFamily: F.sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.1em", textTransform: "uppercase", color: T.muted, marginBottom: 14 }}>
{p.n} {p.id}
</div>
<div style={{ fontFamily: F.serif, fontSize: 21, fontWeight: 700, color: T.ink, marginBottom: 10 }}>{p.title}</div>
<p style={{ fontFamily: F.sans, fontSize: 13.5, color: T.mid, lineHeight: 1.7 }}>{p.body}</p>
</div>
))}
</div>
</section>
);
}
// ─── Stats bar ─────────────────────────────────────────────────────────────────
const STATS = [
{ n: "280+", label: "founders launched" },
{ n: "72h", label: "average time to first version" },
{ n: "4.9★", label: "average rating" },
{ n: "3×", label: "faster than hiring a developer" },
];
function StatsBar() {
return (
<section style={{ background: T.white, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}` }}>
<div style={{ maxWidth: 960, margin: "0 auto", padding: "0 48px", display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
{STATS.map((s, i) => (
<div key={i} style={{ padding: "38px 0", paddingLeft: i > 0 ? 36 : 0, borderRight: i < 3 ? `1px solid ${T.border}` : "none" }}>
<div style={{ fontFamily: F.serif, fontSize: 38, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", marginBottom: 6 }}>{s.n}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>{s.label}</div>
</div>
))}
</div>
</section>
);
}
// ─── Empathy section ───────────────────────────────────────────────────────────
const PAINS = [
{ title: "No more \"I need to hire a developer first\"", body: "vibn is your developer. Start building the moment you have an idea." },
{ title: "No more staring at a blank marketing calendar", body: "AI generates and publishes your content every single week." },
{ title: "No more \"I'll launch when it's ready\"", body: "Most founders ship their first version in under 72 hours." },
];
function EmpathySection() {
return (
<section style={{ background: T.cream, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}`, padding: "76px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 68, alignItems: "center" }}>
<div>
<Eyebrow>Sound familiar?</Eyebrow>
<h2 style={{ fontFamily: F.serif, fontSize: 36, fontWeight: 700, color: T.ink, lineHeight: 1.18, marginBottom: 24, letterSpacing: "-0.02em" }}>
The idea is the hard part. Everything else shouldn't be.
</h2>
<p style={{ fontFamily: F.sans, fontSize: 15, color: T.mid, lineHeight: 1.8, marginBottom: 20 }}>
You know exactly what you want to build and who it's for. But the moment you think
about servers, databases, deployment pipelines, SEO strategies the whole thing stalls.
</p>
<p style={{ fontFamily: F.sans, fontSize: 15, color: T.mid, lineHeight: 1.8 }}>
vibn exists to remove all of that. Not abstract it {" "}
<em style={{ fontFamily: F.serif, fontStyle: "italic" }}>remove it entirely.</em>
</p>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
{PAINS.map((p, i) => (
<div key={i} style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px", display: "flex", gap: 14, alignItems: "flex-start" }}>
<div style={{ width: 20, height: 20, borderRadius: "50%", border: `1.5px solid ${T.stone}`, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, marginTop: 2 }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink }} />
</div>
<div>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>{p.title}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.muted, lineHeight: 1.6 }}>{p.body}</div>
</div>
</div>
))}
</div>
</div>
</section>
);
}
// ─── Final CTA ─────────────────────────────────────────────────────────────────
function FinalCta({ onCta }) {
return (
<section style={{ maxWidth: 660, margin: "0 auto", padding: "92px 48px", textAlign: "center" }}>
<h2 style={{ fontFamily: F.serif, fontSize: 46, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", lineHeight: 1.1, marginBottom: 20 }}>
Your idea deserves to exist.
</h2>
<p style={{ fontFamily: F.sans, fontSize: 16, color: T.mid, lineHeight: 1.75, marginBottom: 36 }}>
Don't let the backend be the reason it doesn't. Start today free, no code, no credit card.
</p>
<PrimaryBtn onClick={onCta} large>Build my product free</PrimaryBtn>
<div style={{ fontFamily: F.sans, fontSize: 12.5, color: T.stone, marginTop: 16 }}>
Joins 280+ non-technical founders already live
</div>
</section>
);
}
// ─── Footer ────────────────────────────────────────────────────────────────────
function Footer() {
return (
<footer style={{ borderTop: `1px solid ${T.border}`, padding: "32px 48px", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.serif, fontSize: 16, fontWeight: 700, color: T.ink }}>vibn</span>
<div style={{ display: "flex", gap: 28 }}>
{["Product", "Pricing", "Stories", "Blog", "Privacy", "Terms"].map(l => (
<span key={l} style={{ fontFamily: F.sans, fontSize: 13, color: T.stone, cursor: "pointer" }}>{l}</span>
))}
</div>
<span style={{ fontFamily: F.sans, fontSize: 12.5, color: T.stone }}>© 2026 vibn</span>
</footer>
);
}
// ─── Root export ───────────────────────────────────────────────────────────────
export default function Website({ onGetStarted = () => {}, onLogin = () => {} }) {
return (
<div style={{ background: T.paper, color: T.ink, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Inter', sans-serif; }
button { font-family: inherit; }
`}</style>
<Nav onGetStarted={onGetStarted} onLogin={onLogin} />
<Hero onCta={onGetStarted} />
<QuoteBand />
<HowItWorks />
<StatsBar />
<EmpathySection />
<FinalCta onCta={onGetStarted} />
<Footer />
</div>
);
}