skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
reason-machines/design-skills103 installs

designmd-supply-generator

Generate DESIGN.md files from any website using Context.dev APIs for design tokens, brand data, and visual extraction

How do I install this agent skill?

npx skills add https://github.com/reason-machines/design-skills --skill designmd-supply-generator
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The skill is generally safe for its intended purpose of design documentation generation but lacks boundary markers when processing external website content, creating a risk for indirect prompt injection. It follows standard practices for handling API keys through environment variables.

  • Socketpass

    No alerts

  • Snykwarn

    Risk: MEDIUM · 2 issues

What does this agent skill do?

designmd-supply-generator

Skill by ara.so — Design Skills collection.

What It Does

designmd-supply is a Next.js application that transforms any website into a comprehensive DESIGN.md design system document. It orchestrates four Context.dev APIs (Styleguide, Brand, Screenshot, Markdown) and uses an LLM via Vercel AI Gateway to generate structured design documentation with YAML frontmatter covering colors, typography, layout, components, and brand guidelines.

The system caches all API responses and generated documents in Turso (libSQL) for fast subsequent access.

Installation

git clone https://github.com/context-dot-dev/designmd-supply.git
cd designmd-supply
npm install

Environment Setup

cp .env.example .env

Required variables in .env:

CONTEXT_DEV_API_KEY=your_context_dev_key
VERCEL_AI_GATEWAY_API_KEY=your_vercel_ai_key

# Optional: Turso cache (auto-injected on Vercel)
designmd_TURSO_DATABASE_URL=libsql://your-db.turso.io
designmd_TURSO_AUTH_TOKEN=your_turso_token

Get API keys:

Development

npm run dev
# Open http://localhost:3000

Core API Endpoints

1. Generate DESIGN.md

POST /api/design-md

// Request body
{
  "domain": "stripe.com"
}

// Response
{
  "markdown": "---\ntitle: Stripe Design System\n...",
  "cached": false
}

2. Get Cached Design Doc

GET /api/design-md?domain=stripe.com

Returns cached DESIGN.md if available, otherwise triggers generation.

3. Fetch Brand Data

GET /api/brand?domain=stripe.com

Returns Context.dev Brand API response (cached):

{
  "domain": "stripe.com",
  "name": "Stripe",
  "logo": "https://...",
  "colors": ["#635BFF", "#0A2540"],
  "industry": "Financial Technology"
}

4. Fetch Styleguide Tokens

GET /api/styleguide?domain=stripe.com

Returns design tokens (colors, typography, spacing, radii, components).

5. Get Screenshot

GET /api/screenshot?domain=stripe.com

Returns high-quality screenshot of homepage.

Usage Patterns

Basic: Generate Design Doc for a Domain

import { generateDesignMd } from '@/lib/design-md';

async function createDesignDoc(domain: string) {
  const result = await fetch('/api/design-md', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ domain })
  });
  
  const { markdown } = await result.json();
  return markdown;
}

// Usage
const designDoc = await createDesignDoc('figma.com');
console.log(designDoc);

Advanced: Use Context.dev APIs Directly

import { createContextClient } from 'context.dev';

const contextClient = createContextClient({
  apiKey: process.env.CONTEXT_DEV_API_KEY!
});

// Extract styleguide tokens
async function getDesignTokens(domain: string) {
  const styleguide = await contextClient.web.extractStyleguide({
    url: `https://${domain}`
  });
  
  return {
    colors: styleguide.colors,
    typography: styleguide.typography,
    spacing: styleguide.spacing,
    borderRadius: styleguide.borderRadius
  };
}

// Get brand intelligence
async function getBrandData(domain: string) {
  const brand = await contextClient.brand.retrieve({
    domain
  });
  
  return {
    name: brand.name,
    logo: brand.logo,
    colors: brand.colors,
    slogan: brand.slogan,
    industry: brand.industry
  };
}

Server-Side: Complete Pipeline

import { createContextClient } from 'context.dev';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';

export async function generateDesignMdFull(domain: string) {
  const client = createContextClient({
    apiKey: process.env.CONTEXT_DEV_API_KEY!
  });
  
  // Parallel fetch all Context.dev data
  const [styleguide, brand, screenshot, markdown] = await Promise.all([
    client.web.extractStyleguide({ url: `https://${domain}` }),
    client.brand.retrieve({ domain }),
    client.web.screenshot({ 
      url: `https://${domain}`,
      width: 1920,
      height: 1080
    }),
    client.web.webScrapeMd({ url: `https://${domain}` })
  ]);
  
  // Compose prompt
  const prompt = `Generate a DESIGN.md for ${domain}.
  
Styleguide tokens:
${JSON.stringify(styleguide, null, 2)}

Brand data:
${JSON.stringify(brand, null, 2)}

Page content:
${markdown.content}

Create comprehensive design system documentation with sections:
- Overview
- Colors
- Typography
- Layout & Spacing
- Components
- Do's and Don'ts`;

  // Generate with LLM
  const { text } = await generateText({
    model: openai('gpt-4o'),
    messages: [
      {
        role: 'user',
        content: [
          { type: 'text', text: prompt },
          { 
            type: 'image', 
            image: screenshot.base64,
            mimeType: 'image/png'
          }
        ]
      }
    ]
  });
  
  return text;
}

Turso Caching Integration

Cache Operations

import { getCached, setCached, listDomains } from '@/lib/turso';

// Read from cache
const cached = await getCached('stripe.com', 'designmd');
if (cached) {
  return JSON.parse(cached);
}

// Write to cache
await setCached('stripe.com', 'styleguide', JSON.stringify(styleguideData));
await setCached('stripe.com', 'brand', JSON.stringify(brandData));
await setCached('stripe.com', 'designmd', generatedMarkdown);

// List all cached domains
const domains = await listDomains();
// Returns: ['stripe.com', 'figma.com', ...]

Batch Read for Directory

import { getCachedBatch } from '@/lib/turso';

async function buildDirectory(domains: string[]) {
  const kinds = ['brand', 'screenshot'];
  const batch = await getCachedBatch(domains, kinds);
  
  return domains.map(domain => ({
    domain,
    brand: batch[domain]?.brand ? JSON.parse(batch[domain].brand) : null,
    screenshot: batch[domain]?.screenshot || null
  }));
}

Adding Domains to Directory

Edit lib/domains.ts:

export const TOP_DOMAINS = [
  'stripe.com',
  'figma.com',
  'linear.app',
  'notion.so',
  'vercel.com',
  // Add your domain here
  'yoursite.com'
];

The cache populates on first visit. Pre-render at build:

// app/guides/[domain]/page.tsx
export async function generateStaticParams() {
  const domains = await listDomains();
  return domains.map(domain => ({ domain }));
}

Component: Design Doc Display

'use client';

import { useEffect, useState } from 'react';
import ReactMarkdown from 'react-markdown';

export function DesignDocViewer({ domain }: { domain: string }) {
  const [markdown, setMarkdown] = useState('');
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    async function load() {
      const res = await fetch(`/api/design-md?domain=${domain}`);
      const data = await res.json();
      setMarkdown(data.markdown);
      setLoading(false);
    }
    load();
  }, [domain]);
  
  if (loading) return <div>Generating design system...</div>;
  
  return (
    <article className="prose prose-lg max-w-4xl">
      <ReactMarkdown>{markdown}</ReactMarkdown>
    </article>
  );
}

Common Workflows

1. Generate and Download Design Doc

async function downloadDesignMd(domain: string) {
  const res = await fetch('/api/design-md', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ domain })
  });
  
  const { markdown } = await res.json();
  
  const blob = new Blob([markdown], { type: 'text/markdown' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `${domain}-DESIGN.md`;
  a.click();
}

2. Search and Preview

'use client';

import { useState } from 'react';
import { useRouter } from 'next/navigation';

export function DomainSearch() {
  const [domain, setDomain] = useState('');
  const router = useRouter();
  
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const cleaned = domain.replace(/^https?:\/\//, '').split('/')[0];
    router.push(`/guides/${cleaned}`);
  };
  
  return (
    <form onSubmit={handleSubmit} className="flex gap-2">
      <input
        type="text"
        value={domain}
        onChange={(e) => setDomain(e.target.value)}
        placeholder="Enter domain (e.g., stripe.com)"
        className="flex-1 px-4 py-2 border rounded"
      />
      <button type="submit" className="px-6 py-2 bg-blue-600 text-white rounded">
        Generate
      </button>
    </form>
  );
}

3. Batch Generate for Multiple Domains

async function batchGenerate(domains: string[]) {
  const results = await Promise.allSettled(
    domains.map(domain =>
      fetch('/api/design-md', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ domain })
      }).then(r => r.json())
    )
  );
  
  return results.map((result, i) => ({
    domain: domains[i],
    success: result.status === 'fulfilled',
    markdown: result.status === 'fulfilled' ? result.value.markdown : null
  }));
}

Troubleshooting

Issue: API Rate Limits

Solution: Context.dev APIs have rate limits. Cache aggressively and use batch operations:

// Check cache first
const cached = await getCached(domain, 'styleguide');
if (cached) return JSON.parse(cached);

// Space out API calls
await new Promise(resolve => setTimeout(resolve, 1000));
const data = await contextClient.web.extractStyleguide({ url });

Issue: LLM Generation Timeout

Solution: Increase timeout for Vercel AI SDK:

const { text } = await generateText({
  model: openai('gpt-4o'),
  messages: [...],
  maxRetries: 3,
  abortSignal: AbortSignal.timeout(60000) // 60 seconds
});

Issue: Missing Turso Environment Variables

Symptom: Cache writes fail silently.

Solution: Verify environment variables are set:

if (!process.env.designmd_TURSO_DATABASE_URL) {
  console.warn('Turso not configured, cache disabled');
  return null; // Fallback to live API
}

Issue: Screenshot Too Large

Solution: Compress or reduce dimensions:

const screenshot = await client.web.screenshot({
  url: `https://${domain}`,
  width: 1280, // Reduce from 1920
  height: 720,  // Reduce from 1080
  format: 'jpeg', // Use JPEG instead of PNG
  quality: 80
});

Issue: Domain Not Resolving

Solution: Validate and normalize domain input:

function normalizeDomain(input: string): string {
  return input
    .replace(/^https?:\/\//, '')
    .replace(/^www\./, '')
    .split('/')[0]
    .toLowerCase()
    .trim();
}

Build and Deploy

npm run build
npm run start

Deploy to Vercel:

vercel

Turso integration auto-configures on Vercel Marketplace. For other platforms, manually set designmd_TURSO_DATABASE_URL and designmd_TURSO_AUTH_TOKEN.

Type Safety

// lib/types.ts
export interface DesignMdResponse {
  markdown: string;
  cached: boolean;
  domain: string;
  generatedAt?: string;
}

export interface StyleguideData {
  colors: Array<{ name: string; value: string; usage?: string }>;
  typography: Array<{ name: string; fontFamily: string; fontSize: string }>;
  spacing: Record<string, string>;
  borderRadius: Record<string, string>;
  components: Array<{ name: string; description: string }>;
}

export interface BrandData {
  domain: string;
  name: string;
  logo?: string;
  backdrop?: string;
  colors: string[];
  slogan?: string;
  industry?: string;
}

Performance Optimization

// Use React.cache for request deduplication
import { cache } from 'react';

export const getCachedDesignMd = cache(async (domain: string) => {
  const cached = await getCached(domain, 'designmd');
  if (cached) return cached;
  
  const generated = await generateDesignMdFull(domain);
  await setCached(domain, 'designmd', generated);
  return generated;
});

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/reason-machines/design-skills/designmd-supply-generator">View designmd-supply-generator on skillZs</a>