Files
crepes-demo/README.md
OpenClaw 9b750238c2
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Initial commit: json-render crepes demo
2026-02-09 07:30:54 +01:00

9.5 KiB

🥞 Les Crêpes de Maîtres

A beautiful demo showcasing json-render with French chef crêpe recipes. Features recipes from legendary chefs like Auguste Escoffier, Olivier Roellinger, Pierre Hermé, and Joël Robuchon.

🎯 What is json-render?

json-render is a library from Vercel Labs that enables AI-generated UIs with guardrailed components. It provides:

  • Guardrailed — AI can only use components in your catalog
  • Predictable — JSON output matches your schema, every time
  • Fast — Stream and render progressively as the model responds

This demo uses json-render's Renderer component with a type-safe catalog to render recipe specs as React components.

How It Works

  1. Define Component Catalog (lib/catalog.ts):

    export const catalog = defineCatalog(schema, {
      components: {
        RecipeHeader: {
          props: z.object({
            title: z.string(),
            chef: z.string(),
            // ...
          }),
          description: "Header with recipe info"
        },
        // ...
      }
    });
    
  2. Map to React Components (lib/registry.tsx):

    export const { registry } = defineRegistry(catalog, {
      components: {
        RecipeHeader: ({ props }) => (
          <div>
            <h1>{props.title}</h1>
            {/* ... */}
          </div>
        ),
        // ...
      }
    });
    
  3. Create JSON Specs (lib/recipes.ts):

    const recipe = {
      root: "root",
      elements: {
        root: {
          type: "RecipeCard",
          props: { title: "Crêpes Suzette", /* ... */ },
          children: ["chef", "header", "ingredients", /* ... */]
        },
        chef: {
          type: "ChefInfo",
          props: { name: "Auguste Escoffier", /* ... */ }
        },
        // ...
      }
    };
    
  4. Render with json-render (app/page.tsx):

    <Provider>
      <Renderer spec={recipe} registry={registry} />
    </Provider>
    

Result: AI-generated JSON specs become beautiful, type-safe React UIs!

🚀 Quick Start (Local Development)

# Install dependencies
npm install

# Run development server
npm run dev

# Open http://localhost:3000

🐳 Docker Build

# Build the image
docker build -t crepes-demo:latest .

# Run locally
docker run -p 3000:3000 crepes-demo:latest

☸️ Kubernetes Deployment with Flux

Prerequisites

  • Kubernetes cluster with Flux installed
  • Container registry (Docker Hub, GitHub Container Registry, etc.)
  • Domain configured with Cloudflare
  • Ingress controller (nginx, traefik, etc.)
  • cert-manager for TLS certificates
  • external-dns for automatic DNS records (optional)

Step 1: Build and Push Image

# Tag your image
docker tag crepes-demo:latest YOUR_REGISTRY/crepes-demo:latest

# Push to registry
docker push YOUR_REGISTRY/crepes-demo:latest

Step 2: Update Configuration

k8s/deployment.yaml:

  • Update image: with your registry URL

k8s/ingress.yaml:

  • Update all instances of crepes.yourdomain.com with your actual domain
  • Adjust ingressClassName if not using nginx
  • Verify cert-manager issuer name

flux/gitrepository.yaml:

  • Update Git repository URL with your fork

Step 3: Use the Deploy Script

cd /home/openclaw/.openclaw/workspace/crepes-demo

# Set your configuration
export REGISTRY="ghcr.io/YOUR_USERNAME"
export DOMAIN="crepes.yourdomain.com"

# Run deployment script
./deploy.sh $REGISTRY $DOMAIN

Step 4: Push to Git

# Initialize git repository
git init
git add .
git commit -m "Initial commit: json-render crêpes demo"

# Push to your GitHub repository
git remote add origin https://github.com/YOUR_USERNAME/crepes-demo.git
git push -u origin main

Step 5: Deploy Flux Resources

# Apply Flux GitRepository and Kustomization
kubectl apply -f flux/gitrepository.yaml
kubectl apply -f flux/kustomization.yaml

# Watch deployment
kubectl get kustomizations -n flux-system -w

Step 6: Verify Deployment

# Check pods
kubectl get pods -l app=crepes-demo

# Check service
kubectl get svc crepes-demo

# Check ingress
kubectl get ingress crepes-demo

# Check Flux sync status
flux get kustomizations

Step 7: Configure Cloudflare

If using external-dns with Cloudflare:

  1. DNS records should be created automatically
  2. Verify in Cloudflare dashboard
  3. Ensure SSL/TLS mode is "Full (strict)" or "Full"

If configuring manually:

  1. Create an A or CNAME record pointing to your ingress IP/hostname
  2. Enable Cloudflare proxy (orange cloud) for DDoS protection
  3. Configure SSL/TLS settings

🔄 Continuous Deployment

Flux will automatically:

  • Monitor your Git repository every 1 minute
  • Apply changes to the cluster
  • Check deployment health
  • Rollback on failures

To update the app:

# Make changes
git add .
git commit -m "Update recipe"
git push

# Flux will sync automatically, or force sync:
flux reconcile kustomization crepes-demo

🎨 Customization

Adding New Recipes

  1. Define your recipe spec in lib/recipes.ts:

    {
      root: "root",
      elements: {
        root: {
          type: "RecipeCard",
          props: { title: "My Recipe", /* ... */ },
          children: ["chef", "header", /* ... */]
        },
        // ... more elements
      }
    }
    
  2. The spec will be automatically rendered using the existing component catalog!

Adding New Components

  1. Update component schema in lib/catalog.ts:

    MyNewComponent: {
      props: z.object({
        myProp: z.string(),
      }),
      description: "My new component"
    }
    
  2. Add React implementation in lib/registry.tsx:

    MyNewComponent: ({ props }) => (
      <div>{props.myProp}</div>
    )
    
  3. Use in recipe specs with type: "MyNewComponent"

Styling

The app uses Tailwind CSS. Modify component styles in lib/registry.tsx or adjust the theme in tailwind.config.ts.

📚 Project Structure

crepes-demo/
├── app/
│   ├── page.tsx                    # Main page with Renderer
│   ├── layout.tsx                  # Root layout
│   └── globals.css                 # Global styles
├── lib/
│   ├── catalog.ts                  # json-render component catalog
│   ├── registry.tsx                # React component implementations + Provider
│   └── recipes.ts                  # Recipe JSON specs
├── k8s/
│   ├── deployment.yaml             # Kubernetes Deployment
│   ├── service.yaml                # Kubernetes Service
│   ├── ingress.yaml                # Kubernetes Ingress (Cloudflare)
│   └── kustomization.yaml          # Kustomize config
├── flux/
│   ├── gitrepository.yaml          # Flux GitRepository
│   └── kustomization.yaml          # Flux Kustomization
├── .github/workflows/
│   └── deploy.yml                  # GitHub Actions CI/CD
├── Dockerfile                      # Multi-stage Docker build
├── deploy.sh                       # Automated deployment script
├── README.md                       # Full documentation (this file)
└── QUICKSTART.md                   # Quick deployment guide

🔧 Troubleshooting

Pods not starting

kubectl describe pod -l app=crepes-demo
kubectl logs -l app=crepes-demo

Flux not syncing

flux logs
flux get sources git
flux get kustomizations

Certificate issues

kubectl describe certificate crepes-demo-tls
kubectl describe certificaterequest
kubectl logs -n cert-manager -l app=cert-manager

DNS not resolving

# Check external-dns logs
kubectl logs -n external-dns -l app=external-dns

# Verify ingress has external IP
kubectl get ingress crepes-demo

🌐 Architecture

User Request
    ↓
Cloudflare (CDN, DDoS protection, SSL)
    ↓
Ingress Controller (nginx)
    ↓
Kubernetes Service
    ↓
Deployment (2 replicas)
    ↓
Next.js App (json-render Renderer)

🎓 Learning json-render

This demo shows the core concepts:

  1. Catalog Definition: Define allowed components with typed props (Zod schemas)
  2. Registry: Map component names to React implementations
  3. Spec Format: JSON tree structure with root + elements
  4. Renderer: Takes spec + registry, outputs React components
  5. Provider: Wraps Renderer with required contexts (Action, Data, Visibility)

In production with AI:

  • User types: "Show me a recipe for chocolate chip cookies"
  • AI generates a JSON spec using your catalog components
  • json-render's Renderer turns it into React instantly
  • Safe: AI can't inject arbitrary code, only use your components

📖 Additional Resources

🍴 Recipe Credits

Recipes inspired by the legendary techniques of:

  • Auguste Escoffier - Father of modern French cuisine (Crêpes Suzette)
  • Olivier Roellinger - Three-Michelin-starred Breton chef (Buckwheat Galettes)
  • Pierre Hermé - "Picasso of Pastry" (Salted Caramel Crêpes)
  • Joël Robuchon - Most Michelin-starred chef in history (Crêpes Parmentier)

📜 License

MIT License - Feel free to use this demo for your own projects!


Built with ❤️ using json-render. Bon Appétit! 🇫🇷