diff --git a/.gitignore b/.gitignore index 9d0e020..31df85f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ config.toml # AI code assistants .claude/ + + +# Website +.astro/ diff --git a/website/astro.config.mjs b/website/astro.config.mjs new file mode 100644 index 0000000..afda615 --- /dev/null +++ b/website/astro.config.mjs @@ -0,0 +1,48 @@ +// @ts-check +import { defineConfig } from "astro/config"; +import starlight from "@astrojs/starlight"; +import tailwindcss from "@tailwindcss/vite"; + +// https://astro.build/config +export default defineConfig({ + site: "https://cuttlekit.dev", + image: { + service: { + entrypoint: "astro/assets/services/noop", + }, + }, + vite: { + plugins: [tailwindcss()], + }, + integrations: [ + starlight({ + title: "cuttlekit", + logo: { + src: "./src/assets/logo-text-2.svg", + replacesTitle: true, + }, + social: [ + { + icon: "github", + label: "GitHub", + href: "https://github.com/betalyra/cuttlekit", + }, + { + icon: "discord", + label: "Discord", + href: "https://discord.gg/ebtwHGcyXR", + }, + ], + sidebar: [ + { + label: "Getting Started", + items: [ + { label: "Introduction", slug: "introduction" }, + ], + }, + ], + customCss: ["./src/styles/global.css"], + disable404Route: true, + }), + ], +}); diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000..9f5fd56 --- /dev/null +++ b/website/package.json @@ -0,0 +1,25 @@ +{ + "name": "@cuttlekit/website", + "type": "module", + "version": "0.0.1", + "engines": { + "node": ">=22.12.0" + }, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/mdx": "^5.0.0", + "@astrojs/starlight": "^0.38.1", + "@fontsource/bangers": "^5.2.8", + "@fontsource/kalam": "^5.2.8", + "@fontsource/space-grotesk": "^5.2.10", + "@tailwindcss/vite": "^4.2.1", + "astro": "^6.0.4", + "react-icons": "^5.6.0", + "tailwindcss": "^4.2.1" + } +} diff --git a/website/public/android-chrome-192x192.png b/website/public/android-chrome-192x192.png new file mode 100644 index 0000000..a208692 Binary files /dev/null and b/website/public/android-chrome-192x192.png differ diff --git a/website/public/android-chrome-512x512.png b/website/public/android-chrome-512x512.png new file mode 100644 index 0000000..dca99ef Binary files /dev/null and b/website/public/android-chrome-512x512.png differ diff --git a/website/public/apple-touch-icon.png b/website/public/apple-touch-icon.png new file mode 100644 index 0000000..df9bd1d Binary files /dev/null and b/website/public/apple-touch-icon.png differ diff --git a/website/public/favicon-16x16.png b/website/public/favicon-16x16.png new file mode 100644 index 0000000..e33a194 Binary files /dev/null and b/website/public/favicon-16x16.png differ diff --git a/website/public/favicon-32x32.png b/website/public/favicon-32x32.png new file mode 100644 index 0000000..e80d500 Binary files /dev/null and b/website/public/favicon-32x32.png differ diff --git a/website/public/favicon.ico b/website/public/favicon.ico new file mode 100644 index 0000000..95759ef Binary files /dev/null and b/website/public/favicon.ico differ diff --git a/website/public/site.webmanifest b/website/public/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/website/public/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/website/src/assets/favicon/android-chrome-192x192.png b/website/src/assets/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..a208692 Binary files /dev/null and b/website/src/assets/favicon/android-chrome-192x192.png differ diff --git a/website/src/assets/favicon/android-chrome-512x512.png b/website/src/assets/favicon/android-chrome-512x512.png new file mode 100644 index 0000000..dca99ef Binary files /dev/null and b/website/src/assets/favicon/android-chrome-512x512.png differ diff --git a/website/src/assets/favicon/apple-touch-icon.png b/website/src/assets/favicon/apple-touch-icon.png new file mode 100644 index 0000000..df9bd1d Binary files /dev/null and b/website/src/assets/favicon/apple-touch-icon.png differ diff --git a/website/src/assets/favicon/favicon-16x16.png b/website/src/assets/favicon/favicon-16x16.png new file mode 100644 index 0000000..e33a194 Binary files /dev/null and b/website/src/assets/favicon/favicon-16x16.png differ diff --git a/website/src/assets/favicon/favicon-32x32.png b/website/src/assets/favicon/favicon-32x32.png new file mode 100644 index 0000000..e80d500 Binary files /dev/null and b/website/src/assets/favicon/favicon-32x32.png differ diff --git a/website/src/assets/favicon/favicon.ico b/website/src/assets/favicon/favicon.ico new file mode 100644 index 0000000..95759ef Binary files /dev/null and b/website/src/assets/favicon/favicon.ico differ diff --git a/website/src/assets/favicon/site.webmanifest b/website/src/assets/favicon/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/website/src/assets/favicon/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/website/src/assets/logo-cuttlefish.svg b/website/src/assets/logo-cuttlefish.svg new file mode 100644 index 0000000..e32696b --- /dev/null +++ b/website/src/assets/logo-cuttlefish.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/assets/logo-dark.svg b/website/src/assets/logo-dark.svg new file mode 100644 index 0000000..9cff264 --- /dev/null +++ b/website/src/assets/logo-dark.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/assets/logo-text-2.png b/website/src/assets/logo-text-2.png new file mode 100644 index 0000000..692c89b Binary files /dev/null and b/website/src/assets/logo-text-2.png differ diff --git a/website/src/assets/logo-text-2.svg b/website/src/assets/logo-text-2.svg new file mode 100644 index 0000000..b426bbf --- /dev/null +++ b/website/src/assets/logo-text-2.svg @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/assets/logo-text.svg b/website/src/assets/logo-text.svg new file mode 100644 index 0000000..b022e30 --- /dev/null +++ b/website/src/assets/logo-text.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/assets/logo.svg b/website/src/assets/logo.svg new file mode 100644 index 0000000..e32696b --- /dev/null +++ b/website/src/assets/logo.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/components/CuttlefishLogo.astro b/website/src/components/CuttlefishLogo.astro new file mode 100644 index 0000000..a8743cd --- /dev/null +++ b/website/src/components/CuttlefishLogo.astro @@ -0,0 +1,181 @@ +--- +interface Props { + class?: string; +} +const { class: className = '' } = Astro.props; +--- + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/website/src/components/ShowcaseDemo.astro b/website/src/components/ShowcaseDemo.astro new file mode 100644 index 0000000..e87662c --- /dev/null +++ b/website/src/components/ShowcaseDemo.astro @@ -0,0 +1,466 @@ +--- +interface Prompt { + text: string; + rotate: string; +} + +const prompts: Prompt[] = [ + { text: "build me a landing page", rotate: "-rotate-1" }, + { text: "switch to brutalist style", rotate: "rotate-[0.5deg]" }, + { text: "create an ad visual", rotate: "-rotate-[0.5deg]" }, + { text: "add a dark mode toggle", rotate: "rotate-1" }, + { text: "show my Notion data as charts", rotate: "-rotate-[1.5deg]" }, + { text: "make it mobile-friendly", rotate: "rotate-[0.8deg]" }, +]; +--- + +
+

+ TRY IMAGINING THIS +

+ + +
+ +
+
+
+
+ localhost:5173 +
+ + +
+ + +
+
+
Sales Dashboard
+
Jan — Feb 2026
+
+
+
+
Total Bookings
+
€438,200
+
+21.4%
+
+
+
Current MRR
+
€168,400
+
+14.2%
+
+
+
Expansion
+
27%
+
High
+
+
+
+
+
Customer Segments
+
+
Scale-ups 46%
+
Startups 34%
+
Enterprise 20%
+
+
+
+
Geographic Mix
+
+
EU & UK 56%
+
North America 32%
+
Other 12%
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+
Send
+
+
+ + +
+ {prompts.map((p) => ( + + ))} +
+
+ + + + diff --git a/website/src/content.config.ts b/website/src/content.config.ts new file mode 100644 index 0000000..43fb7a6 --- /dev/null +++ b/website/src/content.config.ts @@ -0,0 +1,10 @@ +import { defineCollection } from "astro:content"; +import { docsLoader } from "@astrojs/starlight/loaders"; +import { docsSchema } from "@astrojs/starlight/schema"; + +export const collections = { + docs: defineCollection({ + loader: docsLoader(), + schema: docsSchema(), + }), +}; diff --git a/website/src/content/docs/introduction.mdx b/website/src/content/docs/introduction.mdx new file mode 100644 index 0000000..a92d271 --- /dev/null +++ b/website/src/content/docs/introduction.mdx @@ -0,0 +1,101 @@ +--- +title: Introduction +description: Get started with cuttlekit — a generative UI toolkit that creates interactive UIs on the fly using LLMs. +--- + +cuttlekit is a generative UI toolkit that turns natural language into fully interactive user interfaces. Describe what you need, and an LLM builds it — live in your browser, no code required on your end. + +No templates. No generated JavaScript. No framework lock-in. Just working HTML + CSS streaming to the browser in real-time. + +## What can it do? + +- 💬 **Describe → UI** — say what you want, get a working interface +- ⚡ **Real-time streaming** — watch it build live in the browser +- 🖱️ **Fully interactive** — buttons, forms, drag & drop — all work +- 🔄 **Iterate by talking** — refine by describing changes +- 🔌 **API integrations** — connect to Linear, Notion, and more +- 🤖 **Multi-model** — Gemini, Groq, or any OpenAI-compatible provider +- 🧠 **Memory** — remembers past interactions across sessions + +## How it works + +
+
+
YOU
+
"build me a sales dashboard"
+
+ TYPE + CLICK + DRAG +
+
+ +
+
+ PROMPT + +
+
+ + HTML +
+
+ ACTION + +
+
+ +
+
AI
+
generates a working UI
+
+ HTML + CSS + LIVE +
+
+
+ +
the loop keeps going — you refine, the AI adapts
+ +Every click, form submission, or drag action is sent to the server. The LLM sees the current page state and generates minimal CSS-selector patches — no full-page re-renders for small changes. + +## Quick start + +### Running locally + +```bash +git clone https://github.com/betalyra/cuttlekit.git +cd cuttlekit +pnpm install +``` + +Configure your environment: + +```bash +cp .env.example .env # add your API keys +cp config.example.toml config.toml +``` + +You'll need at least one model provider API key in `.env`. The easiest way to get started is with [Google AI Studio](https://aistudio.google.com/) — the Gemini API is free to use. + +Then start both servers: + +```bash +pnpm run dev:backend # terminal 1 +pnpm run dev:webpage # terminal 2 +``` + +Open [http://localhost:5173](http://localhost:5173) and start describing UIs. + +### Running with Docker + +```bash +git clone https://github.com/betalyra/cuttlekit.git +cd cuttlekit +cp .env.example .env # add your API keys +cp config.example.toml config.toml +docker compose up --build +``` + +Open [http://localhost:34513](http://localhost:34513) and you're ready to go. diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro new file mode 100644 index 0000000..d495994 --- /dev/null +++ b/website/src/pages/index.astro @@ -0,0 +1,449 @@ +--- +import ShowcaseDemo from '../components/ShowcaseDemo.astro'; +import CuttlefishLogo from '../components/CuttlefishLogo.astro'; +import '../styles/global.css'; +import logoText from '../assets/logo-text-2.svg'; +--- + + + + + + + + + + + + + cuttlekit — generative UI toolkit + + + + +
+ +
+ + +
+
+
+
+
+
+
+ + + + + +
+
+
+
EXPERIMENTAL
+ +

+ TALK TO IT. + IT BUILDS + YOUR UI. +

+ +

+ You type what you want. An LLM generates a working UI. Clicks, forms, drag‑and‑drop — all functional, no code on your end. +

+ + +
+ + + +
+
+
+ + +
+ + +
+
+
+

+ WHAT IS THIS? +

+

+ A generative UI toolkit that wires LLMs to a browser. You describe a UI, it builds one. Every button works, every form submits. +

+ + +
+ +
+
01
+
+

"Build me a project dashboard with task tracking"

+
+
+

JUST DESCRIBE IT

+

Plain language in, working interface out.

+
+ + +
+
02
+
+
+
+
+
+
+
+
+
+
+

WATCH IT APPEAR

+

HTML appears as the LLM writes it. You see your UI take shape in real‑time.

+
+ + +
+
03
+
+
CLICK
+
DRAG
+
TYPE
+
+

FULLY INTERACTIVE

+

Not a static mockup. Server handles every interaction — zero JavaScript in the generated output.

+
+ + +
+
04
+
+

"Make the sidebar wider. Add a dark mode."

+
+
+

ITERATE NATURALLY

+

Refine by talking. The LLM sees what's on screen and updates it.

+
+
+
+
+ + +
+
+

+ HOW IT WORKS +

+ + +
+ +
+ +
+ +
+
YOU
+

"build me a sales dashboard"

+
+ TYPE + CLICK + DRAG +
+
+ + + + +
+
+ PROMPT + +
+
+ + HTML +
+
+ + +
+
AI
+

generates a working UI

+
+ HTML + CSS + LIVE +
+
+
+ + +
+

the loop keeps going — you refine, the AI adapts. like a cuttlefish changing shape.

+
+
+
+
+ + +
+ +
+
+
+
+
+ + +
+ + +
+ + +
+
+
+

+ UNDER THE HOOD +

+ +
+ +
+

INSTANT UPDATES

+

No build step, no deployment. Describe a change and it just runs — right in the browser.

+
+ +
+

IT REMEMBERS YOU

+

Vector-based memory across sessions. Knows what you built before and how you like things.

+
+ +
+

CONNECTS TO APIs

+

Connect to Linear, Notion, or any external API. Fast code execution in secure sandboxes.

+
+ +
+

PICK YOUR MODEL

+

Use with any model provider. Gemini, Groq, OpenAI, or bring your own.

+
+ +
+

WORKS EVERYWHERE

+

Output is plain HTML + CSS. No React, no Vue, no build step for generated content.

+
+ +
+

SOURCE AVAILABLE

+

Free for personal and internal use. Commercial license if you're offering it as a hosted service.

+
+ +
+
+
+ + +
+ + +
+
+

+ GET STARTED +

+
+
+
QUICK START
+
$ git clone https://github.com/betalyra/cuttlekit.git
+
+$ pnpm install
+$ cp .env.example .env       # configure your API keys
+$ cp config.example.toml config.toml  # cp configuration or edit
+$ pnpm run dev:backend & pnpm run dev:webpage
+
+
+ + + + + + + + + diff --git a/website/src/styles/global.css b/website/src/styles/global.css new file mode 100644 index 0000000..58bf384 --- /dev/null +++ b/website/src/styles/global.css @@ -0,0 +1,52 @@ +@import "tailwindcss"; +@import "@fontsource/space-grotesk/400.css"; +@import "@fontsource/space-grotesk/500.css"; +@import "@fontsource/space-grotesk/700.css"; +@import "@fontsource/bangers/400.css"; +@import "@fontsource/kalam/400.css"; +@import "@fontsource/kalam/700.css"; + +@theme { + --font-sans: "Space Grotesk", system-ui, sans-serif; + --font-display: "Bangers", cursive; + --font-handwritten: "Kalam", cursive; + + --color-teal: #2dd4bf; + --color-slate-dark: #475569; + --color-pink-pop: #ec4899; + --color-cyan-pop: #22d3ee; + --color-purple-pop: #d946ef; + --color-amber-pop: #f59e0b; + --color-ink: #0f172a; + --color-paper: #fafaf9; +} + +/* Override Starlight theme to match cuttlekit branding */ +:root { + --sl-font: "Space Grotesk", system-ui, sans-serif; + --sl-color-accent-low: #134e4a; + --sl-color-accent: #2dd4bf; + --sl-color-accent-high: #ccfbf1; + --sl-color-white: #fafaf9; + --sl-color-gray-1: #e2e8f0; + --sl-color-gray-2: #94a3b8; + --sl-color-gray-3: #64748b; + --sl-color-gray-4: #334155; + --sl-color-gray-5: #1e293b; + --sl-color-gray-6: #0f172a; + --sl-color-black: #020617; +} + +:root[data-theme="light"] { + --sl-color-accent-low: #ccfbf1; + --sl-color-accent: #0d9488; + --sl-color-accent-high: #134e4a; + --sl-color-white: #020617; + --sl-color-gray-1: #1e293b; + --sl-color-gray-2: #334155; + --sl-color-gray-3: #64748b; + --sl-color-gray-4: #94a3b8; + --sl-color-gray-5: #e2e8f0; + --sl-color-gray-6: #f8fafc; + --sl-color-black: #fafaf9; +} diff --git a/website/tsconfig.json b/website/tsconfig.json new file mode 100644 index 0000000..8bf91d3 --- /dev/null +++ b/website/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +}