Align illustration pipeline and add full body figure set.

Use bilder/ as the only drop zone (q90 convert), ship production
JPEGs for all catalog IDs including HTML-rendered S-02…S-07, and
trim redundant cover master from assets/cover.
This commit is contained in:
grok-bot committed 2026-08-02 21:17:45 +02:00
1 parent 90818da78a
commit 80e5838432
42 files changed
+2276 -20

No files matched your search

+11
View File
@@ -12,9 +12,16 @@ CLAUDE.local.md
.env.*
secrets/
# Python / todo-cli
__pycache__/
*.pyc
.venv/
*.egg-info/
.pytest_cache/
.ruff_cache/
node_modules/
# Build
build/
dist/*.aux
dist/*.log
@@ -22,3 +29,7 @@ dist/*.out
dist/*.toc
# PDF-Output optional versionieren — dist/*.pdf nicht pauschal ignorieren
kladde
# Illustration Drop-Zone (Rohquellen; Produktion unter assets/)
bilder/
pics/
+9
View File
@@ -0,0 +1,9 @@
---
description: Übernimmt Bilder aus bilder/ als JPEG q90 nach assets/ (ID-Korrelation)
---
# update-pics
Lade und führe den Skill aus: `.grok/skills/update-pics/SKILL.md`.
Kurz: `python3 scripts/convert_illustrations.py` im Repo-Root.
Drop-Zone ist **`bilder/`** (nicht `pics/`). Kein Manuskript-Edit, kein PDF-Bau ohne Auftrag.
+95
View File
@@ -0,0 +1,95 @@
---
name: update-pics
description: >
Übernimmt Rohbilder aus bilder/ als JPEG (Qualität 90, Navy-Composite) nach
assets/illustrations/ und assets/cover/. Mapping über ID-Präfix (K-01, M-03, …)
in scripts/convert_illustrations.py / abbildungen.md.
Nutzen bei: „update-pics“, „Bilder aus bilder“, „Illustrationen aktualisieren“,
„Assets ersetzen“, /update-pics.
---
# update-pics — Illustrationen aus `bilder/` übernehmen
Drop-Zone `bilder/` → kanonische JPGs unter `assets/`. Kein Manuskript-Edit, kein ungefragter PDF-Bau.
**Hinweis:** In den Schwesterprojekten heißt die Drop-Zone oft `pics/`. In diesem Repo ist der Kanon **`bilder/`** (siehe `abbildungen.md`).
## Prinzipien
1. **Nur Assets** — Kapitel-Markdown und `abbildungen.md` bleiben unberührt.
2. **ID-Korrelation** — Dateiname beginnt mit Katalog-ID (`K-02-….png` → `K-02` → Zielname aus dem Convert-Skript).
3. **JPEG q90 + Navy-Composite** — RGBA wird auf Night Navy (`#0B1B2B`) gelegt.
4. **Quellen belassen** — Dateien in `bilder/` nicht löschen.
5. **Deterministisch** — immer `scripts/convert_illustrations.py`, nicht manuell raten.
## Pfade
| Rolle | Pfad |
|-------|------|
| Quelle (Drop) | `bilder/` |
| Ziel Illustrationen | `assets/illustrations/` |
| Ziel Cover | `assets/cover/` |
| Katalog | `abbildungen.md` |
| Skript | `scripts/convert_illustrations.py` |
Erlaubte Quellformate: was Pillow lädt (typisch `.png`, `.jpg`, `.jpeg`, `.webp`).
## Ablauf
### 1. Vorbedingungen
- Repo-Root (mit `abbildungen.md` und `scripts/convert_illustrations.py`).
- `bilder/` enthält mindestens eine Bilddatei mit ID-Präfix.
- Pillow: `python3 -c "from PIL import Image"` — falls fehlend: User informieren (`pip install Pillow`).
### 2. Übernehmen
```bash
python3 scripts/convert_illustrations.py
```
Das Skript mappt ID-Präfixe auf kanonische Dateinamen und schreibt JPEGs.
### 3. Report
Skript-Ausgabe im Chat zusammenfassen:
```text
## update-pics
**Quelle:** bilder/
**Übernommen / übersprungen / Fehler:** …
**Hinweis:** Zum PDF `/pdf` bzw. `just pdf` (nur auf Wunsch).
```
### 4. Nicht tun
- Keine `![…]()` in Kapitel einfügen oder Captions ändern
- `abbildungen.md` nicht um Status-Spalten „patchen“
- Kein `just pdf` / `just assemble` ohne Auftrag
- Keine Dateien in `bilder/` löschen
- Keine zweite Drop-Zone `pics/` anlegen (Doppelspur vermeiden)
## Korrelation (kurz)
| Quelle in `bilder/` | ID | Ziel (Beispiel) |
|---------------------|-----|-----------------|
| `K-02-irgendwas.png` | K-02 | `assets/illustrations/K-02-surfaces-eine-engine.jpg` |
| `COVER-01B-….png` | COVER-01B | `assets/cover/COVER-01B-full.jpg` |
| `diagram.png` | — | skip (kein ID-Präfix) |
Kanonische Namen: `scripts/convert_illustrations.py` (`TARGETS`) und `abbildungen.md`.
## Häufige Fehler
| Symptom | Ursache | Nächster Schritt |
|---------|---------|------------------|
| `bilder/` fehlt / leer | keine Drop-Dateien | Rohbilder mit ID-Präfix ablegen |
| skip / kein Match | Dateiname startet nicht mit `K-NN` / `M-NN` / … | umbenennen laut Katalog |
| `Pillow fehlt` | Dependency | `pip install Pillow` |
| Ziel unverändert im PDF | nur Asset getauscht | PDF neu bauen, wenn gewünscht |
## Erfolg
- Erkannte Katalog-IDs aus `bilder/` liegen als JPEG q90 unter den kanonischen Asset-Pfaden
- Unbekannte Dateien klar gemeldet
- Keine Manuskript-Diffs
+4 -3
View File
@@ -1,15 +1,16 @@
# Abbildungen und Gemini-Prompts
**Buch:** *Grok Build – Der umfassende Praxisleitfaden*
**Stand:** 2026-07-28
**Stand:** 2026-08-02
**Zweck:** Inventar sinnvoller Abbildungen mit didaktischem Anker und **englischen Gemini-Prompts** (print-tauglich).
**Status (2026-07-28):** Inventar + Prompt-Dateien + Manuskript-Einbettungen. **Cover liegt vor** (`assets/cover/COVER-01B-full.jpg`, aus `grok-build-cover.png`). Body-Illustrationen noch offen — generieren über [`prompts/gemini/`](prompts/gemini/), Rohdateien nach `bilder/`, dann `python3 scripts/convert_illustrations.py`.
**Status (2026-08-02):** Inventar + Prompt-Dateien + Manuskript-Einbettungen. **Cover:** `assets/cover/COVER-01B-full.jpg` (Master-Roh in `bilder/COVER-01B-master.png`, Drop-Zone gitignored). **Body-Assets:** alle 22 geplanten Figuren als JPEG q90 unter `assets/illustrations/` (S-02…S-07 aus HTML-Render `scripts/_fig_render/` → `bilder/` → convert). Inventar-only (kein Body-Embed): **K-03**, **N-01**.
- **Im Body geplant:** **22 Figuren** (+ Cover).
- **Nur Inventar (nicht im Body):** **K-03** (Redundanz zu K-01), **N-01** (NICE, Text reicht).
- Landscape im Body: `{width=90%}` (Vorwort/Einführung: `{width=80%}`); N-03 Portrait: `{width=55%}`.
- Copy-paste-Prompts: [`prompts/gemini/`](prompts/gemini/) — Cover + KEY/MUST/SHOULD/NICE.
- Copy-paste-Prompts: [`prompts/gemini/`](prompts/gemini/) — Cover + KEY/MUST/SHOULD/NICE.
- **Gesamtliste mit Vollprompts:** [`prompts/gemini/LISTE.md`](prompts/gemini/LISTE.md) (Übersicht + pro Figur Anker, Caption, Asset, englischer Gemini-Prompt, Render-Target).
Dieses Dokument ist die Source of Truth für Inventar, Captions und Didaktik.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

+14 -3
View File
@@ -2,9 +2,20 @@
Gerüste zum Kopieren und Anpassen. Keine echten Secrets.
## Hierarchie (nicht 1:1-Kopien)
| Schicht | Pfad | Rolle |
|---------|------|--------|
| **Kanon / Superset** | [`../../vorlagen/`](../../vorlagen/) | kopierfertige Minima: Permissions, MCP, Hooks, AGENTS, Plugin, User |
| **Snippet** | diese Dateien hier | kurze, kapitelnahe Ausschnitte zum Einfügen |
| **Lebend** | [`../todo-cli/`](../todo-cli/) | Mini-Repo mit vollem `.grok/`-Harness — Instantiierung, kann leicht von Vorlagen abweichen |
Bei Schema-Fragen gilt die Vorlage (und der User-Guide); todo-cli ist Lern- und Demo-Material.
## Dateien hier
| Datei | Zweck |
|-------|--------|
| [`github-actions-grok-review.yml`](github-actions-grok-review.yml) | Headless PR-Review (Kapitel 10 / 15) |
| [`mcp.filesystem.beispiel.toml`](mcp.filesystem.beispiel.toml) | Eng gescopter filesystem-MCP |
Siehe auch [`../../vorlagen/`](../../vorlagen/).
| [`config.project.beispiel.toml`](config.project.beispiel.toml) | Schlankes Project-`.grok/config.toml` (permission); ausführlicher: `vorlagen/config.permissions.toml` |
| [`mcp.filesystem.beispiel.toml`](mcp.filesystem.beispiel.toml) | Eng gescopter filesystem-MCP; Überblick: `vorlagen/config.mcp.toml` |
+3 -3
View File
@@ -18,7 +18,7 @@ deny = [
"Bash(wget *)",
"Bash(git push --force *)",
"Bash(git push -f *)",
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)",
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
]
File diff suppressed because it is too large. Load diff
+6 -3
View File
@@ -3,8 +3,9 @@
Vollständige englische Prompts für **Gemini / Imagen** zur Bildgenerierung.
**Buch:** *Grok Build – Der umfassende Praxisleitfaden. Der Coding-Agent von xAI richtig einsetzen*
**Autor:** Martin Richardt · **Stand:** 2026-07-28
**Source of Truth (Inventar):** [`../../abbildungen.md`](../../abbildungen.md)
**Autor:** Martin Richardt · **Stand:** 2026-08-02
**Source of Truth (Inventar):** [`../../abbildungen.md`](../../abbildungen.md)
**Gesamtliste mit Vollprompts:** [`LISTE.md`](LISTE.md)
---
@@ -13,6 +14,7 @@ Vollständige englische Prompts für **Gemini / Imagen** zur Bildgenerierung.
```text
prompts/gemini/
├── README.md ← diese Datei
├── LISTE.md ← Gesamtliste: Anker + Caption + englische Vollprompts
├── _global-style.txt ← gemeinsamer Stil (optional voranstellen)
├── cover/ ← Titelseite / Cover
│ ├── COVER-01A-text-free.txt (empfohlen, textfrei)
@@ -127,5 +129,6 @@ python3 scripts/convert_illustrations.py
## Pflege
- Inhaltliche Änderungen an Prompts: hier **und** in `abbildungen.md` synchron halten.
- Inhaltliche Änderungen an Prompts: Einzeldatei unter `key|must|should|nice|cover/` **und** bei Bedarf `LISTE.md` (All-in-one-Spiegel) und `abbildungen.md` (Inventar/Captions).
- Neue Figur: Prompt-Datei anlegen + Zeile in `abbildungen.md` + diese README-Tabelle + `convert_illustrations.py` TARGETS.
- Drop-Zone ist nur **`bilder/`** (nicht `pics/`); Produktion: `assets/illustrations/` und `assets/cover/`.
+77
View File
@@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="common.css"/>
<style>
.tree { flex: 1.4; display: flex; flex-direction: column; justify-content: center; }
.side { flex: 0.9; display: flex; flex-direction: column; gap: 16px; justify-content: center; }
.nest { margin-left: 28px; border-left: 3px solid #c9d4e3; padding-left: 18px; }
.nest .nest { margin-left: 20px; }
.path { font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 15px; color: var(--muted); }
.glow-parent { background: rgba(46,196,255,0.06); border: 1px solid rgba(46,196,255,0.25); }
</style>
</head>
<body>
<div class="page">
<h1>Nested AGENTS.md discovery</h1>
<p class="subtitle">Tighter rules win where the agent works</p>
<div class="stage">
<div class="card tree">
<div class="label" style="margin-bottom:12px">Monorepo tree</div>
<div class="file-row glow-parent">
<div class="icon-doc"></div>
<div>
<div class="mono">AGENTS.md</div>
<div class="path">repo root</div>
</div>
<span class="chip" style="margin-left:auto">global Do / Don’t</span>
</div>
<div class="nest">
<div class="path" style="margin:6px 0 4px">apps/web/</div>
<div class="file-row glow-parent">
<div class="icon-doc"></div>
<div>
<div class="mono">AGENTS.md</div>
<div class="path">apps/web</div>
</div>
<span class="chip violet" style="margin-left:auto">stack + commands</span>
</div>
<div class="nest">
<div class="path" style="margin:6px 0 4px">apps/web/src/</div>
<div class="file-row hot">
<div class="icon-doc"></div>
<div>
<div class="mono">AGENTS.md</div>
<div class="path">nearest wins</div>
</div>
<div class="agent" title="agent" style="margin-left:auto"></div>
</div>
<div class="file-row dim">
<div class="icon-doc" style="opacity:0.5"></div>
<div>
<div class="mono" style="color:var(--muted)">local.notes</div>
<div class="path">ignored</div>
</div>
<span class="chip deny" style="margin-left:auto">gitignore</span>
</div>
</div>
</div>
</div>
<div class="side">
<div class="card">
<div class="label">Discovery</div>
<p class="note" style="margin-top:12px;font-size:20px;color:var(--ink)">
Walk up from the working directory. Load every AGENTS.md; closer files refine the compass.
</p>
</div>
<div class="card" style="display:flex;flex-direction:column;gap:12px">
<span class="chip cyan">root = global Do / Don’t</span>
<span class="chip violet">package = stack + commands</span>
<span class="chip">src = local overrides</span>
</div>
</div>
</div>
</div>
</body>
</html>
+61
View File
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="common.css"/>
<style>
.map { flex: 1.5; display: flex; gap: 18px; }
.rules { flex: 0.85; display: flex; flex-direction: column; gap: 14px; }
.spot {
position: absolute; inset: 0; border-radius: 14px; pointer-events: none;
background: radial-gradient(ellipse at 50% 40%, rgba(46,196,255,0.35), transparent 70%);
}
</style>
</head>
<body>
<div class="page">
<h1>Path-scoped rules light up where you work</h1>
<p class="subtitle">Spotlight, not a novel — .grok/rules/*.md</p>
<div class="stage">
<div class="map">
<div class="region">
<div class="region-title">frontend/</div>
<div class="note">UI components · routes</div>
</div>
<div class="region">
<div class="region-title">backend/</div>
<div class="note">API · store</div>
</div>
<div class="region lit">
<div class="spot"></div>
<div class="region-title">tests/</div>
<div class="note">pytest · fixtures</div>
<div style="margin-top:28px;display:flex;align-items:center;gap:12px">
<div class="agent"></div>
<span class="chip cyan">agent here</span>
</div>
</div>
</div>
<div class="rules card">
<div class="label" style="margin-bottom:8px">.grok/rules/</div>
<div class="rule-card on">
<div class="mono">testing.md</div>
<div class="note" style="margin-top:4px">spotlight on tests/</div>
</div>
<div class="rule-card off">
<div class="mono">security.md</div>
<div class="note" style="margin-top:4px">dim until sensitive paths</div>
</div>
<div class="rule-card off">
<div class="mono">frontend.md</div>
<div class="note" style="margin-top:4px">idle</div>
</div>
<div class="footer-row">
<span class="chip">path-scoped</span>
<span class="chip cyan">not always-on</span>
</div>
</div>
</div>
</div>
</body>
</html>
+70
View File
@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="common.css"/>
<style>
.lanes { flex: 1; display: flex; flex-direction: column; gap: 18px; }
.lane-row { display: flex; gap: 20px; flex: 1; }
.trunk {
height: 72px; border-radius: 16px; background: var(--navy);
color: #fff; display: flex; align-items: center; justify-content: space-between;
padding: 0 28px; font-weight: 700; font-size: 20px;
}
.pr {
background: rgba(46,196,255,0.2); color: #fff; border-radius: 999px;
padding: 8px 16px; font-size: 15px; font-weight: 650;
}
.anti {
width: 280px; border: 2px dashed var(--deny); border-radius: 16px;
padding: 16px; background: rgba(194,59,74,0.06);
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 10px; text-align: center;
}
.pill { padding: 10px 14px; border-radius: 10px; background: var(--panel); font-weight: 650; font-size: 16px; }
</style>
</head>
<body>
<div class="page">
<h1>Parallel tracks without collisions</h1>
<p class="subtitle">Research parallel · writes isolated · merge with review</p>
<div class="stage" style="flex-direction:column">
<div class="lane-row">
<div class="track a" style="flex:1">
<div style="display:flex;justify-content:space-between;align-items:center">
<span class="chip cyan">Track A</span>
<span class="mono">feat-auth</span>
</div>
<div class="pill">Session A · worktree</div>
<div class="note">isolated files on disk</div>
</div>
<div class="track b" style="flex:1">
<div style="display:flex;justify-content:space-between;align-items:center">
<span class="chip violet">Track B</span>
<span class="mono">fix-flaky</span>
</div>
<div class="pill">Session B · worktree</div>
<div class="note">separate branch checkout</div>
</div>
<div class="anti">
<span class="x-badge">✕</span>
<strong style="font-size:17px">Anti-pattern</strong>
<span class="note">two pens, one working tree</span>
</div>
</div>
<div class="trunk">
<span>shared remote · main</span>
<div style="display:flex;gap:12px;align-items:center">
<span class="pr">PR gate</span>
<span class="chip ok" style="background:#fff;color:var(--ok)">human review</span>
</div>
</div>
<div class="footer-row">
<span class="chip cyan">research parallel</span>
<span class="chip violet">writes isolated</span>
<span class="chip ok">merge with review</span>
</div>
</div>
</div>
</body>
</html>
+76
View File
@@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="common.css"/>
<style>
.pipe { flex: 1; display: flex; align-items: stretch; gap: 8px; }
.gate-title { font-size: 20px; font-weight: 750; }
.ex { font-size: 14px; color: var(--muted); font-weight: 600; }
.stop {
position: absolute; top: 10px; right: 10px;
background: var(--deny); color: #fff; font-size: 12px; font-weight: 800;
padding: 4px 8px; border-radius: 6px;
}
</style>
</head>
<body>
<div class="page">
<h1>Authorization pipeline before every tool call</h1>
<p class="subtitle">Mode → Rules → Trust → Sandbox → Execute</p>
<div class="stage" style="flex-direction:column">
<div style="display:flex;align-items:center;gap:16px;margin-bottom:8px">
<div class="packet">tool call</div>
<span class="note" style="font-size:18px">packet travels left → right; deny stops; ask pauses</span>
</div>
<div class="pipe">
<div class="gate">
<div class="gate-box active">
<div class="gate-num">1</div>
<div class="gate-title">Mode</div>
<div class="ex">Plan · Normal · Always</div>
</div>
</div>
<div class="arrow">→</div>
<div class="gate">
<div class="gate-box">
<div class="stop">deny</div>
<div class="gate-num">2</div>
<div class="gate-title">Permission rules</div>
<div class="ex">deny rm · allow pytest</div>
</div>
</div>
<div class="arrow">→</div>
<div class="gate">
<div class="gate-box">
<div class="gate-num">3</div>
<div class="gate-title">Folder trust</div>
<div class="ex">trusted?</div>
</div>
</div>
<div class="arrow">→</div>
<div class="gate">
<div class="gate-box">
<div class="gate-num">4</div>
<div class="gate-title">Sandbox</div>
<div class="ex">OS fence</div>
</div>
</div>
<div class="arrow">→</div>
<div class="gate">
<div class="gate-box" style="border-color:var(--ok);box-shadow:0 0 0 4px rgba(42,157,110,0.15)">
<div class="gate-num" style="background:var(--ok)">5</div>
<div class="gate-title">Execute tool</div>
<div class="ex">run</div>
</div>
</div>
</div>
<div class="footer-row" style="margin-top:28px">
<span class="chip deny">any red deny stops</span>
<span class="chip warn">ask = human key</span>
<span class="chip ok">only then execute</span>
</div>
</div>
</div>
</body>
</html>
+61
View File
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="common.css"/>
<style>
.stack { flex: 1; display: flex; flex-direction: column; gap: 18px; justify-content: center; }
.layer-body { flex: 1; }
.layer-title { font-size: 24px; font-weight: 750; margin-bottom: 6px; }
.flow-arrow {
text-align: center; color: var(--cyan); font-size: 22px; font-weight: 700; height: 12px; line-height: 0;
}
</style>
</head>
<body>
<div class="page">
<h1>Laptop policy, CI review, human merge</h1>
<p class="subtitle">Local rules travel with the repo — ownership stays human</p>
<div class="stage">
<div class="stack">
<div class="layer">
<div class="layer-badge" style="background:var(--cyan)">1</div>
<div class="layer-body">
<div class="layer-title">Developer laptop</div>
<div class="note" style="font-size:18px">
<span class="mono">.grok/config.toml</span> deny rules · <span class="mono">AGENTS.md</span>
</div>
</div>
<span class="chip cyan">local policy</span>
</div>
<div class="flow-arrow">↓</div>
<div class="layer">
<div class="layer-badge" style="background:var(--violet)">2</div>
<div class="layer-body">
<div class="layer-title">CI runner</div>
<div class="note" style="font-size:18px">
<span class="mono">grok -p</span> headless · read-only or yolo + deny
</div>
</div>
<span class="chip violet">automated review</span>
</div>
<div class="flow-arrow">↓</div>
<div class="layer">
<div class="layer-badge" style="background:var(--navy)">3</div>
<div class="layer-body">
<div class="layer-title">Human merge gate</div>
<div class="note" style="font-size:18px">PR check · approve or reject</div>
</div>
<span class="chip ok">human ownership</span>
</div>
</div>
<div class="card" style="width:360px;display:flex;flex-direction:column;justify-content:center;gap:16px">
<span class="chip warn">headless needs a permission plan</span>
<p class="note" style="font-size:18px;color:var(--ink)">
Same deny baseline on laptop and CI. Headless never invents a safety story.
</p>
</div>
</div>
</div>
</body>
</html>
+75
View File
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="common.css"/>
<style>
.cols { flex: 1; display: flex; gap: 28px; }
.col { flex: 1; display: flex; flex-direction: column; gap: 16px; }
.flake {
display: inline-block; padding: 6px 12px; margin: 4px;
border-radius: 8px; background: rgba(90,107,125,0.12);
color: var(--muted); font-size: 14px; font-weight: 600;
opacity: 0.55;
}
.survivor {
display: flex; align-items: center; gap: 12px;
padding: 14px 16px; border-radius: 12px;
background: #fff; border: 1.5px solid var(--ok);
font-weight: 650; font-size: 17px;
}
.dial {
width: 120px; height: 120px; border-radius: 50%;
border: 8px solid var(--line); border-top-color: var(--violet);
display: flex; align-items: center; justify-content: center;
font-weight: 700; font-size: 15px; text-align: center; color: var(--muted);
}
</style>
</head>
<body>
<div class="page">
<h1>Compact saves window — files save decisions</h1>
<p class="subtitle">Lossy summary vs. durable notes on disk</p>
<div class="stage">
<div class="cols">
<div class="col card">
<div class="label">Context window</div>
<div style="margin-top:12px">
<div class="note" style="margin-bottom:6px">before</div>
<div class="bar"><i style="width:92%"></i></div>
</div>
<div style="margin-top:16px">
<div class="note" style="margin-bottom:6px">after <span class="mono">/compact</span></div>
<div class="bar"><i style="width:38%"></i></div>
</div>
<div style="margin-top:20px">
<div class="note" style="margin-bottom:8px">fading detail (lossy)</div>
<div>
<span class="flake">old tool logs</span>
<span class="flake">side paths</span>
<span class="flake">verbose diffs</span>
<span class="flake">chat asides</span>
</div>
</div>
</div>
<div class="col card">
<div class="label">Survivors on disk</div>
<div class="survivor"><div class="icon-doc"></div><span class="mono">plan.md</span></div>
<div class="survivor"><div class="icon-doc"></div><span class="mono">AGENTS.md</span></div>
<div class="survivor"><div class="icon-doc"></div><span>decision notes</span></div>
<div class="survivor"><div class="icon-doc"></div><span>test output</span></div>
<span class="chip ok" style="align-self:flex-start;margin-top:8px">write it down</span>
</div>
<div class="col card" style="flex:0.7;align-items:center;justify-content:center;text-align:center;gap:18px">
<div class="dial">rewind</div>
<div>
<strong style="font-size:18px">time travel</strong>
<p class="note" style="margin-top:8px">≠ compact summary</p>
</div>
<span class="chip violet">separate tools</span>
</div>
</div>
</div>
</div>
</body>
</html>
+323
View File
@@ -0,0 +1,323 @@
/* Shared book-illustration style: night navy / cyan / soft violet */
:root {
--navy: #0b1b2b;
--navy-mid: #132a40;
--cyan: #2ec4ff;
--violet: #8b7cff;
--panel: #f4f7fb;
--card: #ffffff;
--ink: #0f1c2a;
--muted: #5a6b7d;
--line: #d5dde8;
--deny: #c23b4a;
--ok: #2a9d6e;
--soft: #e8eef6;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
width: 1920px;
height: 1080px;
overflow: hidden;
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
color: var(--ink);
background: linear-gradient(135deg, #eef3f9 0%, #f7f9fc 55%, #e8e4f8 100%);
}
.page {
width: 1920px;
height: 1080px;
padding: 56px 72px 48px;
display: flex;
flex-direction: column;
position: relative;
}
.page::before {
content: "";
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 40% 30% at 0% 0%, rgba(46,196,255,0.12), transparent 60%),
radial-gradient(ellipse 35% 35% at 100% 100%, rgba(139,124,255,0.14), transparent 55%);
pointer-events: none;
}
.page > * { position: relative; z-index: 1; }
h1 {
font-size: 48px;
font-weight: 750;
letter-spacing: -0.02em;
line-height: 1.15;
margin-bottom: 8px;
}
.subtitle {
font-size: 22px;
color: var(--muted);
margin-bottom: 36px;
font-weight: 500;
}
.stage {
flex: 1;
display: flex;
gap: 28px;
align-items: stretch;
min-height: 0;
}
.card {
background: var(--card);
border-radius: 20px;
box-shadow: 0 12px 40px rgba(11,27,43,0.08), 0 2px 8px rgba(11,27,43,0.04);
border: 1px solid rgba(11,27,43,0.06);
padding: 24px 28px;
}
.chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
border-radius: 999px;
font-size: 16px;
font-weight: 600;
background: var(--soft);
color: var(--navy);
}
.chip.cyan { background: rgba(46,196,255,0.18); color: #0a4d6b; }
.chip.violet { background: rgba(139,124,255,0.18); color: #3d3480; }
.chip.ok { background: rgba(42,157,110,0.15); color: #145c3d; }
.chip.deny { background: rgba(194,59,74,0.12); color: #8a2030; }
.chip.warn { background: rgba(220,160,40,0.18); color: #7a5400; }
.label {
font-size: 15px;
font-weight: 650;
color: var(--muted);
text-transform: none;
letter-spacing: 0.02em;
}
.mono {
font-family: "SF Mono", "Menlo", "Consolas", monospace;
font-size: 17px;
font-weight: 600;
}
.agent {
width: 56px;
height: 56px;
border-radius: 50%;
background: linear-gradient(145deg, var(--cyan), var(--violet));
box-shadow: 0 6px 18px rgba(46,196,255,0.35);
position: relative;
}
.agent::after {
content: "";
position: absolute;
inset: 14px 14px 18px;
border-radius: 50%;
background: var(--navy);
opacity: 0.85;
}
.folder {
border-left: 3px solid var(--line);
padding-left: 20px;
margin-left: 10px;
}
.file-row {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 14px;
border-radius: 12px;
margin: 8px 0;
background: var(--panel);
}
.file-row.hot {
background: rgba(46,196,255,0.16);
border: 1.5px solid var(--cyan);
box-shadow: 0 0 0 4px rgba(46,196,255,0.12);
}
.file-row.dim {
opacity: 0.45;
}
.icon-doc {
width: 28px;
height: 34px;
background: #fff;
border: 2px solid var(--navy-mid);
border-radius: 4px;
position: relative;
flex-shrink: 0;
}
.icon-doc::before {
content: "md";
position: absolute;
bottom: 2px;
left: 0;
right: 0;
text-align: center;
font-size: 9px;
font-weight: 800;
color: var(--cyan);
}
.gate {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
gap: 10px;
min-width: 0;
}
.gate-box {
width: 100%;
min-height: 140px;
border-radius: 18px;
background: linear-gradient(180deg, #fff 0%, var(--panel) 100%);
border: 2px solid var(--line);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
padding: 16px 12px;
position: relative;
}
.gate-box.active {
border-color: var(--cyan);
box-shadow: 0 0 0 4px rgba(46,196,255,0.15);
}
.gate-num {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--navy);
color: #fff;
font-weight: 700;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.arrow {
color: var(--cyan);
font-size: 32px;
font-weight: 300;
align-self: center;
padding: 0 4px;
}
.track {
flex: 1;
border-radius: 18px;
padding: 22px;
background: var(--card);
border: 2px solid var(--line);
display: flex;
flex-direction: column;
gap: 14px;
}
.track.a { border-top: 5px solid var(--cyan); }
.track.b { border-top: 5px solid var(--violet); }
.layer {
display: flex;
align-items: center;
gap: 28px;
padding: 22px 28px;
border-radius: 18px;
background: var(--card);
border: 1px solid var(--line);
box-shadow: 0 8px 24px rgba(11,27,43,0.06);
}
.layer-badge {
width: 64px;
height: 64px;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 800;
font-size: 22px;
color: #fff;
flex-shrink: 0;
}
.bar {
height: 28px;
border-radius: 8px;
background: var(--soft);
overflow: hidden;
position: relative;
border: 1px solid var(--line);
}
.bar > i {
display: block;
height: 100%;
background: linear-gradient(90deg, var(--cyan), var(--violet));
}
.note {
font-size: 16px;
color: var(--muted);
line-height: 1.35;
}
.footer-row {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-top: 20px;
}
.region {
flex: 1;
border-radius: 16px;
padding: 18px;
background: var(--panel);
border: 2px dashed var(--line);
min-height: 220px;
position: relative;
}
.region.lit {
border-style: solid;
border-color: var(--cyan);
background: rgba(46,196,255,0.08);
box-shadow: inset 0 0 40px rgba(46,196,255,0.12);
}
.region-title {
font-weight: 700;
font-size: 20px;
margin-bottom: 10px;
font-family: "SF Mono", Menlo, Consolas, monospace;
}
.rule-card {
padding: 14px 16px;
border-radius: 14px;
background: #fff;
border: 1px solid var(--line);
margin-bottom: 10px;
font-size: 16px;
font-weight: 650;
}
.rule-card.on {
border-color: var(--cyan);
box-shadow: 0 0 0 3px rgba(46,196,255,0.2);
background: linear-gradient(180deg, #fff, rgba(46,196,255,0.08));
}
.rule-card.off {
opacity: 0.4;
}
.x-badge {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--deny);
color: #fff;
font-weight: 800;
font-size: 14px;
}
.packet {
width: 72px;
height: 48px;
border-radius: 10px;
background: linear-gradient(135deg, var(--navy), var(--navy-mid));
color: #fff;
font-size: 12px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 6px 16px rgba(11,27,43,0.25);
}
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Render S-02…S-07 HTML diagrams → bilder/ PNGs (Chrome headless).
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
DIR="$(cd "$(dirname "$0")" && pwd)"
OUT="${ROOT}/bilder"
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
mkdir -p "$OUT"
for id in S-02 S-03 S-04 S-05 S-06 S-07; do
html="${DIR}/${id}.html"
png="${OUT}/${id}-render.png"
echo "render ${id} → ${png}"
"$CHROME" --headless=new --disable-gpu --hide-scrollbars \
--window-size=1920,1080 \
--screenshot="${png}" \
"file://${html}" 2>/dev/null
# Chrome sometimes writes relative to CWD; normalize
if [[ ! -f "$png" && -f "${DIR}/screenshot.png" ]]; then
mv "${DIR}/screenshot.png" "$png"
fi
if [[ ! -f "$png" && -f screenshot.png ]]; then
mv screenshot.png "$png"
fi
ls -la "$png"
done
echo "OK: rendered to ${OUT}"
+26 -8
View File
@@ -1,12 +1,13 @@
#!/usr/bin/env python3
"""Convert bilder/ PNGs to production JPEGs (quality 90).
"""Convert bilder/ sources to production JPEGs (quality 90).
Maps ID-prefixed source files to clean asset paths under
assets/illustrations/ and assets/cover/ for *Grok Build –
Der umfassende Praxisleitfaden*. Composites RGBA onto
night navy (#0B1B2B) to match the book illustration palette.
See abbildungen.md and prompts/gemini/ for inventory and prompts.
Drop-Zone-Kanon: bilder/ (nicht pics/). See abbildungen.md and
prompts/gemini/ for inventory and prompts.
"""
from __future__ import annotations
@@ -18,13 +19,22 @@ from pathlib import Path
from PIL import Image
REPO = Path(__file__).resolve().parent.parent
SRC = REPO / "bilder"
ILLUSTRATIONS = REPO / "assets" / "illustrations"
COVER = REPO / "assets" / "cover"
SRC_DIR = REPO / "bilder"
NAVY = (0x0B, 0x1B, 0x2B)
QUALITY = 90
def _resolve_src() -> Path | None:
"""Nur bilder/ (Repo-Kanon)."""
if not SRC_DIR.is_dir():
return None
if any(p.is_file() and not p.name.startswith(".") for p in SRC_DIR.iterdir()):
return SRC_DIR
return None
# Target basenames (without .jpg) by ID prefix
TARGETS: dict[str, tuple[Path, str]] = {
"COVER-01B": (COVER, "COVER-01B-full"),
@@ -92,12 +102,17 @@ def convert_one(src: Path, dest_dir: Path, basename: str) -> Path:
def main() -> int:
if not SRC.is_dir():
print(f"Fehlt: {SRC}", file=sys.stderr)
src = _resolve_src()
if src is None:
print(
f"Fehlt: {SRC_DIR} mit Bilddateien (ID-Präfix, z. B. K-01-….png)",
file=sys.stderr,
)
return 1
print(f"Quelle: {src.relative_to(REPO)}/ quality={QUALITY}")
seen: set[str] = set()
for path in sorted(SRC.iterdir()):
for path in sorted(src.iterdir()):
if path.name.startswith("."):
continue
if not path.is_file():
@@ -117,10 +132,13 @@ def main() -> int:
print(f"{path.name} → {out.relative_to(REPO)} ({size_kb:.0f} KiB)")
seen.add(key)
if not seen:
print("Keine Dateien konvertiert.", file=sys.stderr)
return 1
missing = set(TARGETS) - seen
if missing:
print(f"FEHLT: {sorted(missing)}", file=sys.stderr)
return 1
print(f"Hinweis (nicht im Drop): {sorted(missing)}", file=sys.stderr)
print(f"OK: {len(seen)} JPEGs (quality={QUALITY})")
return 0