---
name: brand-asset-generator
description: >
  Build a CE-hosted AI asset generator for any brand/event. User describes a
  content need → AI proposes 3 creative directions → picks one → Gemini generates
  a branded image → edits in Fabric.js canvas (text, logo, format) → downloads PNG.
  Use when: a client needs a self-serve asset creation tool, an event needs branded
  social assets at scale, or CE wants to demo AI creative tooling to a prospect.
---

# Brand Asset Generator Skill

## What This Builds

A CE-branded web application where a client's team can:
1. Describe a content need in plain language
2. Receive 3 AI-generated creative directions (copy + visual concept)
3. Select a direction → AI generates a branded image
4. Edit in a canvas (text, logo, format selection)
5. Download a print-ready PNG

**First deployment:** Future Forward 2026 (weXelerate, Vienna)
**Live path:** `public/future-forward-generator/`
**Source:** `work/pitches/future-forward/generator/`

---

## Architecture

```
Browser (HTML/JS/Fabric.js)
    ↓ POST /api/generate-directions  →  Gemini 2.5 Flash (text)
    ↓ POST /api/generate-image       →  Gemini 3.1 Flash Image
Node.js Express server (port varies, default 3071)
Cloudflared tunnel → public URL
```

### Stack
| Layer | Technology |
|-------|-----------|
| Frontend | Vanilla HTML/CSS/JS, single file |
| Canvas editor | Fabric.js (CDN) |
| Direction AI | Gemini 2.5 Flash (`generateContent`) |
| Image AI | `gemini-3.1-flash-image-preview` (`generateContent`, responseModalities IMAGE) |
| Server | Node.js + Express |
| Hosting | CE staging (nginx) + Cloudflare Tunnel for demos |

---

## CE Design System (STRICT — never guess)

Load these fonts every time:
```html
<link rel="stylesheet" href="https://use.typekit.net/ffj8sbd.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
```

### CSS Variables
```css
:root {
  --ce-red: #cc0000;
  --black: #1a1a1a;
  --white: #ffffff;
  --grey: #666666;
  --grey-light: #999999;
  --border: #eeeeee;
  --bg-card: #fafafa;

  --size-display: 48px;  /* Larken — hero title only */
  --size-h1: 28px;       /* Larken — section titles */
  --size-h2: 20px;       /* Larken — card headlines */
  --size-body: 14px;     /* Inter — all body */
  --size-small: 12px;    /* Inter — secondary */
  --size-label: 10px;    /* Inter — uppercase tags */

  --weight-regular: 400;
  --weight-medium: 500;  /* max weight — never use 700/bold */

  --gap-section: 40px;
  --gap-card: 24px;
  --gap-element: 16px;
  --gap-label: 8px;
  --max-text-width: 680px;
}
```

### Label pattern (always red, always uppercase)
```css
.label {
  font-family: Inter, sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ce-red);
}
```

### Card pattern (horizontal list, not column grid)
```css
.card-row {
  display: grid;
  grid-template-columns: 64px [left-col]px 1fr auto;
  align-items: start;
  gap: 32px;
  padding: 28px 0;
  border-bottom: 1px solid var(--border);
}
```

### Navigation
```css
.top-nav {
  position: fixed; top: 0; left: 0; right: 0;
  padding: 14px 48px;
  display: flex; justify-content: space-between; align-items: center;
  background: white;
  border-bottom: 1px solid var(--border);
  z-index: 1000;
}
.nav-logo img { height: 18px; width: auto; }
```

### Prohibited
- ❌ font-weight 600, 700, or `bold`
- ❌ borders > 1px
- ❌ colors outside the palette
- ❌ font sizes: 9, 11, 13, 15, 18, 22, 24, 26px
- ❌ text wider than 680px
- ❌ posting images in Discord channels

---

## Brand Style JSON (per client)

Each client gets a `brand-style.json` that locks image generation prompts.

### Example — Future Forward 2026
```json
{
  "style_id": "future-forward-2026",
  "client": "weXelerate / Future Forward",
  "output_palette": {
    "background": "#111111",
    "accent": "#DCFF00",
    "text": "#ffffff"
  },
  "output_fonts": {
    "display": "Sora",
    "body": "Inter"
  },
  "subject": {
    "type": "astronaut",
    "suit": "vintage NASA Apollo-era spacesuit, white, photorealistic",
    "visor": "reflective chrome mirrored, face obscured",
    "poses": ["walking forward mid-stride", "floating zero gravity", "extreme visor closeup reflecting cityscape"]
  },
  "background_treatment": {
    "primary": "deep charcoal black #111111",
    "texture": "circular halftone dot pattern in neon lime #DCFF00 radiating behind figure"
  },
  "lighting": {
    "accent_color": "#DCFF00 neon lime",
    "style": "dramatic low-key, single neon source from below or side"
  },
  "aesthetic_tags": [
    "photorealistic",
    "retro-futurism",
    "pop-art halftone",
    "editorial poster quality",
    "high contrast",
    "cinematic"
  ],
  "locked_negative": "no text in image, no watermarks, no logos, no multiple figures",
  "locked_suffix": "Future Forward 2026 Vienna innovation conference, no text in image",
  "logo_url": "https://storage.googleapis.com/b2match-as-1/Fa1QaHC9CvNqhJtiYsFrzru2",
  "logo_canvas_position": "top-left, 160px wide, locked"
}
```

---

## Image Generation API

```javascript
// POST /api/generate-image
// body: { visual_concept: "..." }

const GEMINI_KEY = process.env.GEMINI_API_KEY;
const style = require('./brand-style.json');

const prompt = `
${visual_concept}.
Subject: ${style.subject.suit}, ${style.subject.visor}.
Background: ${style.background_treatment.primary}, ${style.background_treatment.texture}.
Lighting: ${style.lighting.accent_color}, ${style.lighting.style}.
Aesthetic: ${style.aesthetic_tags.join(', ')}.
${style.locked_suffix}. ${style.locked_negative}.
`.trim();

const res = await fetch(
  `https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image-preview:generateContent?key=${GEMINI_KEY}`,
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      contents: [{ parts: [{ text: prompt }] }],
      generationConfig: { responseModalities: ['TEXT', 'IMAGE'] }
    })
  }
);
const data = await res.json();
const imgPart = data.candidates?.[0]?.content?.parts?.find(p => p.inlineData);
// imgPart.inlineData.data = base64, imgPart.inlineData.mimeType = 'image/png'
```

---

## Canvas Formats

| Name | Dimensions | Use |
|------|-----------|-----|
| Instagram | 1080×1080 | Square posts |
| LinkedIn Post | 1200×627 | Feed posts |
| Story 9:16 | 1080×1920 | Stories |
| Twitter/X | 1600×900 | Cards |

Canvas download: `canvas.toDataURL('image/png')` with multiplier 2 for retina.

---

## Direction Generation Prompt

```
System: You are a creative director for [EVENT NAME], [DESCRIPTION]. 
Brand: [COLOR DESCRIPTION], [VISUAL MOTIF].
Return ONLY a JSON array of 3 creative directions:
[{
  "name": "DIRECTION NAME IN CAPS",
  "headline": "3-8 WORD HEADLINE ALL CAPS",
  "subhead": "10-15 word supporting line",
  "body": "20-30 word body copy",
  "visual_concept": "1-2 sentences, cinematic, references brand motif",
  "cta": "2-4 word CTA"
}]
```

---

## Deploying for a New Client

1. Copy `work/pitches/future-forward/generator/` → `work/pitches/[client]/generator/`
2. Create `brand-style.json` with client's visual system
3. Update the direction generation prompt (client name, event description, brand motif)
4. Replace logo URL in canvas init
5. Update nav: client name label, CE logo stays
6. Set port (avoid conflicts — check running servers)
7. Deploy to `public/[client]-generator/`
8. Tunnel: `cloudflared tunnel --url http://localhost:[port]`

---

## File Structure

```
work/pitches/[client]/generator/
├── server.js              # Express server + API routes
├── brand-style.json       # Client visual DNA (locked prompt config)
├── package.json
├── node_modules/
└── public/
    ├── index.html         # Full frontend (single file)
    └── ce-logo.png        # CE wordmark (from public/assets/ce-logo-red.png)
```

---

## Known Issues & Solutions

| Issue | Solution |
|-------|---------|
| Gemini image model not found | Use `gemini-3.1-flash-image-preview` — confirmed working 2026-03-20 |
| OpenAI over quota | Switch to Gemini 2.5 Flash for directions too |
| Logo not loading in nav | Serve logo locally in `public/`, never rely on external URLs |
| Canvas logo CORS | Use same-origin path or CORS-enabled CDN URL |
| Cloudflare tunnel URL changes | Restart tunnel, post new URL — do not hardcode |

---

## Product Vision

This tool is a CE product line: **"Brand Asset Generator"**.

- CE builds it, brands the UI as CE
- Client's visual DNA is locked in `brand-style.json`
- The generated output looks entirely like the client
- Sells as a service: setup fee + hosting

**Pricing model (proposed):**
- Setup: €3,000–5,000 (brand style configuration + deployment)
- Hosting: €200/month
- Custom formats: €500 each

**Future features:**
- Multi-brand support (one tool, dropdown to switch client)
- Saved asset library
- Team accounts
- Figma export
- Batch generation (10 assets from one brief)
