diff --git a/apps/web/features/landing/components/multica-landing.tsx b/apps/web/features/landing/components/multica-landing.tsx index c7759b88..cc90b26c 100644 --- a/apps/web/features/landing/components/multica-landing.tsx +++ b/apps/web/features/landing/components/multica-landing.tsx @@ -74,7 +74,21 @@ export function MulticaLanding() { -
+
+ Works with +
+
+ + Claude Code +
+
+ + Codex +
+
+
+ +
@@ -82,6 +96,10 @@ export function MulticaLanding() {
+ + + + ); } @@ -310,6 +328,511 @@ function FeaturesSection() { ); } +/* -------------------------------------------------------------------------- */ +/* How it Works Section */ +/* -------------------------------------------------------------------------- */ + +const steps = [ + { + number: "01", + title: "Sign up & create your workspace", + description: + "Enter your email, verify with a code, and you're in. Your workspace is created automatically — no setup wizard, no configuration forms.", + }, + { + number: "02", + title: "Install the CLI & connect your machine", + description: + "Run multica login to authenticate, then multica daemon start. The daemon auto-detects Claude Code and Codex on your machine — plug in and go.", + }, + { + number: "03", + title: "Create your first agent", + description: + "Give it a name, write instructions, attach skills, and set triggers. Choose when it activates: on assignment, on comment, or on mention.", + }, + { + number: "04", + title: "Assign an issue and watch it work", + description: + "Pick your agent from the assignee dropdown — just like assigning to a teammate. The task is queued, claimed, and executed automatically. Watch progress in real time.", + }, +]; + +function HowItWorksSection() { + return ( +
+
+

+ Get started +

+

+ Hire your first AI employee +
+ in the next hour. +

+ +
+ {steps.map((step) => ( +
+ + {step.number} + +

+ {step.title} +

+

+ {step.description} +

+
+ ))} +
+ +
+ + Get started + + + + View on GitHub + +
+
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Open Source Section */ +/* -------------------------------------------------------------------------- */ + +const openSourceHighlights = [ + { + title: "Self-host anywhere", + description: + "Run Multica on your own infrastructure. Docker Compose, single binary, or Kubernetes — your data never leaves your network.", + }, + { + title: "No vendor lock-in", + description: + "Bring your own LLM provider, swap agent backends, extend the API. You own the stack, top to bottom.", + }, + { + title: "Transparent by default", + description: + "Every line of code is auditable. See exactly how your agents make decisions, how tasks are routed, and where your data flows.", + }, + { + title: "Community-driven", + description: + "Built with the community, not just for it. Contribute skills, integrations, and agent backends that benefit everyone.", + }, +]; + +function OpenSourceSection() { + return ( +
+
+
+ {/* Left column — heading + CTA */} +
+

+ Open source +

+

+ Open source +
+ for all. +

+

+ Multica is fully open source under the MIT license. Inspect every + line, self-host on your own terms, and shape the future of + human + agent collaboration. +

+
+ + + Star on GitHub + +
+
+ + {/* Right column — highlight grid */} +
+
+ {openSourceHighlights.map((item) => ( +
+

+ {item.title} +

+

+ {item.description} +

+
+ ))} +
+
+
+
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* FAQ Section */ +/* -------------------------------------------------------------------------- */ + +const faqs = [ + { + question: "What coding agents does Multica support?", + answer: + "Multica currently supports Claude Code and OpenAI Codex out of the box. The daemon auto-detects whichever CLIs you have installed. More backends are on the roadmap — and since it's open source, you can add your own.", + }, + { + question: "Do I need to self-host, or is there a cloud version?", + answer: + "Both. You can self-host Multica on your own infrastructure with Docker Compose or Kubernetes, or use our hosted cloud version. Your data, your choice.", + }, + { + question: "How is this different from just using Claude Code or Codex directly?", + answer: + "Coding agents are great at executing. Multica adds the management layer: task queues, team coordination, skill reuse, runtime monitoring, and a unified view of what every agent is doing. Think of it as the project manager for your agents.", + }, + { + question: "Can agents work on long-running tasks autonomously?", + answer: + "Yes. Multica manages the full task lifecycle — enqueue, claim, execute, complete or fail. Agents report blockers proactively and stream progress in real time. You can check in whenever you want or let them run overnight.", + }, + { + question: "Is my code safe? Where does agent execution happen?", + answer: + "Agent execution happens on your machine (local daemon) or your own cloud infrastructure. Code never passes through Multica servers. The platform only coordinates task state and broadcasts events.", + }, + { + question: "How many agents can I run?", + answer: + "As many as your hardware supports. Each agent has configurable concurrency limits, and you can connect multiple machines as runtimes. There are no artificial caps in the open source version.", + }, +]; + +function FAQSection() { + const [openIndex, setOpenIndex] = useState(null); + + return ( +
+
+
+

+ FAQ +

+

+ Questions & answers. +

+
+ +
+ {faqs.map((faq, i) => ( +
+ +
+
+

+ {faq.answer} +

+
+
+
+ ))} +
+
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Footer */ +/* -------------------------------------------------------------------------- */ + +const footerLinks = { + Product: [ + { label: "Features", href: "#features" }, + { label: "How it Works", href: "#how-it-works" }, + { label: "Pricing", href: "#" }, + { label: "Changelog", href: "#" }, + ], + Resources: [ + { label: "Documentation", href: "#" }, + { label: "API Reference", href: "#" }, + { label: "Blog", href: "#" }, + { label: "Community", href: "#" }, + ], + Company: [ + { label: "About", href: "#" }, + { label: "Open Source", href: "#open-source" }, + { label: "GitHub", href: githubUrl }, + { label: "Contact", href: "#" }, + ], + Legal: [ + { label: "Privacy Policy", href: "#" }, + { label: "Terms of Service", href: "#" }, + { label: "MIT License", href: `${githubUrl}/blob/main/LICENSE` }, + ], +}; + +function LandingFooter() { + return ( +
+
+ {/* Top: CTA + link columns */} +
+ {/* Left — newsletter / CTA */} +
+ + + + multica + + +

+ Project management for human + agent teams. Open source, self-hostable, built for the future of work. +

+
+ + Get started + +
+
+ + {/* Right — link columns */} +
+ {Object.entries(footerLinks).map(([group, links]) => ( +
+

+ {group} +

+
    + {links.map((link) => ( +
  • + + {link.label} + +
  • + ))} +
+
+ ))} +
+
+ + {/* Bottom: copyright + legal */} +
+

+ © {new Date().getFullYear()} Multica. All rights reserved. +

+
+ + {/* Giant logo + Game of Life */} +
+
+ + + multica + +
+
+ +
+
+
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Game of Life */ +/* -------------------------------------------------------------------------- */ + +function GameOfLife() { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + const cellSize = 10; + let cols = 0; + let rows = 0; + let grid: boolean[][] = []; + + function resize() { + const dpr = window.devicePixelRatio || 1; + const rect = canvas!.getBoundingClientRect(); + canvas!.width = rect.width * dpr; + canvas!.height = rect.height * dpr; + ctx!.setTransform(dpr, 0, 0, dpr, 0, 0); + + const newCols = Math.ceil(rect.width / cellSize); + const newRows = Math.ceil(rect.height / cellSize); + + if (newCols !== cols || newRows !== rows) { + cols = newCols; + rows = newRows; + grid = initGrid(cols, rows); + } + } + + function initGrid(c: number, r: number): boolean[][] { + return Array.from({ length: c }, () => + Array.from({ length: r }, () => Math.random() < 0.3), + ); + } + + function step() { + const next: boolean[][] = Array.from({ length: cols }, () => + Array(rows).fill(false), + ); + for (let x = 0; x < cols; x++) { + for (let y = 0; y < rows; y++) { + let neighbors = 0; + for (let dx = -1; dx <= 1; dx++) { + for (let dy = -1; dy <= 1; dy++) { + if (dx === 0 && dy === 0) continue; + const nx = x + dx; + const ny = y + dy; + if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && grid[nx]?.[ny]) { + neighbors++; + } + } + } + if (grid[x]?.[y]) { + next[x]![y] = neighbors === 2 || neighbors === 3; + } else { + next[x]![y] = neighbors === 3; + } + } + } + grid = next; + } + + function draw() { + const rect = canvas!.getBoundingClientRect(); + ctx!.clearRect(0, 0, rect.width, rect.height); + for (let x = 0; x < cols; x++) { + for (let y = 0; y < rows; y++) { + if (grid[x]?.[y]) { + ctx!.fillStyle = "rgba(10, 13, 18, 0.12)"; + ctx!.beginPath(); + ctx!.arc( + x * cellSize + cellSize / 2, + y * cellSize + cellSize / 2, + 3, + 0, + Math.PI * 2, + ); + ctx!.fill(); + } + } + } + } + + resize(); + + let frame: number; + let lastStep = 0; + const interval = 300; + + function loop(time: number) { + if (time - lastStep > interval) { + step(); + draw(); + lastStep = time; + } + frame = requestAnimationFrame(loop); + } + + draw(); + frame = requestAnimationFrame(loop); + + const onResize = () => resize(); + window.addEventListener("resize", onResize); + + return () => { + cancelAnimationFrame(frame); + window.removeEventListener("resize", onResize); + }; + }, []); + + return ( + + ); +} + /* -------------------------------------------------------------------------- */ /* Shared components */ /* -------------------------------------------------------------------------- */ @@ -362,6 +885,32 @@ function ImageIcon({ className }: { className?: string }) { } +function ClaudeCodeLogo({ className }: { className?: string }) { + return ( + + ); +} + +function CodexLogo({ className }: { className?: string }) { + return ( + + ); +} + function ProductImage() { return (