🥞 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
-
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" }, // ... } }); -
Map to React Components (
lib/registry.tsx):export const { registry } = defineRegistry(catalog, { components: { RecipeHeader: ({ props }) => ( <div> <h1>{props.title}</h1> {/* ... */} </div> ), // ... } }); -
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", /* ... */ } }, // ... } }; -
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.comwith your actual domain - Adjust
ingressClassNameif 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:
- DNS records should be created automatically
- Verify in Cloudflare dashboard
- Ensure SSL/TLS mode is "Full (strict)" or "Full"
If configuring manually:
- Create an A or CNAME record pointing to your ingress IP/hostname
- Enable Cloudflare proxy (orange cloud) for DDoS protection
- 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
-
Define your recipe spec in
lib/recipes.ts:{ root: "root", elements: { root: { type: "RecipeCard", props: { title: "My Recipe", /* ... */ }, children: ["chef", "header", /* ... */] }, // ... more elements } } -
The spec will be automatically rendered using the existing component catalog!
Adding New Components
-
Update component schema in
lib/catalog.ts:MyNewComponent: { props: z.object({ myProp: z.string(), }), description: "My new component" } -
Add React implementation in
lib/registry.tsx:MyNewComponent: ({ props }) => ( <div>{props.myProp}</div> ) -
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:
- Catalog Definition: Define allowed components with typed props (Zod schemas)
- Registry: Map component names to React implementations
- Spec Format: JSON tree structure with
root+elements - Renderer: Takes spec + registry, outputs React components
- 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
Rendererturns it into React instantly - Safe: AI can't inject arbitrary code, only use your components
📖 Additional Resources
- json-render GitHub - Official repository
- Flux documentation - GitOps toolkit
- Next.js deployment - Deployment guides
- Cloudflare Pages/Workers - Edge deployment
🍴 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! 🇫🇷