# Pitch deck image integration pattern

Use this when building premium HTML-first pitch decks that need image placeholders or generated/internal images.

## Density calibration

User feedback from a deck iteration:

- First version was too wordy.
- Second version became too empty.
- Preferred middle ground: one strong headline per slide plus 2-3 supporting bullets or one concise explanatory block.
- Keep the deck readable on iPhone, but do not strip away the sales argument.

A good slide target:

- 1 core idea
- 1 punchy headline
- 1 concise support paragraph or 2-3 bullets
- 1 visual anchor or image placeholder
- no dense paragraphs unless the slide is explicitly a reference appendix

## Spanish premium deck copy

For Spanish sales decks, prefer concise business Spanish over literal French/English translation.

Good labels:

- `Presencia Infinita`
- `El problema`
- `El cambio`
- `El sistema`
- `La objeción`
- `La venta`
- `Piloto`
- `Cierre`

Useful positioning:

- `No es fake. Es continuidad controlada.`
- `Vendemos presencia. El cliente compra ingresos protegidos.`
- `Nada sale sin marco y sin validación.`

## Placeholder design

For placeholders, make them intentional design objects rather than empty gray boxes:

- rounded premium frame
- dashed inner guide
- small mono labels such as `Hero image`, `9:16 or 4:5`, `Value / metrics`
- visible `+` mark or center target
- keep labels subtle enough that they can remain while reviewing, but easy to remove later

Common placeholder slots for a creator/digital-presence pitch:

- hero model / premium mood image
- feed gap or activity rhythm
- identity-control comparison
- creation / validation / publication cards
- approval panel
- value dashboard
- 30-day pilot timeline
- closing brand/model visual

## ComfyUI-generated deck assets

When generating images internally for a deck:

1. Generate visuals that match the deck's intended content level. For SFW decks, negative prompt should include: `text, watermark, logo, words, letters, signature, nude, explicit, pornographic, low quality`. For decks that showcase creative freedom (e.g., "sin restricciones" slides), use Z-Image Turbo (uncensored) instead of Nano Banana 2 (filtered). See `comfyui` skill `references/z-image-turbo-local.md` for the content-filter comparison.
2. UI/dashboard/timeline generations often contain fake glyphs. Treat them as mood images:
   - blur slightly
   - lower contrast if needed
   - crop/overlay in the deck
   - do not present fake text as real UI
3. Export web derivatives, usually JPG quality 85-90, into a stable relative directory such as `deck_assets/<deck_name>/`.
4. Integrate using relative paths so the same directory can be served by a static HTTP server.
5. Verify both desktop and iPhone screenshots after integration.

## Inline SVG logo for deck branding

For premium decks, create an inline SVG logo rather than a raster image. Benefits:

- infinitely scalable, no pixelation on retina/print
- self-contained in the HTML, no external file dependency
- gradient/filter effects via SVG defs (gold/violet premium feel)
- can be placed in slide headers and as a subtle watermark on closing slides

Pattern:

```html
<!-- In slide header, replace text label with: -->
<div class="logo-wrap">
  <svg class="logo-svg" viewBox="0 0 400 140" fill="none">
    <defs>
      <linearGradient id="infGrad" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" stop-color="#9c7cff"/>
        <stop offset="50%" stop-color="#d8b65a"/>
        <stop offset="100%" stop-color="#9c7cff"/>
      </linearGradient>
      <filter id="glow">
        <feGaussianBlur stdDeviation="2.5" result="blur"/>
        <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
      </filter>
    </defs>
    <!-- infinity symbol + wordmark -->
    <g transform="translate(70, 70)" filter="url(#glow)">
      <ellipse cx="-22" cy="0" rx="24" ry="17" stroke="url(#infGrad)" stroke-width="3.5" fill="none"/>
      <ellipse cx="22" cy="0" rx="24" ry="17" stroke="url(#infGrad)" stroke-width="3.5" fill="none"/>
    </g>
    <text x="120" y="62" font-size="28" font-weight="800" fill="#f7f3ea">Presencia</text>
    <text x="120" y="92" font-size="28" font-weight="300" letter-spacing="3" fill="#d8b65a">INFINITA</text>
  </svg>
  <div class="logo-tag">Doble digital<br>para creadoras</div>
</div>
```

For the closing slide, repeat the logo at reduced opacity (0.4-0.5) as a subtle brand sign-off.

## Serving deck files from a FastAPI app

When a deck HTML and its assets live outside the app's `static/` directory, add a catch-all route AFTER all specific routes:

```python
HOME_DIR = Path("/home/wildlama")
DECK_ASSETS_DIR = HOME_DIR / "deck_assets"

@app.get("/deck_assets/{filepath:path}")
def serve_deck_asset(filepath: str):
    full = DECK_ASSETS_DIR / filepath
    if not full.exists():
        raise HTTPException(status_code=404, detail="Asset not found")
    return FileResponse(full)

# MUST be last — catches everything not matched above
@app.get("/{filename:path}")
def serve_deck(filename: str):
    if filename in ("", "index.html"):
        return FileResponse(STATIC_DIR / "index.html")
    candidate = HOME_DIR / filename
    if candidate.exists() and candidate.is_file():
        return FileResponse(candidate)
    raise HTTPException(status_code=404, detail="Not found")
```

Key: the catch-all `/{filename:path}` must come AFTER `/health`, `/download/{filename}`, `/deck_assets/{filepath:path}`, and all API routes, or it will shadow them.

## Team slide pattern

A common deck slide: 3 portrait cards side by side, each with a photo, role label, name, and one-line description.

```html
<div class="main three">
  <div class="card" style="text-align:center; align-items:center;">
    <div class="image-slot filled" style="min-height:200px; border-radius:20px; width:100%;">
      <img src="deck_assets/team_pro/flo.png" alt="Flo" style="object-fit:cover; object-position:top;">
    </div>
    <div class="number">Fundador</div>
    <h3>Flo</h3>
    <p class="small">VFX Supervisor y arquitecto de IA.</p>
  </div>
  <!-- repeat for Maria, David -->
</div>
```

Key details:
- `object-position:top` is mandatory — without it, mobile cropping shows mid-torso instead of the face.
- Use `.three` grid layout (3 equal columns) that collapses to single column on mobile.
- Keep descriptions to one concise line.
- Generate portraits with Nano Banana 2 using reference photos (see `comfyui` skill). Identity preservation is unreliable — collect 4+ reference photos, generate one variant per reference, and let the user pick.

## Inserting slides mid-deck: counter and nav update

When adding or removing a slide from an existing deck, you MUST update:

1. **All slide counters** — every footer text like `01 / 10` must become `01 / 11` (or the new total).
2. **Bar formula** — the CSS progress bar uses `var(--i) / N * 100%` where N is `total_slides - 1`. Update N.
3. **Nav jump indices** — `data-jump` attributes are 0-indexed slide positions. If you insert at position 9, all slides after it must have their `data-jump` incremented by 1.
4. **The inserted slide's own nav** — its prev/next buttons must point to the correct neighbors.

Fast way to verify after insertion:
```bash
grep -oP '\d+ / \d+' deck.html          # all counters should show the same denominator
grep -oP 'data-jump="\d+"' deck.html     # jumps should be sequential 0..N-1
grep -oP 'var\(--i\) / \d+' deck.html    # bar formula should match N-1
```

## Mobile rule

On iPhone, do not just scale the desktop 16:9 slide. Use a dedicated mobile mode:

- one active slide visible at a time
- vertical flow
- large tap targets
- image below or above text depending on hierarchy
- no sticky footer covering content
- keep the progress/footer at the bottom when content is short
