If you've ever asked Cursor or Claude to build a UI component and gotten back something that looks like a Bootstrap default from 2012, you know the pain. The AI generated functionally correct code, but the styling is generic, inconsistent, and miles away from the polished look you were going for.
The fix exists: feed your AI a DESIGN.md file that defines your exact colors, fonts, spacing, and layout rules. But until recently, the best tool for extracting these specs from any website relied on Context.dev—a paid API that recently locked free-tier access behind a subscription wall.
Open DesignMD solves this. It's a free, self-hosted fork that does the same job using open alternatives: Jina Reader for markdown extraction, Microlink for screenshots, and multi-provider LLM support via the Vercel AI SDK. No subscriptions, no API keys required for the extraction layer.
Why This Fork Exists
The original designmd.supply by Context.dev pioneered the concept of compiling live website telemetry into markdown-based design systems. It was brilliant—and free. Then Context.dev transitioned to a paid-only model, and the extraction pipeline started returning 502 errors for local deployments.
Rather than watch a great tool die behind a paywall, Open DesignMD was created to keep the concept alive. We swapped every proprietary endpoint for free, high-quality alternatives:
-
Context.dev API → Jina Reader (
r.jina.ai) for HTML-to-markdown conversion - Context.dev screenshots → Microlink API for full HD captures
- Context.dev LLM → OpenRouter, Ollama, Google, Anthropic, or standard OpenAI
The result: a tool that runs entirely on free APIs and your own LLM credits (or zero-cost local models via Ollama).
The Tech Stack Under the Hood
Open DesignMD is built on Next.js 16 with Tailwind CSS v4. The stack matters because it enables features that older frameworks would struggle with.
Next.js 16 + Turbopack
The app uses Next.js 16's App Router with Turbopack for fast development builds. The API route handler lives at app/api/design-md/route.ts and orchestrates the entire extraction pipeline.
Jina Reader: Free HTML-to-Markdown
Here's the core insight: you don't need a proprietary API to convert a webpage to clean markdown. Jina Reader does this for free. Send any URL to https://r.jina.ai/{url} and you get clean, LLM-friendly markdown back.
Target URL
│
├──► [Jina Reader] ──────► Clean Markdown
└──► [Microlink] ─────────► Full HD Screenshot
│
▼
[ Open DesignMD Backend ]
│
▼
[ LLM Analysis ]
│
▼
DESIGN.md
The free tier gives you 20 requests per minute without an API key, or 500 RPM with a free key. More than enough for extracting design specs from a handful of sites.
Multi-Provider LLM Support
The Vercel AI SDK lets you plug in almost any LLM provider. Open DesignMD supports:
- OpenRouter (DeepSeek-V3, Llama 3, Mixtral—often free or pennies per million tokens)
- Ollama (fully offline, zero cost)
- Google Gemini (free tier available)
- Anthropic Claude
- Standard OpenAI
The configuration lives in .env:
AI_PROVIDER=openrouter
AI_MODEL=deepseek/deepseek-chat
OPENROUTER_API_KEY=your_key_here
Or for local inference:
AI_PROVIDER=ollama
AI_MODEL=llama3
OLLAMA_BASE_URL=http://localhost:11434
The .chat() Fix: Solving a Vercel AI SDK 5+ Breaking Change
Here's a gotcha that will bite you if you're using the Vercel AI SDK 5+ with custom gateways or alternative providers. The newer SDK versions default to POSTing to OpenAI's /v1/responses endpoint. If you're routing through FreeLLMAPI, LiteLLM, or even OpenRouter, this causes a 404 Not Found because those gateways only support the traditional /v1/chat/completions endpoint.
The fix is deceptively simple. Instead of using the default createOpenAI client directly, you call the .chat(modelName) method:
import { createOpenAI } from "@ai-sdk/openai";
const openai = createOpenAI({
baseURL: process.env.AI_BASE_URL || "https://openrouter.ai/api/v1",
apiKey: process.env.AI_API_KEY,
compatibility: "compatible",
});
// Force /v1/chat/completions instead of /v1/responses
const model = openai.chat(process.env.AI_MODEL || "deepseek/deepseek-chat");
That .chat() call forces the SDK to use the traditional completions endpoint. Without it, any non-OpenAI gateway will fail silently or throw cryptic 404s.
Getting Started: One-Click Setup
Open DesignMD is designed for zero-friction local setup on Windows. The whole process takes about two minutes.
- Clone or download the repository:
git clone https://github.com/Yp-pro/open-designmd.git
Double-click
install.bat. This downloads a portable Node.js v20 runtime and installs dependencies without touching your global Node installation. Nonvm, nonpm install -g, no PATH modifications.Configure your LLM provider in
designmd-portable/app/.env(see examples above). If you're using OpenRouter, grab a free API key from their dashboard. For Ollama, just install Ollama and pull a model.Double-click
run.bat. The app starts onhttp://localhost:3000and opens your browser automatically.Paste any URL into the interface, click extract, and download your
DESIGN.md. The extraction takes 10-30 seconds depending on the site's complexity.
To clear cached data, there's a clear-cache.bat utility that wipes the local Turso cache instantly. This is useful when you want to re-extract a site after they've updated their design.
Using the Generated DESIGN.md
Once you have your DESIGN.md file, drop it into your project root (or wherever your AI agent reads context from). The key is making sure the AI can access it as context before generating components.
Here's a prompt template that works well with Cursor or Claude:
Read the DESIGN.md file in the project root.
Build a pricing card component using these exact design tokens:
colors, typography, spacing, shadows, and border-radius as defined in the spec.
Use Tailwind CSS classes that match the token values.
The AI will reference the design tokens and generate components that match the source website's visual language—not generic Bootstrap defaults. I've tested this with Cursor's inline completion and Claude's artifact mode, and both produce remarkably consistent results.
What makes this powerful is the specificity. Instead of telling the AI "make it look modern," you're giving it exact hex values, font weights, and spacing scales. The result is code that actually matches the design you're targeting.
Here's a simplified example of what the generated DESIGN.md might contain:
# Design System Specification
## Colors
- Primary: #2563EB (blue-600)
- Primary Dark: #1D4ED8 (blue-700)
- Background: #FFFFFF
- Surface: #F8FAFC (slate-50)
- Text Primary: #0F172A (slate-900)
- Text Secondary: #64748B (slate-500)
## Typography
- Font Family: Inter, system-ui, sans-serif
- Heading 1: 2.25rem / 700 / -0.025em tracking
- Heading 2: 1.875rem / 600 / -0.025em tracking
- Body: 1rem / 400 / normal
- Small: 0.875rem / 500
## Spacing Scale
- xs: 0.25rem (4px)
- sm: 0.5rem (8px)
- md: 1rem (16px)
- lg: 1.5rem (24px)
- xl: 2rem (32px)
## Border Radius
- sm: 0.375rem
- md: 0.5rem
- lg: 0.75rem
- full: 9999px
## Shadows
- sm: 0 1px 2px rgba(0,0,0,0.05)
- md: 0 4px 6px rgba(0,0,0,0.07)
- lg: 0 10px 15px rgba(0,0,0,0.1)
The Honest Trade-off
Open DesignMD isn't perfect. The original Context.dev API analyzed raw CSS stylesheets to extract exact variables—every custom property, every media query breakpoint, every animation timing function. Our approach uses Jina Reader's markdown output, then asks an LLM to infer and reconstruct the design tokens from structural content.
This works accurately for 95% of use cases—color palettes, typography scales, spacing patterns, and layout structures all extract cleanly. But it doesn't capture raw stylesheet variables. If a site uses CSS custom properties like --color-primary: #2563EB; in a way that's deeply nested in component-scoped styles, the LLM might infer the value correctly but won't preserve the original variable name.
For most AI coding workflows, the difference is negligible. When Cursor generates a button component, it doesn't care whether the primary color came from --color-primary or was inferred as #2563EB—it just needs the hex value. The LLM-inferred tokens are close enough that components render visually matching the source.
The trade-off is worth it: you get a completely free, self-hosted tool with multi-provider flexibility instead of a paid API dependency. If you need pixel-perfect CSS variable extraction, the original Context.dev API (now paid) might be worth the subscription. For everything else, this works.
What You Get
- Zero cost extraction using Jina Reader and Microlink
- Multi-provider LLM support (OpenRouter, Ollama, Gemini, Claude, OpenAI)
- Portable Windows setup with local Node.js runtime
-
Granular cache controls with
clear-cache.bat - Screenshot timing optimized for React/animations (3-second pause for hydration)
Try It Out
The repository is live on GitHub: Yp-pro/open-designmd
If this fork saves you time or replaces a paid subscription in your workflow, I'd appreciate a star on the repo. And if you find the original concept valuable, please star the upstream designmd.supply too—their pioneering work made this possible.
Got feedback, issues, or feature requests? Open an issue on GitHub or drop a comment below. The tool is actively maintained and I'm interested in real-world use cases. What sites are you extracting design tokens from? What LLM providers are you using? The more feedback, the better the tool gets.
One thing I've noticed in testing: the tool works particularly well with design-heavy sites like Stripe, Linear, and Vercel's marketing pages. These sites have clean, well-structured HTML that Jina Reader parses beautifully, and the resulting design tokens are remarkably accurate. Sites with heavy JavaScript rendering or canvas-based layouts are trickier, but still produce usable results.
Built with Next.js 16, Tailwind CSS v4, Vercel AI SDK, Jina Reader, and Microlink.
Top comments (0)