mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
Add German locale, docs, and localized UI metadata (#190)
* add German locale and translations * add German content coverage checks
This commit is contained in:
parent
534349aa4c
commit
12fa94ca6b
21 changed files with 2817 additions and 54 deletions
271
CONTRIBUTING.de.md
Normal file
271
CONTRIBUTING.de.md
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
# Zu Open Design beitragen
|
||||
|
||||
Danke, dass Sie über einen Beitrag nachdenken. OD ist bewusst klein gehalten — der größte Teil des Werts steckt in **Dateien** (Skills, Designsysteme, Prompt-Fragmente) statt in Framework-Code. Die wirkungsvollsten Beiträge sind deshalb oft ein Ordner, eine Markdown-Datei oder ein PR-großer Adapter.
|
||||
|
||||
Dieser Leitfaden zeigt, wo Sie für welche Art Beitrag suchen sollten und welche Messlatte ein PR vor dem Merge erfüllen muss.
|
||||
|
||||
<p align="center"><a href="CONTRIBUTING.md">English</a> · <b>Deutsch</b> · <a href="CONTRIBUTING.zh-CN.md">简体中文</a> · <a href="CONTRIBUTING.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
## Drei Dinge, die Sie an einem Nachmittag liefern können
|
||||
|
||||
| Wenn Sie möchten… | Fügen Sie eigentlich hinzu | Ort | Umfang |
|
||||
|---|---|---|---|
|
||||
| OD eine neue Artifact-Art rendern lassen (Rechnung, iOS Settings Screen, One-Pager…) | einen **Skill** | [`skills/<your-skill>/`](skills/) | ein Ordner, ca. 2 Dateien |
|
||||
| OD die visuelle Sprache einer neuen Marke sprechen lassen | ein **Design System** | [`design-systems/<brand>/DESIGN.md`](design-systems/) | eine Markdown-Datei |
|
||||
| Eine neue coding-agent CLI anbinden | einen **Agent adapter** | [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts) | ca. 10 Zeilen in einem Array |
|
||||
| Feature ergänzen, Bug fixen, UX-Pattern aus [`open-codesign`][ocod] übernehmen | Code | `apps/web/src/`, `apps/daemon/` | normaler PR |
|
||||
| Dokumentation verbessern, Deutsch / 中文 ergänzen, Tippfehler fixen | Dokumentation | `README.md`, `README.de.md`, `README.zh-CN.md`, `docs/`, `QUICKSTART.md` | ein PR |
|
||||
|
||||
Wenn Sie nicht sicher sind, in welchen Bereich Ihre Idee fällt, [öffnen Sie zuerst eine Discussion / Issue](https://github.com/nexu-io/open-design/issues/new). Wir zeigen Ihnen dann die passende Oberfläche.
|
||||
|
||||
---
|
||||
|
||||
## Lokales Setup
|
||||
|
||||
Das vollständige One-Page-Setup steht in [`QUICKSTART.de.md`](QUICKSTART.de.md). TL;DR für Mitwirkende:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/nexu-io/open-design.git
|
||||
cd open-design
|
||||
corepack enable # wählt das gepinnte pnpm aus packageManager
|
||||
pnpm install
|
||||
pnpm tools-dev run web # daemon + web foreground loop
|
||||
pnpm typecheck # tsc -b --noEmit
|
||||
pnpm build # production build
|
||||
```
|
||||
|
||||
Node `~24` und pnpm `10.33.x` sind erforderlich. `nvm` / `fnm` sind optional; nutzen Sie `nvm install 24 && nvm use 24` oder `fnm install 24 && fnm use 24`, wenn Sie Node so verwalten. macOS, Linux und WSL2 sind die primären Pfade. Windows nativ sollte funktionieren, ist aber kein primäres Ziel.
|
||||
|
||||
Sie brauchen keine Agent-CLI im `PATH`, um OD selbst zu entwickeln. Der daemon meldet dann "no agents found" und fällt auf den **Anthropic API · BYOK** Pfad zurück, der oft die schnellste Dev-Schleife ist.
|
||||
|
||||
---
|
||||
|
||||
## Einen neuen Skill hinzufügen
|
||||
|
||||
Ein Skill ist ein Ordner unter [`skills/`](skills/) mit `SKILL.md` im Root. Er folgt der Claude Code [`SKILL.md` Konvention][skill] plus optionaler `od:` Erweiterung. **Keine Registrierung nötig.** Ordner ablegen, daemon neu starten, der Picker zeigt ihn an.
|
||||
|
||||
### Skill-Ordnerlayout
|
||||
|
||||
```text
|
||||
skills/your-skill/
|
||||
├── SKILL.md # erforderlich
|
||||
├── assets/template.html # optional, aber empfohlen — Seed-Datei
|
||||
├── references/ # optional — Wissensdateien für den Agent
|
||||
│ ├── layouts.md
|
||||
│ ├── components.md
|
||||
│ └── checklist.md
|
||||
└── example.html # stark empfohlen — echtes, handgebautes Beispiel
|
||||
```
|
||||
|
||||
### `SKILL.md` Frontmatter
|
||||
|
||||
Die ersten drei Keys sind die Claude Code Basis-Spec: `name`, `description`, `triggers`. Alles unter `od:` ist OD-spezifisch und optional, aber **`od.mode`** bestimmt, in welcher Gruppe der Skill erscheint.
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: your-skill
|
||||
description: |
|
||||
One-paragraph elevator pitch. The agent reads this verbatim to decide
|
||||
if the user's brief matches. Be concrete: surface, audience, what's in
|
||||
the artifact, what's not.
|
||||
triggers:
|
||||
- "your trigger phrase"
|
||||
- "another phrase"
|
||||
- "中文触发词"
|
||||
od:
|
||||
mode: prototype # prototype | deck | template | design-system
|
||||
platform: desktop # desktop | mobile
|
||||
scenario: marketing # free-form tag for grouping
|
||||
featured: 1 # any positive integer surfaces it under "Showcase examples"
|
||||
preview:
|
||||
type: html # html | jsx | pptx | markdown
|
||||
entry: index.html
|
||||
design_system:
|
||||
requires: true
|
||||
sections: [color, typography, layout, components]
|
||||
example_prompt: "A copy-pastable prompt that nicely shows what this skill does."
|
||||
---
|
||||
|
||||
# Your Skill
|
||||
|
||||
Body is free-form Markdown describing the workflow the agent should follow…
|
||||
```
|
||||
|
||||
Die vollständige Grammatik — typed inputs, Slider-Parameter, capability gating — steht in [`docs/skills-protocol.md`](docs/skills-protocol.md).
|
||||
|
||||
### Merge-Messlatte für einen neuen Skill
|
||||
|
||||
1. **Ein echtes `example.html`.** Handgebaut, direkt von Disk öffnend, mit Designer-Qualität. Kein Lorem ipsum, kein `<svg><rect/></svg>` Placeholder-Hero.
|
||||
2. **Anti-AI-slop Checklist bestehen.** Keine violetten Gradients, keine generischen Emoji-Icons, keine runde Karte mit linkem Border-Akzent, kein Inter als Display-Font, keine erfundenen Zahlen.
|
||||
3. **Ehrliche Platzhalter.** Wenn der Agent keine echte Zahl hat, schreiben Sie `—` oder einen beschrifteten grauen Block, nicht "10× faster".
|
||||
4. **`references/checklist.md` mit mindestens P0 Gates.** Format an [`skills/guizang-ppt/references/checklist.md`](skills/guizang-ppt/) oder [`skills/dating-web/references/checklist.md`](skills/dating-web/) anlehnen.
|
||||
5. **Screenshot unter `docs/screenshots/skills/<skill>.png`**, wenn der Skill featured ist. PNG, ca. 1024×640 retina, aus dem echten `example.html`.
|
||||
6. **Ein einzelner, in sich geschlossener Ordner.** Keine CDN-Imports außer bereits verwendeten, keine unlizenzierte Fonts, keine Bilder über ca. 250 KB.
|
||||
|
||||
Wenn Sie einen vorhandenen Skill forken, behalten Sie LICENSE und Autorenschaft in `references/` und erwähnen Sie es in der PR-Beschreibung.
|
||||
|
||||
### Vorhandene Skills zum Nachahmen
|
||||
|
||||
- Visuelle Single-Screen-Prototypen: [`skills/dating-web/`](skills/dating-web/), [`skills/digital-eguide/`](skills/digital-eguide/)
|
||||
- Multi-Frame Mobile-Flows: [`skills/mobile-onboarding/`](skills/mobile-onboarding/), [`skills/gamified-app/`](skills/gamified-app/)
|
||||
- Dokument / Template: [`skills/pm-spec/`](skills/pm-spec/), [`skills/weekly-update/`](skills/weekly-update/)
|
||||
- Deck-Modus: [`skills/guizang-ppt/`](skills/guizang-ppt/) und [`skills/simple-deck/`](skills/simple-deck/)
|
||||
|
||||
---
|
||||
|
||||
## Ein neues Design System hinzufügen
|
||||
|
||||
Ein Designsystem ist eine einzelne [`DESIGN.md`](design-systems/README.md) Datei unter `design-systems/<slug>/`. **Eine Datei, kein Code.** Ablegen, daemon neu starten, der Picker gruppiert es nach Kategorie.
|
||||
|
||||
### Designsystem-Ordnerlayout
|
||||
|
||||
```text
|
||||
design-systems/your-brand/
|
||||
└── DESIGN.md
|
||||
```
|
||||
|
||||
### `DESIGN.md` Form
|
||||
|
||||
```markdown
|
||||
# Design System Inspired by YourBrand
|
||||
|
||||
> Category: Developer Tools
|
||||
> One-line summary that shows in the picker preview.
|
||||
|
||||
## 1. Visual Theme & Atmosphere
|
||||
…
|
||||
|
||||
## 2. Color
|
||||
- Primary: `#hex` / `oklch(...)`
|
||||
- …
|
||||
|
||||
## 3. Typography
|
||||
…
|
||||
|
||||
## 4. Spacing & Grid
|
||||
## 5. Layout & Composition
|
||||
## 6. Components
|
||||
## 7. Motion & Interaction
|
||||
## 8. Voice & Brand
|
||||
## 9. Anti-patterns
|
||||
```
|
||||
|
||||
Das 9-Section-Schema ist fest — Skill-Bodies greifen darauf per Suche zu. Das erste H1 wird zum Picker-Label (der Prefix `Design System Inspired by` wird entfernt), und `> Category: …` entscheidet die Gruppe. Bestehende Kategorien stehen in [`design-systems/README.md`](design-systems/README.md); nutzen Sie nach Möglichkeit eine vorhandene.
|
||||
|
||||
### Merge-Messlatte für ein neues Designsystem
|
||||
|
||||
1. **Alle 9 Sections vorhanden.** Leere Bodies sind bei schwer auffindbaren Daten akzeptabel, aber die Headings müssen da sein.
|
||||
2. **Hex-Codes sind echt.** Direkt von Website oder Produkt sampeln, nicht aus Erinnerung oder AI raten.
|
||||
3. **OKLch-Werte für Akzentfarben** sind nice-to-have und machen Paletten stabiler.
|
||||
4. **Kein Marketing-Fluff.** Die Tagline einer Marke ist kein Design Token.
|
||||
5. **Slug nutzt ASCII** — `linear.app` wird `linear-app`, `x.ai` wird `x-ai`.
|
||||
|
||||
Die gelieferten Produktsysteme werden aus [`VoltAgent/awesome-design-md`][acd2] über [`scripts/sync-design-systems.ts`](scripts/sync-design-systems.ts) importiert. Wenn Ihre Marke upstream passt, schicken Sie den PR zuerst dorthin; OD übernimmt ihn beim nächsten Sync.
|
||||
|
||||
---
|
||||
|
||||
## Eine neue coding-agent CLI hinzufügen
|
||||
|
||||
Eine neue Agent-CLI ist ein Eintrag in [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts):
|
||||
|
||||
```javascript
|
||||
{
|
||||
id: 'foo',
|
||||
name: 'Foo Coder',
|
||||
bin: 'foo',
|
||||
versionArgs: ['--version'],
|
||||
buildArgs: (prompt) => ['exec', '-p', prompt],
|
||||
streamFormat: 'plain', // or 'claude-stream-json' if it speaks that
|
||||
}
|
||||
```
|
||||
|
||||
Der daemon erkennt sie im `PATH`, der Picker zeigt sie an und der Chat-Pfad funktioniert. Wenn die CLI **typed events** ausgibt, ergänzen Sie einen Parser in [`apps/daemon/src/claude-stream.ts`](apps/daemon/src/claude-stream.ts) und setzen `streamFormat`.
|
||||
|
||||
Merge-Bar:
|
||||
|
||||
1. **Eine echte Session läuft end-to-end** mit dem neuen Agent; fügen Sie den daemon log in die PR-Beschreibung ein.
|
||||
2. **`docs/agent-adapters.md`** dokumentiert die Eigenheiten der CLI.
|
||||
3. **Die README-Tabelle "Unterstützte Code-Agenten"** erhält eine Zeile.
|
||||
|
||||
---
|
||||
|
||||
## Wartung von Lokalisierungen
|
||||
|
||||
Deutsch verwendet das formelle `Sie`, weil OD eine gemischte Zielgruppe aus Solo-Creators, Agenturen und Engineering-Teams anspricht; solange Projektfeedback keine informelle `du`-Stimme nahelegt, ist formelles Deutsch die am wenigsten überraschende Vorgabe. Locale-PRs sollen UI-Chrome, zentrale Dokumentation und display-only Gallery-Metadaten in `apps/web/src/i18n/content.ts` übersetzen, aber nicht `skills/`, `design-systems/` oder Prompt-Bodies, die Agents ausführen. Diese Quell-Prompts sind Workflow-Eingaben; eine gemeinsame Quellsprache vermeidet multiplizierte Prompt-QA über alle Locales. Wenn ein Skill, Designsystem oder Prompt Template ergänzt oder umbenannt wird, aktualisieren Sie die deutschen Display-Metadaten und führen `pnpm --filter @open-design/web test` aus; `content.test.ts` schlägt fehl, wenn die deutsche Display-Coverage driftet. Daemon-Fehler, Export-Dateinamen und agent-generierte Artifact-Texte sind bekannte Grenzen, sofern ein PR sie nicht ausdrücklich umfasst.
|
||||
|
||||
---
|
||||
|
||||
## Code Style
|
||||
|
||||
Wir sind beim Formatting nicht pedantisch (Prettier on save ist okay), aber zwei Regeln sind nicht verhandelbar:
|
||||
|
||||
1. **Single quotes in JS/TS.** Strings sind single-quoted, außer Escaping macht sie hässlich.
|
||||
2. **Kommentare auf Englisch.** Auch wenn ein PR etwas ins Deutsche oder Chinesische übersetzt, bleiben Code-Kommentare englisch, damit es eine greppable Referenzsprache gibt.
|
||||
|
||||
Außerdem:
|
||||
|
||||
- **Nicht erzählen.** Kein `// import the module`, kein `// loop through items`.
|
||||
- **TypeScript** für `apps/web/src/`. Der daemon (`apps/daemon/`) ist plain ESM JavaScript mit JSDoc, wenn Typen wichtig sind.
|
||||
- **Keine neuen Top-Level Dependencies** ohne Absatz in der PR-Beschreibung, was sie bringen und wie viele Bytes sie kosten.
|
||||
- **Vor dem Push `pnpm typecheck` ausführen.** CI tut es auch.
|
||||
|
||||
---
|
||||
|
||||
## Commits & Pull Requests
|
||||
|
||||
- **Ein Anliegen pro PR.**
|
||||
- **Titel ist imperativ + Scope.** `add dating-web skill`, `fix daemon SSE backpressure when CLI hangs`, `docs: clarify .od layout`.
|
||||
- **Body erklärt das Warum.** Der Diff zeigt oft das Was, aber selten den Grund.
|
||||
- **Issue referenzieren**, falls vorhanden. Bei nicht-trivialen PRs ohne Issue bitte zuerst eines öffnen.
|
||||
- **Während Review nicht squashen.** Fixups pushen; wir squashen beim Merge.
|
||||
- **Kein Force-Push auf Shared Branches**, außer Reviewer fragen danach.
|
||||
|
||||
Wir erzwingen kein CLA. Apache-2.0 deckt Beiträge ab; Ihr Beitrag ist unter derselben Lizenz.
|
||||
|
||||
---
|
||||
|
||||
## Bugs melden
|
||||
|
||||
Öffnen Sie ein Issue mit:
|
||||
|
||||
- Exaktem `pnpm tools-dev ...` Aufruf.
|
||||
- Ausgewählter Agent-CLI oder BYOK-Pfad.
|
||||
- Skill + Designsystem, die den Fehler ausgelöst haben.
|
||||
- Relevanter **daemon stderr tail**.
|
||||
- Screenshot, wenn es UI betrifft.
|
||||
|
||||
Für Prompt-Stack-Bugs fügen Sie die **vollständige Assistant Message** bei, damit klar ist, ob Modell oder Prompt verletzt wurde.
|
||||
|
||||
---
|
||||
|
||||
## Fragen stellen
|
||||
|
||||
- Architekturfrage, Designfrage, "Bug oder Fehlbenutzung?" → [GitHub Discussions](https://github.com/nexu-io/open-design/discussions) (bevorzugt, weil suchbar).
|
||||
- "Wie schreibe ich einen Skill für X?" → Discussion öffnen. Wir beantworten sie und übernehmen fehlende Muster in [`docs/skills-protocol.md`](docs/skills-protocol.md).
|
||||
|
||||
---
|
||||
|
||||
## Was wir nicht annehmen
|
||||
|
||||
Um das Projekt fokussiert zu halten, öffnen Sie bitte keine PRs, die:
|
||||
|
||||
- **Eine Model Runtime vendoren.** OD setzt darauf, dass Ihre vorhandene CLI reicht.
|
||||
- **Das Frontend ohne vorherige Abstimmung aus dem aktuellen Stack reißen.** Next.js 16 App Router + React 18 + TS ist gesetzt.
|
||||
- **Den daemon durch eine Serverless Function ersetzen.** Der daemon besitzt ein echtes `cwd` und startet echte CLIs.
|
||||
- **Telemetry / Analytics / Phone-home hinzufügen.** OD ist local-first.
|
||||
- **Ein Binary bündeln** ohne Lizenzdatei und Autorenschaft direkt daneben.
|
||||
|
||||
Wenn Sie nicht sicher sind, ob eine Idee passt, öffnen Sie vor dem Code eine Discussion.
|
||||
|
||||
---
|
||||
|
||||
## Lizenz
|
||||
|
||||
Mit Ihrem Beitrag erklären Sie sich einverstanden, dass er unter der [Apache-2.0-Lizenz](LICENSE) dieses Repositories steht. Ausnahme sind Dateien in [`skills/guizang-ppt/`](skills/guizang-ppt/), die ihre ursprüngliche MIT-Lizenz und Autorenschaft von [op7418](https://github.com/op7418) behalten.
|
||||
|
||||
[skill]: https://docs.anthropic.com/en/docs/claude-code/skills
|
||||
[guizang]: https://github.com/op7418/guizang-ppt-skill
|
||||
[acd2]: https://github.com/VoltAgent/awesome-design-md
|
||||
[ocod]: https://github.com/OpenCoworkAI/open-codesign
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
このガイドでは、各種コントリビューションの対象場所と、PR がマージされるために満たすべき基準を正確に説明します。
|
||||
|
||||
<p align="center"><a href="CONTRIBUTING.md">English</a> · <a href="CONTRIBUTING.zh-CN.md">简体中文</a> · <b>日本語</b></p>
|
||||
<p align="center"><a href="CONTRIBUTING.md">English</a> · <a href="CONTRIBUTING.de.md">Deutsch</a> · <a href="CONTRIBUTING.zh-CN.md">简体中文</a> · <b>日本語</b></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Thanks for thinking about contributing. OD is small on purpose — most of the v
|
|||
|
||||
This guide tells you exactly where to look for each type of contribution and what bar a PR has to clear before we merge it.
|
||||
|
||||
<p align="center"><b>English</b> · <a href="CONTRIBUTING.zh-CN.md">简体中文</a> · <a href="CONTRIBUTING.ja-JP.md">日本語</a></p>
|
||||
<p align="center"><b>English</b> · <a href="CONTRIBUTING.de.md">Deutsch</a> · <a href="CONTRIBUTING.zh-CN.md">简体中文</a> · <a href="CONTRIBUTING.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ This guide tells you exactly where to look for each type of contribution and wha
|
|||
| Make OD speak a new brand's visual language | a **Design System** | [`design-systems/<brand>/DESIGN.md`](design-systems/) | one Markdown file |
|
||||
| Hook up a new coding-agent CLI | an **Agent adapter** | [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts) | ~10 lines in one array |
|
||||
| Add a feature, fix a bug, lift a UX pattern from [`open-codesign`][ocod] | code | `apps/web/src/`, `apps/daemon/` | normal PR |
|
||||
| Improve docs, port a section to 中文, fix typos | docs | `README.md`, `README.zh-CN.md`, `docs/`, `QUICKSTART.md` | one PR |
|
||||
| Improve docs, port a section to Deutsch / 中文, fix typos | docs | `README.md`, `README.de.md`, `README.zh-CN.md`, `docs/`, `QUICKSTART.md` | one PR |
|
||||
|
||||
If you're not sure which bucket your idea is in, [open a discussion / issue first](https://github.com/nexu-io/open-design/issues/new) and we'll point you at the right surface.
|
||||
|
||||
|
|
@ -193,12 +193,18 @@ Bar for merging:
|
|||
|
||||
---
|
||||
|
||||
## Localization maintenance
|
||||
|
||||
German uses formal `Sie` because OD speaks to a mixed audience of solo creators, agencies, and engineering teams; until project feedback shows that an informal `du` voice fits better, formal German is the least surprising default. Locale PRs should translate UI chrome, core docs, and display-only gallery metadata in `apps/web/src/i18n/content.ts`, but should not translate `skills/`, `design-systems/`, or prompt bodies that agents execute. Those source prompts are maintained as workflow inputs, and keeping one source language avoids multiplying prompt QA across locales. When adding or renaming a skill, design system, or prompt template, update the German display metadata and run `pnpm --filter @open-design/web test`; `content.test.ts` fails if German display coverage drifts. Daemon errors, export filenames, and agent-generated artifact text are known limitations unless a PR explicitly scopes them.
|
||||
|
||||
---
|
||||
|
||||
## Code style
|
||||
|
||||
We're not pedantic about formatting (Prettier on save is fine), but two rules are non-negotiable because they show up in the prompt stack and the user-facing API:
|
||||
|
||||
1. **Single quotes in JS/TS.** Strings are single-quoted unless escaping makes them ugly. The codebase is already consistent — please match.
|
||||
2. **Comments in English.** Even if the PR is translating something into 中文, code comments stay in English so we can keep one set of greppable references.
|
||||
2. **Comments in English.** Even if the PR is translating something into Deutsch or 中文, code comments stay in English so we can keep one set of greppable references.
|
||||
|
||||
Beyond that:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
这份指南会告诉你:每种贡献该往哪里看、合并之前 PR 需要过哪些线。
|
||||
|
||||
<p align="center"><a href="CONTRIBUTING.md">English</a> · <b>简体中文</b> · <a href="CONTRIBUTING.ja-JP.md">日本語</a></p>
|
||||
<p align="center"><a href="CONTRIBUTING.md">English</a> · <a href="CONTRIBUTING.de.md">Deutsch</a> · <b>简体中文</b> · <a href="CONTRIBUTING.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
| 让 OD 说一种新品牌的视觉语言 | 一套 **Design System** | [`design-systems/<brand>/DESIGN.md`](design-systems/) | 一个 Markdown 文件 |
|
||||
| 接入一个新的 coding-agent CLI | 一个 **Agent adapter** | [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts) | 一个数组里 ~10 行 |
|
||||
| 加功能、修 bug、从 [`open-codesign`][ocod] 移植一个 UX 模式 | 代码 | `apps/web/src/`、`apps/daemon/` | 普通 PR |
|
||||
| 改文档、补中文翻译、修错别字 | 文档 | `README.md`、`README.zh-CN.md`、`docs/`、`QUICKSTART.md` | 一个 PR |
|
||||
| 改文档、补德语 / 中文翻译、修错别字 | 文档 | `README.md`、`README.de.md`、`README.zh-CN.md`、`docs/`、`QUICKSTART.md` | 一个 PR |
|
||||
|
||||
不确定自己想做的属于哪一桶?[先开 issue / discussion](https://github.com/nexu-io/open-design/issues/new),我们告诉你该改哪个面。
|
||||
|
||||
|
|
|
|||
230
QUICKSTART.de.md
Normal file
230
QUICKSTART.de.md
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
# Schnellstart
|
||||
|
||||
<p align="center"><a href="QUICKSTART.md">English</a> · <b>Deutsch</b></p>
|
||||
|
||||
Führen Sie das vollständige Produkt lokal aus.
|
||||
|
||||
## Umgebungsanforderungen
|
||||
|
||||
- **Node.js:** `~24` (Node 24.x). Das Repository erzwingt dies über `package.json#engines`.
|
||||
- **pnpm:** `10.33.x`. Das Repository pinnt `pnpm@10.33.2` über `packageManager`; verwenden Sie Corepack, damit automatisch die gepinnte Version gewählt wird.
|
||||
- **OS:** macOS, Linux und WSL2 sind die primären Pfade. Windows nativ sollte für die meisten Abläufe funktionieren, WSL2 ist aber die sicherere Basis.
|
||||
- **Optionale lokale Agent-CLI:** Claude Code, Codex, Gemini CLI, OpenCode, Cursor Agent, Qwen, GitHub Copilot CLI usw. Wenn keine installiert ist, verwenden Sie den BYOK-API-Modus in den Einstellungen.
|
||||
|
||||
`nvm` / `fnm` sind optionale Komfortwerkzeuge, keine Voraussetzung für das Projektsetup. Wenn Sie eines davon verwenden, installieren/selektieren Sie Node 24 vor pnpm:
|
||||
|
||||
```bash
|
||||
# nvm
|
||||
nvm install 24
|
||||
nvm use 24
|
||||
|
||||
# fnm
|
||||
fnm install 24
|
||||
fnm use 24
|
||||
```
|
||||
|
||||
Aktivieren Sie dann Corepack und lassen Sie das Repository pnpm auswählen:
|
||||
|
||||
```bash
|
||||
corepack enable
|
||||
corepack pnpm --version # sollte 10.33.2 ausgeben
|
||||
```
|
||||
|
||||
## One-shot (Dev-Modus)
|
||||
|
||||
```bash
|
||||
corepack enable
|
||||
pnpm install
|
||||
pnpm tools-dev run web # startet daemon + web im Vordergrund
|
||||
# öffnen Sie die von tools-dev ausgegebene Web-URL
|
||||
```
|
||||
|
||||
Für die Desktop-Shell und alle verwalteten Sidecars im Hintergrund:
|
||||
|
||||
```bash
|
||||
pnpm tools-dev # startet daemon + web + desktop im Hintergrund
|
||||
```
|
||||
|
||||
Beim ersten Laden erkennt die App Ihre installierte Code-Agent-CLI (Claude Code / Codex / Gemini / OpenCode / Cursor Agent / Qwen), wählt sie automatisch und nutzt standardmäßig den `web-prototype` Skill sowie das `Neutral Modern` Design System. Geben Sie einen Prompt ein und klicken Sie auf **Senden**. Der Agent streamt in den linken Bereich; das `<artifact>` Tag wird herausgeparst und das HTML rechts live gerendert. Nach Abschluss können Sie das Artifact mit **Auf Datenträger speichern** unter `./.od/artifacts/<timestamp>-<slug>/index.html` speichern.
|
||||
|
||||
Das Dropdown **Designsystem** enthält 71 integrierte Systeme: 2 handgeschriebene Starter (Neutral Modern, Warm Editorial) und 69 Produktsysteme, importiert aus [`awesome-design-md`](https://github.com/VoltAgent/awesome-design-md), gruppiert nach Kategorie (AI & LLM, Developer Tools, Productivity, Backend, Design Tools, Fintech, E-Commerce, Media, Automotive). Wählen Sie eines aus, um jeden Prototyp in der Ästhetik dieser Marke zu gestalten.
|
||||
|
||||
Das Dropdown **Skill** gruppiert nach Modus (Prototyp / Deck / Template / Designsystem) und zeigt den Default-Skill pro Modus mit dem Suffix `· default`. Gebündelte Skills:
|
||||
|
||||
- **Prototype** — `web-prototype` (generisch), `saas-landing`, `dashboard`, `pricing-page`, `docs-page`, `blog-post`, `mobile-app`.
|
||||
- **Deck / PPT** — `simple-deck` (single-file horizontal swipe) und `magazine-web-ppt` (das `guizang-ppt` Bundle aus [`op7418/guizang-ppt-skill`](https://github.com/op7418/guizang-ppt-skill) — default für deck mode, bringt eigene Assets/Template + 4 References mit). Skills mit Side Files bekommen automatisch eine "Skill root (absolute)" Präambel, damit der Agent `assets/template.html` und `references/*.md` gegen den echten Pfad auf der Festplatte auflösen kann statt gegen sein CWD.
|
||||
|
||||
Kombinieren Sie Skill, Design System und einen einzelnen Prompt, und Sie erhalten einen layoutpassenden Prototyp oder ein Deck in der gewählten visuellen Sprache.
|
||||
|
||||
## Weitere Skripte
|
||||
|
||||
```bash
|
||||
pnpm tools-dev # daemon + web + desktop im Hintergrund
|
||||
pnpm tools-dev start web # daemon + web im Hintergrund
|
||||
pnpm tools-dev run web # daemon + web im Vordergrund (e2e/dev server)
|
||||
pnpm tools-dev restart # daemon + web + desktop neu starten
|
||||
pnpm tools-dev restart --daemon-port 7457 --web-port 5175
|
||||
pnpm tools-dev status # verwaltete Runtimes prüfen
|
||||
pnpm tools-dev logs # daemon/web/desktop logs anzeigen
|
||||
pnpm tools-dev check # status + aktuelle logs + gängige Diagnosen
|
||||
pnpm tools-dev stop # verwaltete Runtimes stoppen
|
||||
pnpm --filter @open-design/daemon build # apps/daemon/dist/cli.js für `od` bauen
|
||||
pnpm build # Production Build + static export nach apps/web/out/
|
||||
pnpm typecheck # Workspace-Typecheck
|
||||
```
|
||||
|
||||
`pnpm tools-dev` ist der einzige lokale Lifecycle-Einstieg. Verwenden Sie nicht die entfernten Legacy-Root-Aliasse (`pnpm dev`, `pnpm dev:all`, `pnpm daemon`, `pnpm preview`, `pnpm start`).
|
||||
|
||||
Während lokaler Entwicklung startet `tools-dev` zuerst den daemon, übergibt dessen Port an `apps/web`, und `apps/web/next.config.ts` rewritet `/api/*`, `/artifacts/*` und `/frames/*` auf diesen daemon-Port. So kann die App-Router-App ohne CORS-Setup mit dem sibling Express-Prozess sprechen.
|
||||
|
||||
## Prüfungen für Mediengenerierung und Agent-Dispatcher
|
||||
|
||||
Image-, Video-, Audio- und HyperFrames-Skills rufen die lokale `od` CLI über Umgebungsvariablen auf, die der daemon beim Start eines Agent injiziert:
|
||||
|
||||
- `OD_BIN` — absoluter Pfad zu `apps/daemon/dist/cli.js`.
|
||||
- `OD_DAEMON_URL` — die laufende daemon-URL.
|
||||
- `OD_PROJECT_ID` — die aktive Projekt-ID.
|
||||
- `OD_PROJECT_DIR` — das Dateiverzeichnis des aktiven Projekts.
|
||||
|
||||
Wenn Mediengenerierung mit `OD_BIN: parameter not set`, fehlendem `apps/daemon/dist/cli.js` oder `failed to reach daemon at http://127.0.0.1:0` fehlschlägt, bauen Sie die daemon-CLI neu und starten Sie die verwaltete Runtime neu:
|
||||
|
||||
```bash
|
||||
pnpm --filter @open-design/daemon build
|
||||
pnpm tools-dev restart --daemon-port 7457 --web-port 5175
|
||||
ls -la apps/daemon/dist/cli.js
|
||||
curl -s http://127.0.0.1:7457/api/health
|
||||
```
|
||||
|
||||
Öffnen Sie danach das Projekt erneut aus der Open Design App, statt eine alte Terminal-Agent-Session fortzusetzen. Ein vom daemon gestarteter Agent sollte Werte wie diese sehen:
|
||||
|
||||
```bash
|
||||
echo "OD_BIN=$OD_BIN"
|
||||
echo "OD_PROJECT_ID=$OD_PROJECT_ID"
|
||||
echo "OD_PROJECT_DIR=$OD_PROJECT_DIR"
|
||||
echo "OD_DAEMON_URL=$OD_DAEMON_URL"
|
||||
ls -la "$OD_BIN"
|
||||
```
|
||||
|
||||
`OD_DAEMON_URL` muss ein echter daemon-Port wie `http://127.0.0.1:7457` sein, nicht `http://127.0.0.1:0`. Der Wert `:0` ist nur ein interner Hinweis für "freien Port wählen" und darf nicht in Agent-Sessions gelangen.
|
||||
|
||||
Im daemon-only Production Mode serviert der daemon den statischen Next.js Export selbst unter `http://localhost:7456`; ein Reverse Proxy ist dafür nicht beteiligt.
|
||||
|
||||
Wenn Sie nginx vor den daemon setzen, halten Sie SSE-Routen ungepuffert und unkomprimiert. Ein häufiger Fehler ist, dass die Browser-Konsole nach 80-90 Sekunden `net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)` zeigt, weil nginx `gzip on` chunked SSE Antworten puffert, obwohl der daemon `X-Accel-Buffering: no` sendet.
|
||||
|
||||
```nginx
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:7456;
|
||||
|
||||
proxy_buffering off;
|
||||
gzip off;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
## Zwei Ausführungsmodi
|
||||
|
||||
| Modus | Picker-Wert | Ablauf einer Anfrage |
|
||||
|---|---|---|
|
||||
| **Local CLI** (Standard, wenn der daemon einen Agent erkennt) | "Local CLI" | Frontend → daemon `/api/chat` → `spawn(<agent>, ...)` → stdout → SSE → artifact parser → preview |
|
||||
| **Anthropic API** (Fallback / keine CLI) | "Anthropic API · BYOK" | Frontend → `@anthropic-ai/sdk` direkt (`dangerouslyAllowBrowser`) → artifact parser → preview |
|
||||
|
||||
Beide Modi speisen denselben `<artifact>` Parser und denselben sandboxed iframe. Unterschiedlich sind nur Transport und System-Prompt-Auslieferung: lokale CLIs haben keinen separaten Systemkanal, daher wird der zusammengesetzte Prompt in die User Message gefaltet.
|
||||
|
||||
## Prompt-Zusammensetzung
|
||||
|
||||
Bei jedem Senden baut die App einen System Prompt aus drei Schichten und sendet ihn an den Provider:
|
||||
|
||||
```
|
||||
BASE_SYSTEM_PROMPT (output contract: wrap in <artifact>, no code fences)
|
||||
+ active design system body (DESIGN.md — palette/type/layout)
|
||||
+ active skill body (SKILL.md — workflow and output rules)
|
||||
```
|
||||
|
||||
Wechseln Sie Skill oder Designsystem in der oberen Leiste, nutzt die nächste Anfrage den neuen Stack. Bodies werden pro Session im Speicher gecacht; pro Auswahl ist also nur ein daemon fetch nötig.
|
||||
|
||||
## Dateistruktur
|
||||
|
||||
```
|
||||
open-design/
|
||||
├── apps/
|
||||
│ ├── daemon/ # Node/Express — spawns local agents + serves APIs
|
||||
│ │ └── src/
|
||||
│ │ ├── cli.ts # `od` bin entry
|
||||
│ │ ├── server.ts # /api/* + static serving
|
||||
│ │ ├── agents.ts # PATH scanner for claude/codex/gemini/opencode/cursor-agent/qwen/copilot
|
||||
│ │ ├── skills.ts # SKILL.md loader (frontmatter parser)
|
||||
│ │ └── design-systems.ts # DESIGN.md loader
|
||||
│ │ ├── sidecar/ # tools-dev daemon sidecar wrapper
|
||||
│ │ └── tests/ # daemon package tests
|
||||
│ ├── web/ # Next.js 16 App Router + React client
|
||||
│ ├── app/ # App Router entrypoints
|
||||
│ ├── src/ # React + TypeScript client/runtime modules
|
||||
│ │ ├── App.tsx # orchestrates mode / skill / DS pickers + send
|
||||
│ │ ├── providers/ # daemon + BYOK API transports
|
||||
│ │ ├── prompts/ # system, discovery, directions, deck framework
|
||||
│ │ ├── artifacts/ # streaming <artifact> parser + manifests
|
||||
│ │ ├── runtime/ # iframe srcdoc, markdown, export helpers
|
||||
│ │ └── state/ # localStorage + daemon-backed project state
|
||||
│ ├── sidecar/ # tools-dev web sidecar wrapper
|
||||
│ └── next.config.ts # tools-dev rewrites + prod apps/web/out export config
|
||||
│ └── desktop/ # Electron runtime, launched/inspected by tools-dev
|
||||
├── packages/
|
||||
│ ├── contracts/ # shared web/daemon app contracts
|
||||
│ ├── sidecar-proto/ # Open Design sidecar protocol contract
|
||||
│ ├── sidecar/ # generic sidecar runtime primitives
|
||||
│ └── platform/ # generic process/platform primitives
|
||||
├── tools/dev/ # `pnpm tools-dev` lifecycle and inspect CLI
|
||||
├── e2e/ # Playwright UI + external integration/Vitest harness
|
||||
├── skills/ # SKILL.md — drops in from any Claude Code skill repo
|
||||
│ ├── web-prototype/ # generic single-screen prototype (default for prototype mode)
|
||||
│ ├── saas-landing/ # marketing page (hero / features / pricing / CTA)
|
||||
│ ├── dashboard/ # admin / analytics dashboard
|
||||
│ ├── pricing-page/ # standalone pricing + comparison
|
||||
│ ├── docs-page/ # 3-column documentation layout
|
||||
│ ├── blog-post/ # editorial long-form
|
||||
│ ├── mobile-app/ # phone-frame single screen
|
||||
│ ├── simple-deck/ # minimal horizontal-swipe deck
|
||||
│ └── guizang-ppt/ # magazine-web-ppt — bundled deck/PPT default
|
||||
│ ├── SKILL.md
|
||||
│ ├── assets/template.html
|
||||
│ └── references/{themes,layouts,components,checklist}.md
|
||||
├── design-systems/ # DESIGN.md — 9-section schema (awesome-claude-design)
|
||||
│ ├── default/ # Neutral Modern (starter)
|
||||
│ ├── warm-editorial/ # Warm Editorial (starter)
|
||||
│ ├── README.md # catalog overview
|
||||
│ └── …69 product systems # claude · cohere · linear-app · vercel · stripe · airbnb …
|
||||
├── scripts/sync-design-systems.ts # re-import from upstream getdesign tarball
|
||||
├── docs/ # product vision + spec
|
||||
├── .od/ # runtime data (gitignored, auto-created)
|
||||
│ ├── app.sqlite # projects / conversations / messages / tabs
|
||||
│ ├── artifacts/ # one-off "Save to disk" renders
|
||||
│ └── projects/<id>/ # per-project working dir + agent cwd
|
||||
├── pnpm-workspace.yaml # apps/* + packages/* + tools/* + e2e
|
||||
└── package.json # root quality scripts + `od` bin
|
||||
```
|
||||
|
||||
## Fehlerbehebung
|
||||
|
||||
- **"no agents found on PATH"** — installieren Sie eine davon: `claude`, `codex`, `gemini`, `opencode`, `cursor-agent`, `qwen`, `copilot`. Alternativ wechseln Sie in der oberen Leiste zu "Anthropic API · BYOK" und fügen in **Einstellungen** einen Key ein.
|
||||
- **daemon 500 on /api/chat** — prüfen Sie das daemon-Terminal und den stderr-Auszug; meist hat die CLI ihre Argumente abgelehnt. Unterschiedliche CLIs haben unterschiedliche argv-Formen; siehe `apps/daemon/src/agents.ts` `buildArgs`, falls Sie nachjustieren müssen.
|
||||
- **media generation says `OD_BIN` is missing or daemon URL is `:0`** — führen Sie die Media Dispatcher Checks oben aus. Setzen Sie keine alte CLI-Session fort; öffnen Sie das Projekt aus der Open Design App neu, damit der daemon frische `OD_*` Variablen injiziert.
|
||||
- **Codex lädt zu viel Plugin-Kontext** — starten Sie Open Design mit `OD_CODEX_DISABLE_PLUGINS=1 pnpm tools-dev`, damit vom daemon gestartete Codex-Prozesse mit `--disable plugins` laufen.
|
||||
- **artifact never renders** — das Modell hat Text ohne `<artifact>` Wrapper erzeugt. Prüfen Sie, ob der System Prompt ankommt (daemon log), und wechseln Sie ggf. zu einem stärkeren Modell oder strengeren Skill.
|
||||
|
||||
## Bezug zur Vision
|
||||
|
||||
Dieser Schnellstart ist der lauffähige Einstieg zur Spec in [`docs/`](docs/). Die Spec beschreibt, wohin das Projekt wächst (siehe [`docs/roadmap.md`](docs/roadmap.md)). Highlights:
|
||||
|
||||
- `docs/architecture.md` beschreibt den ausgelieferten Stack: Next.js 16 App Router vorne, lokaler daemon dahinter und `apps/web/next.config.ts` Rewrites in dev, damit der Browser mit derselben `/api` Oberfläche spricht.
|
||||
- `docs/skills-protocol.md` beschreibt das vollständige `od:` Frontmatter (typed inputs, sliders, capability gating). Dieses MVP liest nur `name` / `description` / `triggers` / `od.mode` / `od.design_system.requires`; erweitern Sie [`apps/daemon/src/skills.ts`](apps/daemon/src/skills.ts), um den Rest hinzuzufügen.
|
||||
- `docs/agent-adapters.md` sieht reicheren Dispatch vor (capability detection, streaming tool-calls). Unser `apps/daemon/src/agents.ts` ist ein minimaler Dispatcher: genug, um die Verdrahtung zu beweisen.
|
||||
- `docs/modes.md` listet vier Modi: prototype / deck / template / design-system. Wir liefern Skills für die ersten beiden; der Picker filtert bereits nach `mode`.
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
# Quickstart
|
||||
|
||||
<p align="center"><b>English</b> · <a href="QUICKSTART.de.md">Deutsch</a></p>
|
||||
|
||||
Run the full product locally.
|
||||
|
||||
## Environment requirements
|
||||
|
|
|
|||
653
README.de.md
Normal file
653
README.de.md
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
# Open Design
|
||||
|
||||
> **Die Open-Source-Alternative zu [Claude Design][cd].** Local-first, web-deploybar, BYOK auf jeder Ebene: **10 coding-agent CLIs** werden automatisch in Ihrem `PATH` erkannt (Claude Code, Codex, Cursor Agent, Gemini CLI, OpenCode, Qwen, GitHub Copilot CLI, Hermes, Kimi, Pi) und werden zur Design-Engine, gesteuert von **31 kombinierbaren Skills** und **72 brandreifen Design Systems**. Keine CLI? Ein OpenAI-kompatibler BYOK-Proxy ist dieselbe Schleife ohne Spawn.
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/assets/banner.png" alt="Open Design — editorial cover: design with the agent on your laptop" width="100%" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/nexu-io/open-design/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=ffd700&logo=github&logoColor=white" /></a>
|
||||
<a href="https://github.com/nexu-io/open-design/network/members"><img alt="Forks" src="https://img.shields.io/github/forks/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=2ecc71&logo=github&logoColor=white" /></a>
|
||||
<a href="https://github.com/nexu-io/open-design/issues"><img alt="Issues" src="https://img.shields.io/github/issues/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=ff6b6b&logo=github&logoColor=white" /></a>
|
||||
<a href="https://github.com/nexu-io/open-design/pulls"><img alt="Pull Requests" src="https://img.shields.io/github/issues-pr/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=9b59b6&logo=github&logoColor=white" /></a>
|
||||
<a href="https://github.com/nexu-io/open-design/graphs/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=3498db&logo=github&logoColor=white" /></a>
|
||||
<a href="https://github.com/nexu-io/open-design/commits/main"><img alt="Commit activity" src="https://img.shields.io/github/commit-activity/m/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=e67e22&logo=git&logoColor=white" /></a>
|
||||
<a href="https://github.com/nexu-io/open-design/commits/main"><img alt="Last commit" src="https://img.shields.io/github/last-commit/nexu-io/open-design?style=for-the-badge&labelColor=0d1117&color=8e44ad&logo=git&logoColor=white" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square" /></a>
|
||||
<a href="#supported-coding-agents"><img alt="Agents" src="https://img.shields.io/badge/agents-10%20CLIs%20%2B%20BYOK%20proxy-black?style=flat-square" /></a>
|
||||
<a href="#design-systems"><img alt="Design systems" src="https://img.shields.io/badge/design%20systems-72-orange?style=flat-square" /></a>
|
||||
<a href="#skills"><img alt="Skills" src="https://img.shields.io/badge/skills-31-teal?style=flat-square" /></a>
|
||||
<a href="QUICKSTART.md"><img alt="Quickstart" src="https://img.shields.io/badge/quickstart-3%20commands-green?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><a href="README.md">English</a> · <b>Deutsch</b> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ko.md">한국어</a> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
## Warum es existiert
|
||||
|
||||
Anthropics [Claude Design][cd] (veröffentlicht am 2026-04-17, Opus 4.7) hat gezeigt, was passiert, wenn ein LLM aufhört, Prosa zu schreiben, und anfängt, Design-Artefakte zu liefern. Es ging viral und blieb closed-source, nur bezahlt, nur Cloud, fest an Anthropics Modell und Anthropics Skills gebunden. Kein Checkout, kein Self-Hosting, kein Vercel-Deploy, kein Austausch gegen Ihren eigenen Agent.
|
||||
|
||||
**Open Design (OD) ist die Open-Source-Alternative.** Dieselbe Schleife, dasselbe artifact-first Denkmodell, aber ohne Lock-in. Wir liefern keinen Agent: Die stärksten coding agents laufen bereits auf Ihrem Laptop. Wir verbinden sie mit einem skillgesteuerten Design-Workflow, der lokal mit `pnpm tools-dev` läuft, die Web-Schicht zu Vercel deployen kann und auf jeder Ebene BYOK bleibt.
|
||||
|
||||
Geben Sie `make me a magazine-style pitch deck for our seed round` ein. Das interaktive Fragenformular erscheint, bevor das Modell auch nur ein Pixel improvisiert. Der Agent wählt eine von fünf kuratierten visuellen Richtungen. Ein live `TodoWrite` Plan streamt in die UI. Der daemon baut einen echten Projektordner auf der Festplatte mit Seed-Template, Layout-Bibliothek und Self-Check-Checklist. Der Agent liest sie, der Pre-Flight ist erzwungen, bewertet seine eigene Ausgabe mit einer fünfdimensionalen Kritik und gibt ein einzelnes `<artifact>` aus, das Sekunden später in einem sandboxed iframe rendert.
|
||||
|
||||
Das ist nicht "AI versucht, etwas zu designen". Das ist eine AI, die durch den Prompt Stack darauf trainiert wurde, sich wie ein Senior Designer mit funktionierendem Dateisystem, deterministischer Palettenbibliothek und Checklist-Kultur zu verhalten: genau die Messlatte, die Claude Design gesetzt hat, aber offen und unter Ihrer Kontrolle.
|
||||
|
||||
OD steht auf den Schultern von vier Open-Source-Projekten:
|
||||
|
||||
- [**`alchaincyf/huashu-design`**](https://github.com/alchaincyf/huashu-design) — der Design-Philosophie-Kompass. Junior-Designer Workflow, das 5-step brand-asset protocol, die anti-AI-slop checklist, die fünfdimensionale Self-Critique und die Idee "5 schools × 20 design philosophies" hinter unserem Direction Picker, alles verdichtet in [`apps/web/src/prompts/discovery.ts`](apps/web/src/prompts/discovery.ts).
|
||||
- [**`op7418/guizang-ppt-skill`**](https://github.com/op7418/guizang-ppt-skill) — der Deck-Modus. Unverändert unter [`skills/guizang-ppt/`](skills/guizang-ppt/) gebündelt, mit ursprünglicher LICENSE; magazinartige Layouts, WebGL-Hero, P0/P1/P2-Checklists.
|
||||
- [**`OpenCoworkAI/open-codesign`**](https://github.com/OpenCoworkAI/open-codesign) — UX North Star und nächster Peer. Die erste Open-Source-Alternative zu Claude Design. Wir übernehmen den Streaming-Artifact-Loop, das sandboxed-iframe Preview Pattern (vendored React 18 + Babel), das Live-Agent-Panel (todos + tool calls + unterbrechbare Generierung) und die fünf Exportformate (HTML / PDF / PPTX / ZIP / Markdown). Wir unterscheiden uns bewusst im Formfaktor: Sie sind eine Desktop-Electron-App mit gebündeltem [`pi-ai`][piai]; wir sind eine Web-App + lokaler daemon, die an Ihre vorhandene CLI delegiert.
|
||||
- [**`multica-ai/multica`**](https://github.com/multica-ai/multica) — die daemon- und runtime-Architektur. PATH-Scan-Agent-Erkennung, der lokale daemon als einziger privilegierter Prozess, die Agent-as-teammate Sichtweise.
|
||||
|
||||
## Auf einen Blick
|
||||
|
||||
| | Was Sie bekommen |
|
||||
|---|---|
|
||||
| **Code-Agent-CLIs (10)** | Claude Code · Codex CLI · Cursor Agent · Gemini CLI · OpenCode · Qwen Code · GitHub Copilot CLI · Hermes (ACP) · Kimi CLI (ACP) · Pi (RPC) — automatisch im `PATH` erkannt, mit einem Klick wechselbar |
|
||||
| **BYOK-Fallback** | OpenAI-kompatibler Proxy unter `/api/proxy/stream` — fügen Sie `baseUrl` + `apiKey` + `model` ein und jeder Anbieter (Anthropic-via-OpenAI, DeepSeek, Groq, MiMo, OpenRouter, Ihr selbst gehostetes vLLM oder jeder andere OpenAI-kompatible Provider) wird zur Engine. Internal-IP/SSRF wird am daemon-Rand blockiert. |
|
||||
| **Design Systems integriert** | **72** — 2 handgeschriebene Starter + 70 Produktsysteme (Linear, Stripe, Vercel, Airbnb, Tesla, Notion, Anthropic, Apple, Cursor, Supabase, Figma, Xiaohongshu, …), importiert aus [`awesome-design-md`][acd2] |
|
||||
| **Skills integriert** | **31** — 27 im `prototype` mode (web-prototype, saas-landing, dashboard, mobile-app, gamified-app, social-carousel, magazine-poster, dating-web, sprite-animation, motion-frames, critique, tweaks, wireframe-sketch, pm-spec, eng-runbook, finance-report, hr-onboarding, invoice, kanban-board, team-okrs, …) + 4 im `deck` mode (`guizang-ppt` · `simple-deck` · `replit-deck` · `weekly-update`). Im Picker nach `scenario` gruppiert: design / marketing / operation / engineering / product / finance / hr / sale / personal. |
|
||||
| **Visuelle Richtungen** | 5 kuratierte Schulen (Editorial Monocle · Modern Minimal · Warm Soft · Tech Utility · Brutalist Experimental), jeweils mit deterministischer OKLch-Palette + Font Stack ([`apps/web/src/prompts/directions.ts`](apps/web/src/prompts/directions.ts)) |
|
||||
| **Device frames** | iPhone 15 Pro · Pixel · iPad Pro · MacBook · Browser Chrome — pixelgenau, skillübergreifend unter [`assets/frames/`](assets/frames/) geteilt |
|
||||
| **Agent-Runtime** | Der lokale daemon startet die CLI in Ihrem Projektordner: Der Agent bekommt echte `Read`, `Write`, `Bash`, `WebFetch` gegen eine echte Festplattenumgebung, mit Windows-`ENAMETOOLONG` Fallbacks (stdin / prompt-file) in jedem Adapter |
|
||||
| **Imports** | Ziehen Sie einen [Claude Design][cd] Export-ZIP in den Welcome Dialog: `POST /api/import/claude-design` parst ihn zu einem echten Projekt, damit Ihr Agent dort weiterarbeiten kann, wo Anthropic aufgehört hat |
|
||||
| **Persistence** | SQLite in `.od/app.sqlite`: projects · conversations · messages · tabs · saved templates. Morgen wieder öffnen, todo card und offene Dateien sind genau dort, wo Sie sie verlassen haben. |
|
||||
| **Lebenszyklus** | Ein Einstiegspunkt: `pnpm tools-dev` (start / stop / run / status / logs / inspect / check) — startet daemon + web (+ desktop) unter typisierten sidecar stamps |
|
||||
| **Desktop** | Optionale Electron Shell mit sandboxed renderer + sidecar IPC (STATUS / EVAL / SCREENSHOT / CONSOLE / CLICK / SHUTDOWN) — treibt `tools-dev inspect desktop screenshot` für E2E |
|
||||
| **Bereitstellbar auf** | Lokal (`pnpm tools-dev`) · Vercel Web Layer · packaged Electron (Platzhalter, in Arbeit) |
|
||||
| **Lizenz** | Apache-2.0 |
|
||||
|
||||
[acd2]: https://github.com/VoltAgent/awesome-design-md
|
||||
|
||||
## Demo
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/01-entry-view.png" alt="01 · Entry view" /><br/>
|
||||
<sub><b>Entry view</b> — Skill wählen, Design System wählen, Brief eingeben. Dieselbe Oberfläche für Prototypen, Decks, mobile Apps, Dashboards und Editorial Pages.</sub>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/02-question-form.png" alt="02 · Turn-1 discovery form" /><br/>
|
||||
<sub><b>Turn-1 discovery form</b> — bevor das Modell ein Pixel schreibt, fixiert OD den Brief: Oberfläche, Zielgruppe, Ton, Brand-Kontext, Umfang. 30 Sekunden Radio Buttons schlagen 30 Minuten Redirects.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/03-direction-picker.png" alt="03 · Direction picker" /><br/>
|
||||
<sub><b>Direction picker</b> — wenn der Nutzer keine Brand hat, gibt der Agent ein zweites Formular mit 5 kuratierten Richtungen aus (Monocle / Modern Minimal / Tech Utility / Brutalist / Soft Warm). Ein Radio-Klick → deterministische Palette + Font Stack, kein Model-Freestyle.</sub>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/04-todo-progress.png" alt="04 · Live todo progress" /><br/>
|
||||
<sub><b>Live todo progress</b> — der Plan des Agent streamt als Live Card. <code>in_progress</code> → <code>completed</code> Updates landen in Echtzeit. Der Nutzer kann mitten im Flug günstig umleiten.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/05-preview-iframe.png" alt="05 · Sandboxed preview" /><br/>
|
||||
<sub><b>Sandboxed preview</b> — jedes <code><artifact></code> rendert in einem sauberen srcdoc iframe. Direkt im File Workspace editierbar; als HTML, PDF oder ZIP herunterladbar.</sub>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/06-design-systems-library.png" alt="06 · 72-system library" /><br/>
|
||||
<sub><b>72-system library</b> — jedes Produktsystem zeigt seine 4-Farben-Signatur. Klicken Sie für das vollständige <code>DESIGN.md</code>, Swatch Grid und Live Showcase.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/07-magazine-deck.png" alt="07 · Magazine deck" /><br/>
|
||||
<sub><b>Deck mode (guizang-ppt)</b> — der gebündelte <a href="https://github.com/op7418/guizang-ppt-skill"><code>guizang-ppt-skill</code></a> wird unverändert übernommen. Magazinlayouts, WebGL-Hero-Hintergründe, Single-File-HTML-Ausgabe, PDF-Export.</sub>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<img src="docs/screenshots/08-mobile-app.png" alt="08 · Mobile prototype" /><br/>
|
||||
<sub><b>Mobile prototype</b> — pixelgenauer iPhone 15 Pro Chrome (Dynamic Island, Statusbar-SVGs, Home Indicator). Multi-Screen-Prototypen nutzen die gemeinsamen <code>/frames/</code> Assets, damit der Agent nie ein Telefon neu zeichnet.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Skills
|
||||
|
||||
**31 Skills werden direkt mitgeliefert.** Jeder ist ein Ordner unter [`skills/`](skills/), folgt der Claude Code [`SKILL.md`][skill] Konvention und erweitert sie um ein `od:` Frontmatter, das der daemon unverändert parst: `mode`, `platform`, `scenario`, `preview.type`, `design_system.requires`, `default_for`, `featured`, `fidelity`, `speaker_notes`, `animations`, `example_prompt` ([`apps/daemon/src/skills.ts`](apps/daemon/src/skills.ts)).
|
||||
|
||||
Zwei oberste **Modes** tragen den Katalog: **`prototype`** (27 Skills, alles, was als einseitiges Artefakt rendert, von Magazin-Landing bis Phone Screen bis PM Spec Doc) und **`deck`** (4 Skills, horizontale Swipe-Präsentationen mit Deck-Framework-Chrome). Das Feld **`scenario`** gruppiert sie im Picker: `design` · `marketing` · `operation` · `engineering` · `product` · `finance` · `hr` · `sale` · `personal`.
|
||||
|
||||
### Showcase-Beispiele
|
||||
|
||||
Die visuell markanten Skills, die Sie wahrscheinlich zuerst ausführen. Jeder bringt ein echtes `example.html` mit, das Sie direkt aus dem Repo öffnen können, um genau zu sehen, was der Agent erzeugt: keine Authentifizierung, kein Setup.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/dating-web/"><img src="docs/screenshots/skills/dating-web.png" alt="dating-web" /></a><br/>
|
||||
<sub><b><a href="skills/dating-web/"><code>dating-web</code></a></b> · <i>prototype</i><br/>Consumer dating / matchmaking dashboard — linke Navigation, Ticker Bar, KPIs, 30-day mutual-matches chart, Editorial-Typografie.</sub>
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/digital-eguide/"><img src="docs/screenshots/skills/digital-eguide.png" alt="digital-eguide" /></a><br/>
|
||||
<sub><b><a href="skills/digital-eguide/"><code>digital-eguide</code></a></b> · <i>template</i><br/>Zweiseitiger Digital E-Guide — Cover (Titel, Autor, TOC Teaser) + Lesson Spread mit Pull Quote und Schritteliste. Creator / Lifestyle Tone.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/email-marketing/"><img src="docs/screenshots/skills/email-marketing.png" alt="email-marketing" /></a><br/>
|
||||
<sub><b><a href="skills/email-marketing/"><code>email-marketing</code></a></b> · <i>prototype</i><br/>Brand product-launch HTML email — Masthead, Hero Image, Headline Lockup, CTA, Specs Grid. Zentrierte Single Column, table-fallback safe.</sub>
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/gamified-app/"><img src="docs/screenshots/skills/gamified-app.png" alt="gamified-app" /></a><br/>
|
||||
<sub><b><a href="skills/gamified-app/"><code>gamified-app</code></a></b> · <i>prototype</i><br/>Drei-Frame gamified mobile-app prototype auf dunkler Showcase Stage — Cover, today's quests mit XP Ribbons + Level Bar, Quest Detail.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/mobile-onboarding/"><img src="docs/screenshots/skills/mobile-onboarding.png" alt="mobile-onboarding" /></a><br/>
|
||||
<sub><b><a href="skills/mobile-onboarding/"><code>mobile-onboarding</code></a></b> · <i>prototype</i><br/>Drei-Frame Mobile Onboarding Flow — Splash, Value Prop, Sign-in. Status Bar, Swipe Dots, Primary CTA.</sub>
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/motion-frames/"><img src="docs/screenshots/skills/motion-frames.png" alt="motion-frames" /></a><br/>
|
||||
<sub><b><a href="skills/motion-frames/"><code>motion-frames</code></a></b> · <i>prototype</i><br/>Single-Frame Motion-Design-Hero mit loopenden CSS-Animationen — rotierender Type Ring, animierter Globus, tickender Timer. Bereit für HyperFrames-Handoff.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/social-carousel/"><img src="docs/screenshots/skills/social-carousel.png" alt="social-carousel" /></a><br/>
|
||||
<sub><b><a href="skills/social-carousel/"><code>social-carousel</code></a></b> · <i>prototype</i><br/>Drei Karten im 1080×1080 Social-Media-Carousel — filmische Panels mit Display Headlines, die sich über die Serie verbinden, Brand Mark, Loop Affordance.</sub>
|
||||
</td>
|
||||
<td width="50%" valign="top">
|
||||
<a href="skills/sprite-animation/"><img src="docs/screenshots/skills/sprite-animation.png" alt="sprite-animation" /></a><br/>
|
||||
<sub><b><a href="skills/sprite-animation/"><code>sprite-animation</code></a></b> · <i>prototype</i><br/>Pixel / 8-bit Animated Explainer Slide — vollflächige Cream Stage, animiertes Pixel Mascot, kinetische japanische Display Type, loopende CSS Keyframes.</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Design- & Marketing-Oberflächen (Prototyp-Modus)
|
||||
|
||||
| Skill | Plattform | Szenario | Was er erzeugt |
|
||||
|---|---|---|---|
|
||||
| [`web-prototype`](skills/web-prototype/) | desktop | design | Single-page HTML — Landings, Marketing, Hero Pages (default für prototype) |
|
||||
| [`saas-landing`](skills/saas-landing/) | desktop | marketing | Hero / Features / Pricing / CTA Marketing Layout |
|
||||
| [`dashboard`](skills/dashboard/) | desktop | operation | Admin / Analytics mit Sidebar + dichtem Datenlayout |
|
||||
| [`pricing-page`](skills/pricing-page/) | desktop | sale | Eigenständiges Pricing + Vergleichstabellen |
|
||||
| [`docs-page`](skills/docs-page/) | desktop | engineering | 3-spaltiges Dokumentationslayout |
|
||||
| [`blog-post`](skills/blog-post/) | desktop | marketing | Editorial Long-form |
|
||||
| [`mobile-app`](skills/mobile-app/) | mobile | design | iPhone 15 Pro / Pixel gerahmte App-Screen(s) |
|
||||
| [`mobile-onboarding`](skills/mobile-onboarding/) | mobile | design | Multi-Screen Mobile Onboarding Flow (splash · value-prop · sign-in) |
|
||||
| [`gamified-app`](skills/gamified-app/) | mobile | personal | Drei-Frame gamified mobile-app prototype |
|
||||
| [`email-marketing`](skills/email-marketing/) | desktop | marketing | Brand product-launch HTML email (table-fallback safe) |
|
||||
| [`social-carousel`](skills/social-carousel/) | desktop | marketing | 3-card 1080×1080 social carousel |
|
||||
| [`magazine-poster`](skills/magazine-poster/) | desktop | marketing | Einseitiges Poster im Magazin-Stil |
|
||||
| [`motion-frames`](skills/motion-frames/) | desktop | marketing | Motion-design Hero mit loopenden CSS-Animationen |
|
||||
| [`sprite-animation`](skills/sprite-animation/) | desktop | marketing | Pixel / 8-bit Animated Explainer Slide |
|
||||
| [`dating-web`](skills/dating-web/) | desktop | personal | Consumer dating dashboard mockup |
|
||||
| [`digital-eguide`](skills/digital-eguide/) | desktop | marketing | Zweiseitiger Digital E-Guide (cover + lesson) |
|
||||
| [`wireframe-sketch`](skills/wireframe-sketch/) | desktop | design | Handgezeichnete Ideenskizze — für den "show something visible early" Pass |
|
||||
| [`critique`](skills/critique/) | desktop | design | Fünfdimensionales Self-Critique Scoresheet (Philosophy · Hierarchy · Detail · Function · Innovation) |
|
||||
| [`tweaks`](skills/tweaks/) | desktop | design | AI-emitted tweaks panel — das Modell zeigt die Parameter, die sich sinnvoll nachjustieren lassen |
|
||||
|
||||
### Deck-Oberflächen (Deck-Modus)
|
||||
|
||||
| Skill | Default für | Was er erzeugt |
|
||||
|---|---|---|
|
||||
| [`guizang-ppt`](skills/guizang-ppt/) | **default** für deck | Web-PPT im Magazinstil — unverändert aus [op7418/guizang-ppt-skill][guizang] gebündelt, ursprüngliche LICENSE bewahrt |
|
||||
| [`simple-deck`](skills/simple-deck/) | — | Minimaler horizontal-swipe deck |
|
||||
| [`replit-deck`](skills/replit-deck/) | — | Product-walkthrough deck (Replit-style) |
|
||||
| [`weekly-update`](skills/weekly-update/) | — | Team weekly cadence als swipe deck (progress · blockers · next) |
|
||||
|
||||
### Office- & Operations-Oberflächen (Prototyp-Modus, dokumentartige Szenarien)
|
||||
|
||||
| Skill | Szenario | Was er erzeugt |
|
||||
|---|---|---|
|
||||
| [`pm-spec`](skills/pm-spec/) | product | PM specification doc mit TOC + decision log |
|
||||
| [`team-okrs`](skills/team-okrs/) | product | OKR scoresheet |
|
||||
| [`meeting-notes`](skills/meeting-notes/) | operation | Meeting decision log |
|
||||
| [`kanban-board`](skills/kanban-board/) | operation | Board snapshot |
|
||||
| [`eng-runbook`](skills/eng-runbook/) | engineering | Incident runbook |
|
||||
| [`finance-report`](skills/finance-report/) | finance | Exec finance summary |
|
||||
| [`invoice`](skills/invoice/) | finance | Single-page invoice |
|
||||
| [`hr-onboarding`](skills/hr-onboarding/) | hr | Role onboarding plan |
|
||||
|
||||
Einen Skill hinzuzufügen bedeutet: ein Ordner. Lesen Sie [`docs/skills-protocol.md`](docs/skills-protocol.md) für das erweiterte Frontmatter, forken Sie einen vorhandenen Skill, starten Sie den daemon neu, und er erscheint im Picker. Der Katalog-Endpunkt ist `GET /api/skills`; die Seed-Zusammenstellung pro Skill (Template + Side-File-Referenzen) liegt in `GET /api/skills/:id/example`.
|
||||
|
||||
## Sechs tragende Ideen
|
||||
|
||||
### 1 · Wir liefern keinen Agent. Ihrer ist gut genug.
|
||||
|
||||
Der daemon durchsucht beim Start Ihren `PATH` nach [`claude`](https://docs.anthropic.com/en/docs/claude-code), [`codex`](https://github.com/openai/codex), [`cursor-agent`](https://www.cursor.com/cli), [`gemini`](https://github.com/google-gemini/gemini-cli), [`opencode`](https://opencode.ai/), [`qwen`](https://github.com/QwenLM/qwen-code), [`copilot`](https://github.com/features/copilot/cli), `hermes`, `kimi` und [`pi`](https://github.com/mariozechner/pi-ai). Was er findet, wird zur möglichen Design-Engine: über stdio mit je einem Adapter pro CLI gesteuert und im Model Picker austauschbar. Inspiriert von [`multica`](https://github.com/multica-ai/multica) und [`cc-switch`](https://github.com/farion1231/cc-switch). Keine CLI installiert? `POST /api/proxy/stream` ist dieselbe Pipeline ohne Spawn: Fügen Sie ein beliebiges OpenAI-kompatibles `baseUrl` + `apiKey` ein, und der daemon leitet SSE-Chunks zurück, wobei loopback / link-local / RFC1918 Ziele am Rand abgelehnt werden.
|
||||
|
||||
### 2 · Skills sind Dateien, keine Plugins.
|
||||
|
||||
Nach Claude Codes [`SKILL.md` Konvention](https://docs.anthropic.com/en/docs/claude-code/skills) ist jeder Skill `SKILL.md` + `assets/` + `references/`. Legen Sie einen Ordner in [`skills/`](skills/), starten Sie den daemon neu, und er erscheint im Picker. Das gebündelte `magazine-web-ppt` ist [`op7418/guizang-ppt-skill`](https://github.com/op7418/guizang-ppt-skill), unverändert eingecheckt: ursprüngliche Lizenz bewahrt, Attribution bewahrt.
|
||||
|
||||
### 3 · Design Systems sind portables Markdown, kein Theme JSON.
|
||||
|
||||
Das 9-Section `DESIGN.md` Schema aus [`VoltAgent/awesome-design-md`][acd2]: color, typography, spacing, layout, components, motion, voice, brand, anti-patterns. Jedes Artefakt liest aus dem aktiven System. System wechseln → das nächste Render nutzt die neuen Tokens. Das Dropdown bringt **Linear, Stripe, Vercel, Airbnb, Tesla, Notion, Apple, Anthropic, Cursor, Supabase, Figma, Resend, Raycast, Lovable, Cohere, Mistral, ElevenLabs, X.AI, Spotify, Webflow, Sanity, PostHog, Sentry, MongoDB, ClickHouse, Cal, Replicate, Clay, Composio, Xiaohongshu…** mit, insgesamt 72.
|
||||
|
||||
### 4 · Das interaktive Fragenformular verhindert 80% der Redirects.
|
||||
|
||||
ODs Prompt Stack enthält eine harte `RULE 1`: Jeder frische Design Brief beginnt mit einem `<question-form id="discovery">` statt mit Code. Surface · audience · tone · brand context · scale · constraints. Auch ein langer Brief lässt Designentscheidungen offen: visueller Ton, Farbhaltung, Maßstab. Genau diese Dinge fixiert das Formular in 30 Sekunden. Die Kosten einer falschen Richtung sind eine Chat-Runde, nicht ein fertiges Deck.
|
||||
|
||||
Das ist der aus [`huashu-design`](https://github.com/alchaincyf/huashu-design) destillierte **Junior-Designer mode**: Fragen vorne bündeln, früh etwas Sichtbares zeigen (selbst ein Wireframe mit grauen Blöcken), den Nutzer günstig umleiten lassen. Zusammen mit dem Brand-Asset-Protokoll (locate · download · `grep` hex · write `brand-spec.md` · vocalise) ist es der wichtigste Grund, warum Output nicht mehr nach AI-Freestyle wirkt, sondern nach einem Designer, der vor dem Malen aufgepasst hat.
|
||||
|
||||
### 5 · Der daemon lässt den Agent fühlen, als wäre er auf Ihrem Laptop, weil er es ist.
|
||||
|
||||
Der daemon startet die CLI mit `cwd` auf den Artifact-Ordner des Projekts unter `.od/projects/<id>/`. Der Agent bekommt `Read`, `Write`, `Bash`, `WebFetch`: echte Tools gegen ein echtes Dateisystem. Er kann das `assets/template.html` des Skills lesen, Ihre CSS nach Hex-Werten `grep`en, ein `brand-spec.md` schreiben, generierte Bilder ablegen und `.pptx` / `.zip` / `.pdf` Dateien erzeugen, die am Ende des Turns als Download Chips im File Workspace erscheinen. Sessions, Conversations, Messages und Tabs persistieren in einer lokalen SQLite DB: Öffnen Sie das Projekt morgen wieder, und die Todo Card des Agent ist dort, wo Sie sie verlassen haben.
|
||||
|
||||
### 6 · Der Prompt Stack ist das Produkt.
|
||||
|
||||
Was beim Senden zusammengesetzt wird, ist nicht "system + user". Es ist:
|
||||
|
||||
```
|
||||
DISCOVERY directives (turn-1 form, turn-2 brand branch, TodoWrite, 5-dim critique)
|
||||
+ identity charter (OFFICIAL_DESIGNER_PROMPT, anti-AI-slop, junior-pass)
|
||||
+ active DESIGN.md (72 systems available)
|
||||
+ active SKILL.md (31 skills available)
|
||||
+ project metadata (kind, fidelity, speakerNotes, animations, inspiration ids)
|
||||
+ skill side files (auto-injected pre-flight: read assets/template.html + references/*.md)
|
||||
+ (deck kind, no skill seed) DECK_FRAMEWORK_DIRECTIVE (nav / counter / scroll / print)
|
||||
```
|
||||
|
||||
Jede Ebene ist kombinierbar. Jede Ebene ist eine Datei, die Sie editieren können. Lesen Sie [`apps/web/src/prompts/system.ts`](apps/web/src/prompts/system.ts) und [`apps/web/src/prompts/discovery.ts`](apps/web/src/prompts/discovery.ts), um den echten Vertrag zu sehen.
|
||||
|
||||
## Architektur
|
||||
|
||||
```
|
||||
┌────────────────────── browser (Next.js 16) ──────────────────────┐
|
||||
│ chat · file workspace · iframe preview · settings · imports │
|
||||
└──────────────┬───────────────────────────────────┬───────────────┘
|
||||
│ /api/* (rewritten in dev) │
|
||||
▼ ▼
|
||||
┌──────────────────────────────────┐ /api/proxy/stream (SSE)
|
||||
│ Local daemon (Express + SQLite) │ ─→ any OpenAI-compat
|
||||
│ │ endpoint (BYOK)
|
||||
│ /api/agents /api/skills│ w/ SSRF blocking
|
||||
│ /api/design-systems /api/projects/…
|
||||
│ /api/chat (SSE) /api/proxy/stream (SSE)
|
||||
│ /api/templates /api/import/claude-design
|
||||
│ /api/artifacts/save /api/artifacts/lint
|
||||
│ /api/upload /api/projects/:id/files…
|
||||
│ /artifacts (static) /frames (static)
|
||||
│
|
||||
│ optional: sidecar IPC at /tmp/open-design/ipc/<ns>/<app>.sock
|
||||
│ (STATUS · EVAL · SCREENSHOT · CONSOLE · CLICK · SHUTDOWN)
|
||||
└─────────┬────────────────────────┘
|
||||
│ spawn(cli, [...], { cwd: .od/projects/<id> })
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ claude · codex · gemini · opencode · cursor-agent · qwen │
|
||||
│ copilot · hermes (ACP) · kimi (ACP) · pi (RPC) │
|
||||
│ reads SKILL.md + DESIGN.md, writes artifacts to disk │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
| Layer | Stack |
|
||||
|---|---|
|
||||
| Frontend | Next.js 16 App Router + React 18 + TypeScript, Vercel-deploybar |
|
||||
| Daemon | Node 24 · Express · SSE streaming · `better-sqlite3`; Tabellen: `projects` · `conversations` · `messages` · `tabs` · `templates` |
|
||||
| Agent transport | `child_process.spawn`; typisierte Event-Parser für `claude-stream-json` (Claude Code), `copilot-stream-json` (Copilot), `json-event-stream` pro-CLI Parser (Codex / Gemini / OpenCode / Cursor Agent), `acp-json-rpc` (Hermes / Kimi via Agent Client Protocol), `pi-rpc` (Pi via stdio JSON-RPC), `plain` (Qwen Code) |
|
||||
| BYOK proxy | `POST /api/proxy/stream` → OpenAI-kompatibles `/v1/chat/completions`, SSE pass-through; lehnt loopback / link-local / RFC1918 Hosts am daemon-Rand ab |
|
||||
| Storage | Plain files in `.od/projects/<id>/` + SQLite in `.od/app.sqlite` (gitignored, auto-created). Root mit `OD_DATA_DIR` für Testisolation überschreibbar |
|
||||
| Preview | Sandboxed iframe via `srcdoc` + per-Skill `<artifact>` Parser ([`apps/web/src/artifacts/parser.ts`](apps/web/src/artifacts/parser.ts)) |
|
||||
| Export | HTML (inline assets) · PDF (browser print, deck-aware) · PPTX (agent-driven via skill) · ZIP (archiver) · Markdown |
|
||||
| Lifecycle | `pnpm tools-dev start \| stop \| run \| status \| logs \| inspect \| check`; Ports über `--daemon-port` / `--web-port`, Namespaces über `--namespace` |
|
||||
| Desktop (optional) | Electron Shell — entdeckt die Web URL über sidecar IPC, kein Port-Raten; derselbe `STATUS`/`EVAL`/`SCREENSHOT`/`CONSOLE`/`CLICK`/`SHUTDOWN` Kanal treibt `tools-dev inspect desktop …` für E2E |
|
||||
|
||||
## Schnellstart
|
||||
|
||||
```bash
|
||||
git clone https://github.com/nexu-io/open-design.git
|
||||
cd open-design
|
||||
corepack enable
|
||||
corepack pnpm --version # should print 10.33.2
|
||||
pnpm install
|
||||
pnpm tools-dev run web
|
||||
# open the web URL printed by tools-dev
|
||||
```
|
||||
|
||||
Umgebungsanforderungen: Node `~24` und pnpm `10.33.x`. `nvm`/`fnm` sind nur optionale Helfer; wenn Sie eines davon nutzen, führen Sie vor `pnpm install` `nvm install 24 && nvm use 24` oder `fnm install 24 && fnm use 24` aus.
|
||||
|
||||
Für Desktop-/Background-Start, Fixed-Port-Restarts und Media-Generation-Dispatcher-Checks (`OD_BIN`, `OD_DAEMON_URL`, `apps/daemon/dist/cli.js`) siehe [`QUICKSTART.de.md`](QUICKSTART.de.md).
|
||||
|
||||
Der erste Load:
|
||||
|
||||
1. erkennt, welche Agent-CLIs Sie im `PATH` haben, und wählt automatisch eine aus.
|
||||
2. lädt 31 Skills + 72 Design Systems.
|
||||
3. öffnet den Welcome Dialog, damit Sie einen Anthropic Key einfügen können (nur für den BYOK-Fallback-Pfad nötig).
|
||||
4. **erstellt automatisch `./.od/`** — den lokalen Runtime-Ordner für die SQLite Project DB, per-project artifacts und saved renders. Es gibt keinen `od init` Schritt; der daemon `mkdir`t beim Boot alles, was er braucht.
|
||||
|
||||
Geben Sie einen Prompt ein, drücken Sie **Senden**, sehen Sie das Fragenformular erscheinen, füllen Sie es aus, sehen Sie die Todo Card streamen, sehen Sie das Artifact rendern. Klicken Sie **Auf Datenträger speichern** oder laden Sie ein Projekt-ZIP herunter.
|
||||
|
||||
### First-run state (`./.od/`)
|
||||
|
||||
Der daemon besitzt einen versteckten Ordner am Repo-Root. Alles darin ist gitignored und maschinenlokal: niemals committen.
|
||||
|
||||
```
|
||||
.od/
|
||||
├── app.sqlite ← projects · conversations · messages · open tabs
|
||||
├── artifacts/ ← one-off "Save to disk" renders (timestamped)
|
||||
└── projects/<id>/ ← per-project working dir, also the agent's cwd
|
||||
```
|
||||
|
||||
| Wenn Sie möchten… | Tun Sie das |
|
||||
|---|---|
|
||||
| Inhalt prüfen | `ls -la .od && sqlite3 .od/app.sqlite '.tables'` |
|
||||
| Sauber zurücksetzen | `pnpm tools-dev stop`, `rm -rf .od`, dann erneut `pnpm tools-dev run web` |
|
||||
| Woandershin verschieben | noch nicht unterstützt — der Pfad ist relativ zum Repo hart codiert |
|
||||
|
||||
Vollständige Dateistruktur, Skripte und Fehlerbehebung → [`QUICKSTART.de.md`](QUICKSTART.de.md).
|
||||
|
||||
## Repository-Struktur
|
||||
|
||||
```
|
||||
open-design/
|
||||
├── README.md ← English
|
||||
├── README.de.md ← Deutsch
|
||||
├── README.zh-CN.md ← 简体中文
|
||||
├── README.ko.md ← 한국어
|
||||
├── QUICKSTART.md ← run / build / deploy guide
|
||||
├── package.json ← pnpm workspace, single bin: od
|
||||
│
|
||||
├── apps/
|
||||
│ ├── daemon/ ← Node + Express, the only server
|
||||
│ │ ├── src/ ← TypeScript daemon source
|
||||
│ │ │ ├── cli.ts ← `od` bin source, compiled to dist/cli.js
|
||||
│ │ │ ├── server.ts ← /api/* routes (projects, chat, files, exports)
|
||||
│ │ │ ├── agents.ts ← PATH scanner + per-CLI argv builders
|
||||
│ │ │ ├── claude-stream.ts ← streaming JSON parser for Claude Code stdout
|
||||
│ │ │ ├── skills.ts ← SKILL.md frontmatter loader
|
||||
│ │ │ └── db.ts ← SQLite schema (projects/messages/templates/tabs)
|
||||
│ │ ├── sidecar/ ← tools-dev daemon sidecar wrapper
|
||||
│ │ └── tests/ ← daemon package tests
|
||||
│ │
|
||||
│ └── web/ ← Next.js 16 App Router + React client
|
||||
│ ├── app/ ← App Router entrypoints
|
||||
│ ├── next.config.ts ← dev rewrites + prod static export to out/
|
||||
│ └── src/ ← React + TypeScript client modules
|
||||
│ ├── App.tsx ← routing, bootstrap, settings
|
||||
│ ├── components/ ← chat, composer, picker, preview, sketch, …
|
||||
│ ├── prompts/
|
||||
│ │ ├── system.ts ← composeSystemPrompt(base, skill, DS, metadata)
|
||||
│ │ ├── discovery.ts ← turn-1 form + turn-2 branch + 5-dim critique
|
||||
│ │ └── directions.ts ← 5 visual directions × OKLch palette + font stack
|
||||
│ ├── artifacts/ ← streaming <artifact> parser + manifests
|
||||
│ ├── runtime/ ← iframe srcdoc, markdown, export helpers
|
||||
│ ├── providers/ ← daemon SSE + BYOK API transports
|
||||
│ └── state/ ← config + projects (localStorage + daemon-backed)
|
||||
│
|
||||
├── e2e/ ← Playwright UI + external integration/Vitest harness
|
||||
│
|
||||
├── packages/
|
||||
│ ├── contracts/ ← shared web/daemon app contracts
|
||||
│ ├── sidecar-proto/ ← Open Design sidecar protocol contract
|
||||
│ ├── sidecar/ ← generic sidecar runtime primitives
|
||||
│ └── platform/ ← generic process/platform primitives
|
||||
│
|
||||
├── skills/ ← 31 SKILL.md skill bundles (27 prototype + 4 deck)
|
||||
│ ├── web-prototype/ ← default for prototype mode
|
||||
│ ├── saas-landing/ dashboard/ pricing-page/ docs-page/ blog-post/
|
||||
│ ├── mobile-app/ mobile-onboarding/ gamified-app/
|
||||
│ ├── email-marketing/ social-carousel/ magazine-poster/
|
||||
│ ├── motion-frames/ sprite-animation/ digital-eguide/ dating-web/
|
||||
│ ├── critique/ tweaks/ wireframe-sketch/
|
||||
│ ├── pm-spec/ team-okrs/ meeting-notes/ kanban-board/
|
||||
│ ├── eng-runbook/ finance-report/ invoice/ hr-onboarding/
|
||||
│ ├── simple-deck/ replit-deck/ weekly-update/ ← deck mode
|
||||
│ └── guizang-ppt/ ← bundled magazine-web-ppt (default for deck)
|
||||
│ ├── SKILL.md
|
||||
│ ├── assets/template.html ← seed
|
||||
│ └── references/{themes,layouts,components,checklist}.md
|
||||
│
|
||||
├── design-systems/ ← 72 DESIGN.md systems
|
||||
│ ├── default/ ← Neutral Modern (starter)
|
||||
│ ├── warm-editorial/ ← Warm Editorial (starter)
|
||||
│ ├── linear-app/ vercel/ stripe/ airbnb/ notion/ cursor/ apple/ …
|
||||
│ └── README.md ← catalog overview
|
||||
│
|
||||
├── assets/
|
||||
│ └── frames/ ← shared device frames (used cross-skill)
|
||||
│ ├── iphone-15-pro.html
|
||||
│ ├── android-pixel.html
|
||||
│ ├── ipad-pro.html
|
||||
│ ├── macbook.html
|
||||
│ └── browser-chrome.html
|
||||
│
|
||||
├── templates/
|
||||
│ └── deck-framework.html ← deck baseline (nav / counter / print)
|
||||
│
|
||||
├── scripts/
|
||||
│ └── sync-design-systems.ts ← re-import upstream awesome-design-md tarball
|
||||
│
|
||||
├── docs/
|
||||
│ ├── spec.md ← product spec, scenarios, differentiation
|
||||
│ ├── architecture.md ← topologies, data flow, components
|
||||
│ ├── skills-protocol.md ← extended SKILL.md od: frontmatter
|
||||
│ ├── agent-adapters.md ← per-CLI detection + dispatch
|
||||
│ ├── modes.md ← prototype / deck / template / design-system
|
||||
│ ├── references.md ← long-form provenance
|
||||
│ ├── roadmap.md ← phased delivery
|
||||
│ ├── schemas/ ← JSON schemas
|
||||
│ └── examples/ ← canonical artifact examples
|
||||
│
|
||||
└── .od/ ← runtime data, gitignored, auto-created
|
||||
├── app.sqlite ← projects / conversations / messages / tabs
|
||||
├── projects/<id>/ ← per-project working folder (agent's cwd)
|
||||
└── artifacts/ ← saved one-off renders
|
||||
```
|
||||
|
||||
## Designsysteme
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/assets/design-systems-library.png" alt="The 72 design systems library — style guide spread" width="100%" />
|
||||
</p>
|
||||
|
||||
72 Systeme direkt mitgeliefert, jedes als ein einzelnes [`DESIGN.md`](design-systems/README.md):
|
||||
|
||||
<details>
|
||||
<summary><b>Vollständiger Katalog</b> (zum Aufklappen klicken)</summary>
|
||||
|
||||
**AI & LLM** — `claude` · `cohere` · `mistral-ai` · `minimax` · `together-ai` · `replicate` · `runwayml` · `elevenlabs` · `ollama` · `x-ai`
|
||||
|
||||
**Developer Tools** — `cursor` · `vercel` · `linear-app` · `framer` · `expo` · `clickhouse` · `mongodb` · `supabase` · `hashicorp` · `posthog` · `sentry` · `warp` · `webflow` · `sanity` · `mintlify` · `lovable` · `composio` · `opencode-ai` · `voltagent`
|
||||
|
||||
**Productivity** — `notion` · `figma` · `miro` · `airtable` · `superhuman` · `intercom` · `zapier` · `cal` · `clay` · `raycast`
|
||||
|
||||
**Fintech** — `stripe` · `coinbase` · `binance` · `kraken` · `mastercard` · `revolut` · `wise`
|
||||
|
||||
**E-Commerce** — `shopify` · `airbnb` · `uber` · `nike` · `starbucks` · `pinterest`
|
||||
|
||||
**Media** — `spotify` · `playstation` · `wired` · `theverge` · `meta`
|
||||
|
||||
**Automotive** — `tesla` · `bmw` · `ferrari` · `lamborghini` · `bugatti` · `renault`
|
||||
|
||||
**Other** — `apple` · `ibm` · `nvidia` · `vodafone` · `sentry` · `resend` · `spacex`
|
||||
|
||||
**Starters** — `default` (Neutral Modern) · `warm-editorial`
|
||||
|
||||
</details>
|
||||
|
||||
Die Bibliothek wird über [`scripts/sync-design-systems.ts`](scripts/sync-design-systems.ts) aus [`VoltAgent/awesome-design-md`][acd2] importiert. Führen Sie es erneut aus, um zu aktualisieren.
|
||||
|
||||
## Visuelle Richtungen
|
||||
|
||||
Wenn der Nutzer keine Brand Spec hat, gibt der Agent ein zweites Formular mit fünf kuratierten Richtungen aus: die OD-Adaption von [`huashu-design`s "5 schools × 20 design philosophies" fallback](https://github.com/alchaincyf/huashu-design#%E8%AE%BE%E8%AE%A1%E6%96%B9%E5%90%91%E9%A1%BE%E9%97%AE-fallback). Jede Richtung ist eine deterministische Spec: Palette in OKLch, Font Stack, Layout-Posture-Cues, Referenzen. Der Agent bindet sie unverändert in das `:root` des Seed Templates. Ein Radio-Klick → ein vollständig spezifiziertes visuelles System. Keine Improvisation, kein AI-slop.
|
||||
|
||||
| Richtung | Stimmung | Referenzen |
|
||||
|---|---|---|
|
||||
| Editorial — Monocle / FT | Printmagazin, Tinte + Cream + warmer Rust | Monocle · FT Weekend · NYT Magazine |
|
||||
| Modern minimal — Linear / Vercel | Kühl, strukturiert, minimaler Akzent | Linear · Vercel · Stripe |
|
||||
| Tech utility | Informationsdichte, Monospace, Terminal | Bloomberg · Bauhaus tools |
|
||||
| Brutalist | Roh, übergroße Type, keine Schatten, harte Akzente | Bloomberg Businessweek · Achtung |
|
||||
| Soft warm | Großzügig, niedriger Kontrast, peachy Neutrals | Notion marketing · Apple Health |
|
||||
|
||||
Vollständige Spec → [`apps/web/src/prompts/directions.ts`](apps/web/src/prompts/directions.ts).
|
||||
|
||||
## Jenseits des Chats — was sonst mitgeliefert wird
|
||||
|
||||
Der Chat-/Artifact-Loop steht im Rampenlicht, aber einige weniger sichtbare Fähigkeiten sind bereits verdrahtet und wichtig, bevor Sie OD mit etwas anderem vergleichen:
|
||||
|
||||
- **Claude Design ZIP import.** Ziehen Sie einen Export von claude.ai in den Welcome Dialog. `POST /api/import/claude-design` extrahiert ihn in ein echtes `.od/projects/<id>/`, öffnet die Entry-Datei als Tab und bereitet einen Continue-where-Anthropic-left-off Prompt für Ihren lokalen Agent vor. Kein erneutes Prompting, kein "ask the model to re-create what we just had". ([`apps/daemon/src/server.ts`](apps/daemon/src/server.ts) — `/api/import/claude-design`)
|
||||
- **OpenAI-kompatibler BYOK proxy.** `POST /api/proxy/stream` nimmt `{ baseUrl, apiKey, model, messages }`, normalisiert den Pfad (`…/v1/chat/completions`), leitet SSE-Chunks an den Browser zurück und lehnt loopback / link-local / RFC1918 Ziele ab, um SSRF zu verhindern. Alles, was das OpenAI Chat Schema spricht, funktioniert: Anthropic-via-OpenAI shim, DeepSeek, Groq, MiMo, OpenRouter, Ihr selbst gehostetes vLLM. MiMo bekommt automatisch `tool_choice: 'none'`, weil sein Tool Schema bei freier Generierung Probleme macht.
|
||||
- **User-saved templates.** Wenn Ihnen ein Render gefällt, snapshottet `POST /api/templates` HTML + Metadata in die SQLite `templates` Tabelle. Das nächste Projekt wählt es aus einer "your templates" Zeile im Picker: dieselbe Oberfläche wie die mitgelieferten 31, aber Ihre eigene.
|
||||
- **Tab persistence.** Jedes Projekt merkt sich offene Dateien und aktiven Tab in der `tabs` Tabelle. Öffnen Sie das Projekt morgen wieder, und der Workspace sieht genau so aus, wie Sie ihn verlassen haben.
|
||||
- **Artifact lint API.** `POST /api/artifacts/lint` führt strukturelle Checks auf einem generierten Artifact aus (kaputtes `<artifact>` Framing, fehlende Side Files, stale palette tokens) und gibt Findings zurück, die der Agent in seinen nächsten Turn einlesen kann. Die fünfdimensionale Self-Critique nutzt das, um ihren Score auf echte Evidenz statt Vibes zu stützen.
|
||||
- **Sidecar protocol + desktop automation.** Daemon-, Web- und Desktop-Prozesse tragen typisierte Five-Field-Stamps (`app · mode · namespace · ipc · source`) und expose'n einen JSON-RPC IPC Channel unter `/tmp/open-design/ipc/<namespace>/<app>.sock`. `tools-dev inspect desktop status \| eval \| screenshot` steuert diesen Channel, sodass Headless-E2E gegen eine echte Electron Shell funktioniert, ohne bespoke Harnesses ([`packages/sidecar-proto/`](packages/sidecar-proto/), [`apps/desktop/src/main/`](apps/desktop/src/main/)).
|
||||
- **Windows-friendly spawning.** Jeder Adapter, der sonst am ~32 KB argv Limit von `CreateProcess` bei langen zusammengesetzten Prompts scheitern würde (Codex, Gemini, OpenCode, Cursor Agent, Qwen, Pi), füttert den Prompt stattdessen über stdin. Claude Code und Copilot behalten `-p`; der daemon fällt auf eine temp prompt-file zurück, wenn selbst das überläuft.
|
||||
- **Per-namespace runtime data.** `OD_DATA_DIR` und `--namespace` geben Ihnen vollständig isolierte `.od/`-artige Trees, damit Playwright, Beta Channels und Ihre echten Projekte nie dieselbe SQLite-Datei teilen.
|
||||
|
||||
## Anti-AI-Slop-Maschinerie
|
||||
|
||||
Die gesamte Maschinerie unten ist das [`huashu-design`](https://github.com/alchaincyf/huashu-design) Playbook, portiert in ODs Prompt Stack und pro Skill über Side-File-Pre-Flight erzwingbar. Lesen Sie [`apps/web/src/prompts/discovery.ts`](apps/web/src/prompts/discovery.ts) für die Live-Formulierung:
|
||||
|
||||
- **Question form first.** Turn 1 ist nur `<question-form>`: kein Denken, keine Tools, keine Narration. Der Nutzer wählt Defaults mit Radio-Geschwindigkeit.
|
||||
- **Brand-spec extraction.** Wenn der Nutzer Screenshot oder URL anhängt, führt der Agent ein fünfstufiges Protokoll aus (locate · download · grep hex · codify `brand-spec.md` · vocalise), bevor er CSS schreibt. **Er rät Brandfarben niemals aus Erinnerung.**
|
||||
- **Five-dim critique.** Vor dem Ausgeben von `<artifact>` bewertet der Agent seine Ausgabe still 1–5 über philosophy / hierarchy / execution / specificity / restraint. Alles unter 3/5 ist eine Regression: fixen und neu scoren. Zwei Durchgänge sind normal.
|
||||
- **P0/P1/P2 checklist.** Jeder Skill liefert ein `references/checklist.md` mit harten P0 Gates. Der Agent muss P0 bestehen, bevor er ausgibt.
|
||||
- **Slop blacklist.** Aggressive violette Gradients, generische Emoji Icons, runde Karte mit linkem Border Accent, handgezeichnete SVG-Menschen, Inter als *display* Face, erfundene Metriken: im Prompt ausdrücklich verboten.
|
||||
- **Honest placeholders > fake stats.** Wenn der Agent keine echte Zahl hat, schreibt er `—` oder einen beschrifteten grauen Block, nicht "10× faster".
|
||||
|
||||
## Vergleich
|
||||
|
||||
| Achse | [Claude Design][cd] (Anthropic) | [Open CoDesign][ocod] | **Open Design** |
|
||||
|---|---|---|---|
|
||||
| Lizenz | Closed | MIT | **Apache-2.0** |
|
||||
| Formfaktor | Web (claude.ai) | Desktop (Electron) | **Web-App + lokaler Daemon** |
|
||||
| Auf Vercel deploybar | ❌ | ❌ | **✅** |
|
||||
| Agent-Runtime | Gebündelt (Opus 4.7) | Gebündelt ([`pi-ai`][piai]) | **Delegiert an die vorhandene CLI des Nutzers** |
|
||||
| Skills | Proprietär | 12 Custom-TS-Module + `SKILL.md` | **31 dateibasierte [`SKILL.md`][skill] Bundles, einfach ablegbar** |
|
||||
| Designsystem | Proprietär | `DESIGN.md` (v0.2 Roadmap) | **`DESIGN.md` × 72 ausgelieferte Systeme** |
|
||||
| Provider-Flexibilität | Nur Anthropic | 7+ über [`pi-ai`][piai] | **10 CLI-Adapter + OpenAI-kompatibler BYOK-Proxy** |
|
||||
| Initiales Fragenformular | ❌ | ❌ | **✅ Harte Regel, Turn 1** |
|
||||
| Richtungswahl | ❌ | ❌ | **✅ 5 deterministische Richtungen** |
|
||||
| Live-Todo-Fortschritt + Tool-Stream | ❌ | ✅ | **✅** (UX-Pattern aus open-codesign) |
|
||||
| Sandboxed-iframe-Vorschau | ❌ | ✅ | **✅** (Pattern aus open-codesign) |
|
||||
| Claude Design ZIP-Import | n/a | ❌ | **✅ `POST /api/import/claude-design` — dort weiterbearbeiten, wo Anthropic aufgehört hat** |
|
||||
| Chirurgische Edits im Kommentar-Modus | ❌ | ✅ | 🚧 Roadmap (aus [`open-codesign`][ocod] übernehmen) |
|
||||
| AI-emitted Tweaks Panel | ❌ | ✅ | 🟡 Teilweise — [`tweaks` skill](skills/tweaks/) wird geliefert, dedizierte chatseitige Panel-UX bleibt Roadmap |
|
||||
| Dateisystemnaher Workspace | ❌ | Teilweise (Electron-Sandbox) | **✅ Echtes cwd, echte Tools, persistentes SQLite (projects · conversations · messages · tabs · templates)** |
|
||||
| 5-dimensionale Self-Critique | ❌ | ❌ | **✅ Pre-Emit-Gate** |
|
||||
| Artifact Lint | ❌ | ❌ | **✅ `POST /api/artifacts/lint` — Findings fließen zurück zum Agent** |
|
||||
| Sidecar-IPC + headless Desktop | ❌ | ❌ | **✅ Gestempelte Prozesse + `tools-dev inspect desktop status \| eval \| screenshot`** |
|
||||
| Exportformate | Begrenzt | HTML / PDF / PPTX / ZIP / Markdown | **HTML / PDF / PPTX (agent-driven) / ZIP / Markdown** |
|
||||
| PPT-Skill-Wiederverwendung | N/A | Built-in | **[`guizang-ppt-skill`][guizang] wird eingehängt (Default für deck mode)** |
|
||||
| Mindestabrechnung | Pro / Max / Team | BYOK | **BYOK — jede OpenAI-kompatible `baseUrl` einfügen** |
|
||||
|
||||
[cd]: https://x.com/claudeai/status/2045156267690213649
|
||||
[ocod]: https://github.com/OpenCoworkAI/open-codesign
|
||||
[piai]: https://github.com/mariozechner/pi-ai
|
||||
[acd]: https://github.com/VoltAgent/awesome-claude-design
|
||||
[guizang]: https://github.com/op7418/guizang-ppt-skill
|
||||
[skill]: https://docs.anthropic.com/en/docs/claude-code/skills
|
||||
|
||||
## Unterstützte Code-Agenten
|
||||
|
||||
Beim daemon Boot automatisch aus `PATH` erkannt. Keine Konfiguration nötig. Streaming Dispatch lebt in [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts) (`AGENT_DEFS`); per-CLI Parser liegen daneben. Modelle werden entweder durch Probing von `<bin> --list-models` / `<bin> models` / ACP Handshake befüllt oder aus einer kuratierten Fallback-Liste, wenn die CLI keine Liste ausgibt.
|
||||
|
||||
| Agent | Bin | Stream-Format | Argv-Form (zusammengesetzter Prompt-Pfad) |
|
||||
|---|---|---|---|
|
||||
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `claude` | `claude-stream-json` (typed events) | `claude -p <prompt> --output-format stream-json --verbose [--include-partial-messages] [--add-dir …] --permission-mode bypassPermissions` |
|
||||
| [Codex CLI](https://github.com/openai/codex) | `codex` | `json-event-stream` + `codex` Parser | `codex exec --json --skip-git-repo-check --full-auto [-C cwd] [--model …] [-c model_reasoning_effort=…] -` (Prompt über stdin) |
|
||||
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `gemini` | `json-event-stream` + `gemini` Parser | `gemini --output-format stream-json --skip-trust --yolo [--model …] -` (Prompt über stdin) |
|
||||
| [OpenCode](https://opencode.ai/) | `opencode` | `json-event-stream` + `opencode` Parser | `opencode run --format json --dangerously-skip-permissions [--model …] -` (Prompt über stdin) |
|
||||
| [Cursor Agent](https://www.cursor.com/cli) | `cursor-agent` | `json-event-stream` + `cursor-agent` Parser | `cursor-agent --print --output-format stream-json --stream-partial-output --force --trust [--workspace cwd] [--model …] -` (Prompt über stdin) |
|
||||
| [Qwen Code](https://github.com/QwenLM/qwen-code) | `qwen` | `plain` (rohe stdout Chunks) | `qwen --yolo [--model …] -` (Prompt über stdin) |
|
||||
| [GitHub Copilot CLI](https://github.com/features/copilot/cli) | `copilot` | `copilot-stream-json` (typed events) | `copilot -p <prompt> --allow-all-tools --output-format json [--model …] [--add-dir …]` |
|
||||
| [Hermes](https://github.com/eqlabs/hermes) | `hermes` | `acp-json-rpc` (Agent Client Protocol) | `hermes acp --accept-hooks` |
|
||||
| Kimi CLI | `kimi` | `acp-json-rpc` | `kimi acp` |
|
||||
| [Pi](https://github.com/mariozechner/pi-ai) | `pi` | `pi-rpc` (stdio JSON-RPC) | `pi --mode rpc --no-session [--model …] [--thinking …]` (Prompt als RPC-`prompt` Befehl gesendet) |
|
||||
| **OpenAI-compatible BYOK** | n/a | SSE pass-through | `POST /api/proxy/stream` → `<baseUrl>/v1/chat/completions`; SSRF-guarded against loopback / link-local / RFC1918 |
|
||||
|
||||
Eine neue CLI ist ein Eintrag in [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts). Streaming Format ist eines von `claude-stream-json`, `copilot-stream-json`, `json-event-stream` (mit per-CLI `eventParser`), `acp-json-rpc`, `pi-rpc` oder `plain`.
|
||||
|
||||
## Referenzen & Herkunft
|
||||
|
||||
Jedes externe Projekt, aus dem dieses Repo etwas übernimmt. Jeder Link führt zur Quelle, damit Sie die Provenienz prüfen können.
|
||||
|
||||
| Projekt | Rolle hier |
|
||||
|---|---|
|
||||
| [`Claude Design`][cd] | Das closed-source Produkt, zu dem dieses Repo die Open-Source-Alternative ist. |
|
||||
| [**`alchaincyf/huashu-design`**](https://github.com/alchaincyf/huashu-design) | Der Design-Philosophie-Kern. Junior-Designer Workflow, 5-step brand-asset protocol, anti-AI-slop checklist, fünfdimensionale Self-Critique und die "5 schools × 20 design philosophies" Bibliothek hinter unserem Direction Picker, alles verdichtet in [`apps/web/src/prompts/discovery.ts`](apps/web/src/prompts/discovery.ts) und [`apps/web/src/prompts/directions.ts`](apps/web/src/prompts/directions.ts). |
|
||||
| [**`op7418/guizang-ppt-skill`**][guizang] | Web-PPT-Skill im Magazinstil, unverändert unter [`skills/guizang-ppt/`](skills/guizang-ppt/) gebündelt, ursprüngliche LICENSE bewahrt. Default für den Deck-Modus. P0/P1/P2 Checklist-Kultur für jeden anderen Skill übernommen. |
|
||||
| [**`multica-ai/multica`**](https://github.com/multica-ai/multica) | Die daemon + adapter Architektur. PATH-Scan-Agent-Erkennung, lokaler daemon als einziger privilegierter Prozess, Agent-as-teammate Sichtweise. Wir übernehmen das Modell, nicht den Code. |
|
||||
| [**`OpenCoworkAI/open-codesign`**][ocod] | Die erste Open-Source-Alternative zu Claude Design und unser nächster Peer. Übernommene UX Patterns: streaming-artifact loop, sandboxed-iframe preview (vendored React 18 + Babel), live agent panel (todos + tool calls + interruptible), fünf Exportformate (HTML/PDF/PPTX/ZIP/Markdown), local-first storage hub, `SKILL.md` taste-injection. UX Patterns auf unserer Roadmap: comment-mode surgical edits, AI-emitted tweaks panel. **Wir vendoren [`pi-ai`][piai] bewusst nicht**: open-codesign bündelt es als Agent Runtime; wir delegieren an die CLI, die der Nutzer bereits hat. |
|
||||
| [`VoltAgent/awesome-claude-design`][acd] / [`awesome-design-md`][acd2] | Quelle des 9-Section `DESIGN.md` Schemas und der 69 Produktsysteme, die über [`scripts/sync-design-systems.ts`](scripts/sync-design-systems.ts) importiert wurden. |
|
||||
| [`farion1231/cc-switch`](https://github.com/farion1231/cc-switch) | Inspiration für symlink-basierte Skill-Verteilung über mehrere Agent-CLIs. |
|
||||
| [Claude Code skills][skill] | Die `SKILL.md` Konvention wurde unverändert übernommen: Jeder Claude Code Skill kann in `skills/` gelegt werden und wird vom daemon gefunden. |
|
||||
|
||||
Der ausführliche Provenienztext, was wir jeweils übernehmen und was bewusst nicht, steht in [`docs/references.md`](docs/references.md).
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] Daemon + agent detection (10 CLI adapters) + skill registry + design-system catalog
|
||||
- [x] Web app + chat + question form + 5-direction picker + todo progress + sandboxed preview
|
||||
- [x] 31 skills + 72 design systems + 5 visual directions + 5 device frames
|
||||
- [x] SQLite-backed projects · conversations · messages · tabs · templates
|
||||
- [x] OpenAI-compatible BYOK proxy (`/api/proxy/stream`) with SSRF guard
|
||||
- [x] Claude Design ZIP import (`/api/import/claude-design`)
|
||||
- [x] Sidecar protocol + Electron desktop with IPC automation (STATUS / EVAL / SCREENSHOT / CONSOLE / CLICK / SHUTDOWN)
|
||||
- [x] Artifact lint API + 5-dim self-critique pre-emit gate
|
||||
- [ ] Comment-mode surgical edits (click element → instruction → patch) — pattern from [`open-codesign`][ocod]
|
||||
- [ ] AI-emitted tweaks panel UX — building block ([`tweaks` skill](skills/tweaks/)) ships; chat-integrated panel still pending
|
||||
- [ ] Vercel + tunnel deployment recipe (Topology B)
|
||||
- [ ] One-command `npx od init` to scaffold a project with `DESIGN.md`
|
||||
- [ ] Skill marketplace (`od skills install <github-repo>`) and `od skill add | list | remove | test` CLI surface (drafted in [`docs/skills-protocol.md`](docs/skills-protocol.md), implementation pending)
|
||||
- [ ] Packaged Electron build out of `apps/packaged/`
|
||||
|
||||
Phased delivery → [`docs/roadmap.md`](docs/roadmap.md).
|
||||
|
||||
## Status
|
||||
|
||||
Dies ist eine frühe Implementierung: Der geschlossene Loop (detect → pick skill + design system → chat → parse `<artifact>` → preview → save) läuft end-to-end. Prompt Stack und Skill-Bibliothek tragen den größten Wert und sind stabil. Die komponentenbezogene UI wird täglich ausgeliefert.
|
||||
|
||||
## Geben Sie uns einen Star
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/nexu-io/open-design"><img src="docs/assets/star-us.png" alt="Star Open Design on GitHub — github.com/nexu-io/open-design" width="100%" /></a>
|
||||
</p>
|
||||
|
||||
Wenn Ihnen das dreißig Minuten gespart hat, geben Sie ein ★. Stars bezahlen keine Miete, aber sie zeigen dem nächsten Designer, Agent und Contributor, dass dieses Experiment Aufmerksamkeit verdient. Ein Klick, drei Sekunden, echtes Signal: [github.com/nexu-io/open-design](https://github.com/nexu-io/open-design).
|
||||
|
||||
## Mitwirken
|
||||
|
||||
Issues, PRs, neue Skills und neue Design Systems sind willkommen. Die wirkungsvollsten Beiträge sind meist ein Ordner, eine Markdown-Datei oder ein PR-großer Adapter:
|
||||
|
||||
- **Add a skill** — legen Sie einen Ordner in [`skills/`](skills/) an, der der [`SKILL.md`][skill] Konvention folgt.
|
||||
- **Add a design system** — legen Sie ein `DESIGN.md` in [`design-systems/<brand>/`](design-systems/) nach dem 9-Section Schema ab.
|
||||
- **Wire up a new coding-agent CLI** — ein Eintrag in [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts).
|
||||
|
||||
Vollständiger Walkthrough, Merge-Messlatte, Code Style und was wir nicht annehmen → [`CONTRIBUTING.de.md`](CONTRIBUTING.de.md) ([English](CONTRIBUTING.md), [简体中文](CONTRIBUTING.zh-CN.md)).
|
||||
|
||||
## Mitwirkende
|
||||
|
||||
Danke an alle, die Open Design vorangebracht haben: durch Code, Docs, Feedback, neue Skills, neue Design Systems oder auch ein scharfes Issue. Jeder echte Beitrag zählt, und die Wand unten ist die einfachste Art, das laut zu sagen.
|
||||
|
||||
<a href="https://github.com/nexu-io/open-design/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=nexu-io/open-design&cache_bust=2026-04-30" alt="Open Design contributors" />
|
||||
</a>
|
||||
|
||||
Wenn Sie Ihren ersten PR gemergt haben: willkommen. Das Label [`good-first-issue`](https://github.com/nexu-io/open-design/labels/good-first-issue) ist der Einstiegspunkt.
|
||||
|
||||
## Repository-Aktivität
|
||||
|
||||
<picture>
|
||||
<img alt="Open Design — repository metrics" src="docs/assets/github-metrics.svg" />
|
||||
</picture>
|
||||
|
||||
Das SVG oben wird täglich von [`.github/workflows/metrics.yml`](.github/workflows/metrics.yml) mit [`lowlighter/metrics`](https://github.com/lowlighter/metrics) regeneriert. Lösen Sie auf dem **Actions** Tab manuell eine Aktualisierung aus, wenn Sie sie früher brauchen; für reichere Plugins (traffic, follow-up time) fügen Sie ein `METRICS_TOKEN` Repository Secret mit einem fine-grained PAT hinzu.
|
||||
|
||||
## Star-Historie
|
||||
|
||||
<a href="https://star-history.com/#nexu-io/open-design&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=nexu-io/open-design&type=Date&theme=dark&cache_bust=2026-04-30" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=nexu-io/open-design&type=Date&cache_bust=2026-04-30" />
|
||||
<img alt="Open Design star history" src="https://api.star-history.com/svg?repos=nexu-io/open-design&type=Date&cache_bust=2026-04-30" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
Wenn die Kurve nach oben biegt, ist das das Signal, nach dem wir suchen. ★ dieses Repo, um sie anzuschieben.
|
||||
|
||||
## Lizenz
|
||||
|
||||
Apache-2.0. Das gebündelte [`skills/guizang-ppt/`](skills/guizang-ppt/) behält seine ursprüngliche [LICENSE](skills/guizang-ppt/LICENSE) (MIT) und Autorenschaftszuordnung zu [op7418](https://github.com/op7418).
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<a href="QUICKSTART.md"><img alt="Quickstart" src="https://img.shields.io/badge/quickstart-3%20commands-green?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><a href="README.md">English</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ko.md">한국어</a> · <b>日本語</b></p>
|
||||
<p align="center"><a href="README.md">English</a> · <a href="README.de.md">Deutsch</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ko.md">한국어</a> · <b>日本語</b></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<a href="QUICKSTART.md"><img alt="Quickstart" src="https://img.shields.io/badge/quickstart-3%20commands-green?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><a href="README.md">English</a> · <a href="README.zh-CN.md">简体中文</a> · <b>한국어</b> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
<p align="center"><a href="README.md">English</a> · <a href="README.de.md">Deutsch</a> · <a href="README.zh-CN.md">简体中文</a> · <b>한국어</b> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -341,6 +341,7 @@ Daemon은 저장소 루트에 하나의 숨겨진 폴더를 소유합니다. 그
|
|||
```
|
||||
open-design/
|
||||
├── README.md ← 영어
|
||||
├── README.de.md ← Deutsch
|
||||
├── README.zh-CN.md ← 简体中文
|
||||
├── README.ko.md ← 한국어 (이 파일)
|
||||
├── QUICKSTART.md ← 실행 / 빌드 / 배포 가이드
|
||||
|
|
@ -613,7 +614,7 @@ daemon 부팅 시 `PATH`에서 자동 감지됩니다. 설정 필요 없음. 스
|
|||
- **디자인 시스템 추가** — 9섹션 스키마를 사용하여 [`design-systems/<brand>/`](design-systems/)에 `DESIGN.md`를 드롭하세요.
|
||||
- **새 코딩 에이전트 CLI 연결** — [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts)에 항목 하나 추가.
|
||||
|
||||
전체 설명, 병합 기준, 코드 스타일, 받지 않는 것 → [`CONTRIBUTING.md`](CONTRIBUTING.md) ([简体中文](CONTRIBUTING.zh-CN.md)).
|
||||
전체 설명, 병합 기준, 코드 스타일, 받지 않는 것 → [`CONTRIBUTING.md`](CONTRIBUTING.md) ([Deutsch](CONTRIBUTING.de.md), [简体中文](CONTRIBUTING.zh-CN.md)).
|
||||
|
||||
## 컨트리뷰터
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<a href="QUICKSTART.md"><img alt="Quickstart" src="https://img.shields.io/badge/quickstart-3%20commands-green?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><b>English</b> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ko.md">한국어</a> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
<p align="center"><b>English</b> · <a href="README.de.md">Deutsch</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ko.md">한국어</a> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -343,6 +343,7 @@ Full file map, scripts, and troubleshooting → [`QUICKSTART.md`](QUICKSTART.md)
|
|||
```
|
||||
open-design/
|
||||
├── README.md ← this file
|
||||
├── README.de.md ← Deutsch
|
||||
├── README.zh-CN.md ← 简体中文
|
||||
├── QUICKSTART.md ← run / build / deploy guide
|
||||
├── package.json ← pnpm workspace, single bin: od
|
||||
|
|
@ -615,7 +616,7 @@ Issues, PRs, new skills, and new design systems are all welcome. The highest-lev
|
|||
- **Add a design system** — drop a `DESIGN.md` into [`design-systems/<brand>/`](design-systems/) using the 9-section schema.
|
||||
- **Wire up a new coding-agent CLI** — one entry in [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts).
|
||||
|
||||
Full walkthrough, bar-for-merging, code style, and what we don't accept → [`CONTRIBUTING.md`](CONTRIBUTING.md) ([简体中文](CONTRIBUTING.zh-CN.md)).
|
||||
Full walkthrough, bar-for-merging, code style, and what we don't accept → [`CONTRIBUTING.md`](CONTRIBUTING.md) ([Deutsch](CONTRIBUTING.de.md), [简体中文](CONTRIBUTING.zh-CN.md)).
|
||||
|
||||
## Contributors
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<a href="QUICKSTART.md"><img alt="Quickstart" src="https://img.shields.io/badge/quickstart-3%20commands-green?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><a href="README.md">English</a> · <b>简体中文</b> · <a href="README.ko.md">한국어</a> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
<p align="center"><a href="README.md">English</a> · <a href="README.de.md">Deutsch</a> · <b>简体中文</b> · <a href="README.ko.md">한국어</a> · <a href="README.ja-JP.md">日本語</a></p>
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -343,6 +343,7 @@ Daemon 在仓库根下维护一个隐藏目录,里面所有内容都已 gitign
|
|||
```
|
||||
open-design/
|
||||
├── README.md ← 英文
|
||||
├── README.de.md ← Deutsch
|
||||
├── README.zh-CN.md ← 本文件
|
||||
├── QUICKSTART.md ← 跑 / 构建 / 部署
|
||||
├── package.json ← 单 bin: od
|
||||
|
|
@ -611,7 +612,7 @@ Daemon 启动时从 `PATH` 自动检测,无需配置。流式分发逻辑在 [
|
|||
- **加一套 design system** —— 往 [`design-systems/<brand>/`](design-systems/) 丢一份 `DESIGN.md`,用 9 段式 schema。
|
||||
- **接入一个新的 coding-agent CLI** —— 在 [`apps/daemon/src/agents.ts`](apps/daemon/src/agents.ts) 里加一项。
|
||||
|
||||
完整流程、合并硬线、代码风格、我们不接收的 PR 类型 → [`CONTRIBUTING.zh-CN.md`](CONTRIBUTING.zh-CN.md)([English](CONTRIBUTING.md))。
|
||||
完整流程、合并硬线、代码风格、我们不接收的 PR 类型 → [`CONTRIBUTING.zh-CN.md`](CONTRIBUTING.zh-CN.md)([English](CONTRIBUTING.md),[Deutsch](CONTRIBUTING.de.md))。
|
||||
|
||||
## 贡献者墙
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import { useT } from '../i18n';
|
||||
import { useI18n } from '../i18n';
|
||||
import {
|
||||
localizeDesignSystemCategory,
|
||||
localizeDesignSystemSummary,
|
||||
} from '../i18n/content';
|
||||
import type { DesignSystemSummary, Surface } from '../types';
|
||||
|
||||
interface Props {
|
||||
|
|
@ -37,7 +41,7 @@ function surfaceOf(system: DesignSystemSummary): Surface {
|
|||
}
|
||||
|
||||
export function DesignSystemsTab({ systems, selectedId, onSelect, onPreview }: Props) {
|
||||
const t = useT();
|
||||
const { locale, t } = useI18n();
|
||||
const [filter, setFilter] = useState('');
|
||||
const [surfaceFilter, setSurfaceFilter] = useState<SurfaceFilter>('all');
|
||||
const [category, setCategory] = useState<string>('All');
|
||||
|
|
@ -67,21 +71,26 @@ export function DesignSystemsTab({ systems, selectedId, onSelect, onPreview }: P
|
|||
return surfaceScoped.filter((s) => {
|
||||
if (category !== 'All' && (s.category || 'Uncategorized') !== category) return false;
|
||||
if (!q) return true;
|
||||
const summary = localizeDesignSystemSummary(locale, s).toLowerCase();
|
||||
const categoryLabel = localizeDesignSystemCategory(
|
||||
locale,
|
||||
s.category || 'Uncategorized',
|
||||
).toLowerCase();
|
||||
return (
|
||||
s.title.toLowerCase().includes(q) ||
|
||||
s.summary.toLowerCase().includes(q)
|
||||
s.summary.toLowerCase().includes(q) ||
|
||||
summary.includes(q) ||
|
||||
categoryLabel.includes(q)
|
||||
);
|
||||
});
|
||||
}, [surfaceScoped, filter, category]);
|
||||
}, [surfaceScoped, filter, category, locale]);
|
||||
|
||||
// The category metadata coming from each design system is authored in
|
||||
// English. We translate the well-known buckets (All / Uncategorized) but
|
||||
// pass the rest through unchanged so user-facing labels stay aligned with
|
||||
// the underlying tags.
|
||||
// Category metadata is authored in English; keep raw values in state for
|
||||
// filtering while localizing the visible labels for the current UI locale.
|
||||
const renderCategory = (c: string) => {
|
||||
if (c === 'All') return t('ds.categoryAll');
|
||||
if (c === 'Uncategorized') return t('ds.categoryUncategorized');
|
||||
return c;
|
||||
return localizeDesignSystemCategory(locale, c);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -144,7 +153,9 @@ export function DesignSystemsTab({ systems, selectedId, onSelect, onPreview }: P
|
|||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="ds-row-summary">{s.summary || s.category}</div>
|
||||
<div className="ds-row-summary">
|
||||
{localizeDesignSystemSummary(locale, s)}
|
||||
</div>
|
||||
</div>
|
||||
{s.swatches && s.swatches.length > 0 ? (
|
||||
<div className="ds-row-swatches" aria-hidden>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useT } from '../i18n';
|
||||
import { useI18n } from '../i18n';
|
||||
import {
|
||||
localizeSkillDescription,
|
||||
localizeSkillPrompt,
|
||||
} from '../i18n/content';
|
||||
import type { Dict } from '../i18n/types';
|
||||
import { fetchSkillExample } from '../providers/registry';
|
||||
import { exportAsHtml, exportAsPdf, exportAsZip } from '../runtime/exports';
|
||||
|
|
@ -93,8 +97,12 @@ function matchesSurface(skill: SkillSummary, filter: SurfaceFilter): boolean {
|
|||
return filter === 'all' || surfaceOf(skill) === filter;
|
||||
}
|
||||
|
||||
function quotePrompt(locale: string, text: string): string {
|
||||
return locale === 'de' ? `„${text}“` : `“${text}”`;
|
||||
}
|
||||
|
||||
export function ExamplesTab({ skills, onUsePrompt }: Props) {
|
||||
const t = useT();
|
||||
const { locale, t } = useI18n();
|
||||
// Hold preview HTML per skill across re-renders so cards never re-flicker.
|
||||
const [previews, setPreviews] = useState<Record<string, string | null>>({});
|
||||
const [surfaceFilter, setSurfaceFilter] = useState<SurfaceFilter>('all');
|
||||
|
|
@ -291,7 +299,10 @@ export function ExamplesTab({ skills, onUsePrompt }: Props) {
|
|||
{previewSkill ? (
|
||||
<PreviewModal
|
||||
title={previewSkill.name}
|
||||
subtitle={previewSkill.examplePrompt || previewSkill.description.replace(/\s+/g, ' ').slice(0, 160)}
|
||||
subtitle={
|
||||
localizeSkillPrompt(locale, previewSkill)
|
||||
?? localizeSkillDescription(locale, previewSkill).slice(0, 160)
|
||||
}
|
||||
views={[
|
||||
{
|
||||
id: 'preview',
|
||||
|
|
@ -320,7 +331,7 @@ function ExampleCard({
|
|||
onUsePrompt: () => void;
|
||||
onOpenPreview: () => void;
|
||||
}) {
|
||||
const t = useT();
|
||||
const { locale, t } = useI18n();
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const [shareOpen, setShareOpen] = useState(false);
|
||||
const shareRef = useRef<HTMLDivElement | null>(null);
|
||||
|
|
@ -345,6 +356,8 @@ function ExampleCard({
|
|||
const exportTitle = skill.name;
|
||||
const isMobile = skill.platform === 'mobile';
|
||||
const isDeck = skill.mode === 'deck';
|
||||
const displayPrompt = localizeSkillPrompt(locale, skill);
|
||||
const displayDescription = localizeSkillDescription(locale, skill).slice(0, 240);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -402,9 +415,7 @@ function ExampleCard({
|
|||
) : null}
|
||||
</div>
|
||||
<div className="example-prompt">
|
||||
{skill.examplePrompt
|
||||
? `“${skill.examplePrompt}”`
|
||||
: skill.description.replace(/\s+/g, ' ').slice(0, 240)}
|
||||
{displayPrompt ? quotePrompt(locale, displayPrompt) : displayDescription}
|
||||
</div>
|
||||
<div className="example-card-actions">
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import { useT } from '../i18n';
|
||||
import { useI18n, useT } from '../i18n';
|
||||
import {
|
||||
localizePromptTemplateCategory,
|
||||
localizePromptTemplateSummary,
|
||||
} from '../i18n/content';
|
||||
import type { PromptTemplateSummary } from '../types';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
|
|
@ -15,7 +19,7 @@ interface Props {
|
|||
// images on CMS / Cloudflare Stream, both public). Each card opens a
|
||||
// preview modal with the full prompt body and attribution.
|
||||
export function PromptTemplatesTab({ surface, templates, onPreview }: Props) {
|
||||
const t = useT();
|
||||
const { locale, t } = useI18n();
|
||||
const [filter, setFilter] = useState('');
|
||||
const [category, setCategory] = useState<string>('All');
|
||||
|
||||
|
|
@ -37,13 +41,18 @@ export function PromptTemplatesTab({ surface, templates, onPreview }: Props) {
|
|||
return false;
|
||||
}
|
||||
if (!q) return true;
|
||||
const localized = localizePromptTemplateSummary(locale, tpl);
|
||||
return (
|
||||
tpl.title.toLowerCase().includes(q)
|
||||
|| tpl.summary.toLowerCase().includes(q)
|
||||
|| (tpl.tags ?? []).some((tag) => tag.toLowerCase().includes(q))
|
||||
|| localized.title.toLowerCase().includes(q)
|
||||
|| localized.summary.toLowerCase().includes(q)
|
||||
|| localized.category.toLowerCase().includes(q)
|
||||
|| (localized.tags ?? []).some((tag) => tag.toLowerCase().includes(q))
|
||||
);
|
||||
});
|
||||
}, [surfaceScoped, filter, category]);
|
||||
}, [surfaceScoped, filter, category, locale]);
|
||||
|
||||
if (surfaceScoped.length === 0) {
|
||||
return (
|
||||
|
|
@ -66,7 +75,7 @@ export function PromptTemplatesTab({ surface, templates, onPreview }: Props) {
|
|||
<select value={category} onChange={(e) => setCategory(e.target.value)}>
|
||||
{categories.map((c) => (
|
||||
<option key={c} value={c}>
|
||||
{c === 'All' ? t('common.all') : c}
|
||||
{c === 'All' ? t('common.all') : localizePromptTemplateCategory(locale, c)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
|
@ -78,13 +87,16 @@ export function PromptTemplatesTab({ surface, templates, onPreview }: Props) {
|
|||
<div className="tab-empty">{t('promptTemplates.emptyNoMatch')}</div>
|
||||
) : (
|
||||
<div className="prompt-templates-grid">
|
||||
{filtered.map((tpl) => (
|
||||
<PromptTemplateCard
|
||||
key={tpl.id}
|
||||
tpl={tpl}
|
||||
onPreview={() => onPreview(tpl)}
|
||||
/>
|
||||
))}
|
||||
{filtered.map((tpl) => {
|
||||
const localized = localizePromptTemplateSummary(locale, tpl);
|
||||
return (
|
||||
<PromptTemplateCard
|
||||
key={tpl.id}
|
||||
tpl={localized}
|
||||
onPreview={() => onPreview(localized)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="prompt-templates-footer">
|
||||
|
|
|
|||
124
apps/web/src/i18n/content.test.ts
Normal file
124
apps/web/src/i18n/content.test.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import { readdir, readFile, stat } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { parseFrontmatter } from '../../../daemon/src/frontmatter';
|
||||
import { GERMAN_CONTENT_IDS } from './content';
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url));
|
||||
|
||||
function sorted(values: Iterable<string>): string[] {
|
||||
return [...values].sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
async function entriesWithFile(root: string, fileName: string): Promise<string[]> {
|
||||
const entries = await readdir(root, { withFileTypes: true });
|
||||
const ids: string[] = [];
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
const filePath = path.join(root, entry.name, fileName);
|
||||
try {
|
||||
if ((await stat(filePath)).isFile()) {
|
||||
ids.push(entry.name);
|
||||
}
|
||||
} catch {
|
||||
// Missing optional registry files are ignored, matching daemon discovery.
|
||||
}
|
||||
}
|
||||
return sorted(ids);
|
||||
}
|
||||
|
||||
async function readSkillIds(): Promise<string[]> {
|
||||
const skillsRoot = path.join(repoRoot, 'skills');
|
||||
const dirs = await entriesWithFile(skillsRoot, 'SKILL.md');
|
||||
const ids = await Promise.all(
|
||||
dirs.map(async (dir) => {
|
||||
const raw = await readFile(path.join(skillsRoot, dir, 'SKILL.md'), 'utf8');
|
||||
const { data } = parseFrontmatter(raw) as { data: { name?: unknown } };
|
||||
const name = data.name;
|
||||
return typeof name === 'string' && name.trim() ? name : dir;
|
||||
}),
|
||||
);
|
||||
return sorted(ids);
|
||||
}
|
||||
|
||||
async function readDesignSystemIds(): Promise<string[]> {
|
||||
return entriesWithFile(path.join(repoRoot, 'design-systems'), 'DESIGN.md');
|
||||
}
|
||||
|
||||
async function readDesignSystemCategories(): Promise<string[]> {
|
||||
const systemsRoot = path.join(repoRoot, 'design-systems');
|
||||
const ids = await readDesignSystemIds();
|
||||
const categories = await Promise.all(
|
||||
ids.map(async (id) => {
|
||||
const raw = await readFile(path.join(systemsRoot, id, 'DESIGN.md'), 'utf8');
|
||||
return /^>\s*Category:\s*(.+?)\s*$/im.exec(raw)?.[1] ?? 'Uncategorized';
|
||||
}),
|
||||
);
|
||||
return sorted(new Set(categories));
|
||||
}
|
||||
|
||||
async function readPromptTemplateSummaries(): Promise<
|
||||
Array<{ id: string; category: string; tags: string[] }>
|
||||
> {
|
||||
const templatesRoot = path.join(repoRoot, 'prompt-templates');
|
||||
const summaries: Array<{ id: string; category: string; tags: string[] }> = [];
|
||||
for (const surface of ['image', 'video']) {
|
||||
const dir = path.join(templatesRoot, surface);
|
||||
const entries = await readdir(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.isFile() || !entry.name.endsWith('.json')) continue;
|
||||
const raw = JSON.parse(await readFile(path.join(dir, entry.name), 'utf8')) as {
|
||||
id?: unknown;
|
||||
category?: unknown;
|
||||
tags?: unknown;
|
||||
};
|
||||
if (typeof raw.id !== 'string' || !raw.id) continue;
|
||||
summaries.push({
|
||||
id: raw.id,
|
||||
category: typeof raw.category === 'string' ? raw.category : 'General',
|
||||
tags: Array.isArray(raw.tags) ? raw.tags.filter((tag): tag is string => typeof tag === 'string') : [],
|
||||
});
|
||||
}
|
||||
}
|
||||
return summaries;
|
||||
}
|
||||
|
||||
describe('German display content coverage', () => {
|
||||
it('covers every curated skill, design system, and prompt template', async () => {
|
||||
const [skillIds, designSystemIds, promptTemplateSummaries] = await Promise.all([
|
||||
readSkillIds(),
|
||||
readDesignSystemIds(),
|
||||
readPromptTemplateSummaries(),
|
||||
]);
|
||||
|
||||
expect(sorted(GERMAN_CONTENT_IDS.skills), 'skills display copy').toEqual(skillIds);
|
||||
expect(sorted(GERMAN_CONTENT_IDS.designSystems), 'design-system summaries').toEqual(
|
||||
designSystemIds,
|
||||
);
|
||||
expect(sorted(GERMAN_CONTENT_IDS.promptTemplates), 'prompt-template metadata').toEqual(
|
||||
sorted(promptTemplateSummaries.map((template) => template.id)),
|
||||
);
|
||||
});
|
||||
|
||||
it('covers every curated display category and prompt tag', async () => {
|
||||
const [designSystemCategories, promptTemplateSummaries] = await Promise.all([
|
||||
readDesignSystemCategories(),
|
||||
readPromptTemplateSummaries(),
|
||||
]);
|
||||
const promptTemplateCategories = new Set(
|
||||
promptTemplateSummaries.map((template) => template.category),
|
||||
);
|
||||
const promptTemplateTags = new Set(promptTemplateSummaries.flatMap((template) => template.tags));
|
||||
|
||||
expect(sorted(GERMAN_CONTENT_IDS.designSystemCategories)).toEqual(
|
||||
expect.arrayContaining(designSystemCategories),
|
||||
);
|
||||
expect(sorted(GERMAN_CONTENT_IDS.promptTemplateCategories)).toEqual(
|
||||
expect.arrayContaining(sorted(promptTemplateCategories)),
|
||||
);
|
||||
expect(sorted(GERMAN_CONTENT_IDS.promptTemplateTags)).toEqual(
|
||||
expect.arrayContaining(sorted(promptTemplateTags)),
|
||||
);
|
||||
});
|
||||
});
|
||||
715
apps/web/src/i18n/content.ts
Normal file
715
apps/web/src/i18n/content.ts
Normal file
|
|
@ -0,0 +1,715 @@
|
|||
import type {
|
||||
DesignSystemSummary,
|
||||
PromptTemplateSummary,
|
||||
SkillSummary,
|
||||
} from '../types';
|
||||
import type { Locale } from './types';
|
||||
|
||||
const DE_SKILL_COPY: Record<string, { description?: string; examplePrompt?: string }> = {
|
||||
'audio-jingle': {
|
||||
examplePrompt:
|
||||
'Ein fröhlicher 30-Sekunden-Indie-Pop-Jingle für den Launch eines Coffee Shops — warmes E-Piano, Besen-Drums, sanfter Bass und ein einzelner sonniger „ahhh“-Chor im Refrain. Ohne Gesang. Loop-freundliches Ende.',
|
||||
description:
|
||||
'Audio-Generierung für Jingles, Musikbetten, Voiceover und Soundeffekte. Musik-Anfragen werden an Suno V5 / Udio / Lyria geleitet, Sprache an MiniMax TTS / FishAudio / ElevenLabs V3 und SFX an ElevenLabs SFX oder AudioCraft. Die Ausgabe ist eine MP3/WAV-Datei im Projektordner.',
|
||||
},
|
||||
'blog-post': {
|
||||
examplePrompt:
|
||||
'Ein Long-form-Artikel / Blogpost — Masthead, Hero-Bild-Platzhalter, Artikeltext mit Abbildungen und Pull Quotes, Autorenzeile, verwandte Beiträge.',
|
||||
},
|
||||
'critique': {
|
||||
examplePrompt:
|
||||
'Führen Sie eine 5-dimensionale Kritik für das gerade erzeugte magazine-web-ppt Deck aus — bewerten Sie Philosophie / Hierarchie / Detail / Funktion / Innovation und geben Sie Keep / Fix / Quick-wins aus.',
|
||||
},
|
||||
'dashboard': {
|
||||
examplePrompt:
|
||||
'Admin- / Analytics-Dashboard in einer einzigen HTML-Datei.',
|
||||
},
|
||||
'dating-web': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie ‚mutuals‘ — eine Dating-Site für X-Poster. Tägliches Digest-Dashboard mit Statistiken, Balkendiagramm für gegenseitige Matches und Community-Ticker.',
|
||||
},
|
||||
'digital-eguide': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie ‚The Creator\'s Style & Format Guide‘ — Coverseite und eine Innenseite für eine Lifestyle-Creator-Brand.',
|
||||
},
|
||||
'docs-page': {
|
||||
examplePrompt:
|
||||
'Eine Dokumentationsseite — linke Navigation, scrollbarer Artikelbereich, rechte Inhaltsübersicht.',
|
||||
},
|
||||
'email-marketing': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie eine Launch-E-Mail für eine sportliche Laufschuhmarke — Masthead, Hero, großes Headline-Lockup, Specs Grid, CTA.',
|
||||
},
|
||||
'eng-runbook': {
|
||||
examplePrompt:
|
||||
'Schreiben Sie ein Runbook für unseren Auth-Service — Alerts, Dashboards, Standardverfahren, On-Call-Rotation.',
|
||||
},
|
||||
'finance-report': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie einen Q3-Finanzbericht für ein Early-Stage-SaaS — MRR, Burn, Bruttomarge, Top-Accounts.',
|
||||
},
|
||||
'gamified-app': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie eine gamifizierte Life-Management-App — mobiler Multi-Screen-Prototyp: Cover-Poster, heutige Quests mit XP und Quest-Detail. ‚Daily quests for becoming a better human.‘',
|
||||
},
|
||||
'magazine-web-ppt': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie mir ein Magazin-PPT über ‚Ein-Personen-Unternehmen · von AI gefaltete Organisationen‘, 25-minütiger Vortrag, Zielgruppe Designer + Gründer. Empfehlen Sie zuerst eine Richtung (Monocle / WIRED / Kinfolk / Domus / Lab), damit ich wählen kann.',
|
||||
},
|
||||
'hr-onboarding': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie einen 30-Tage-Onboardingplan für einen neuen Product Designer in einem 40-Personen-Startup.',
|
||||
},
|
||||
'hyperframes': {
|
||||
examplePrompt:
|
||||
'Ein 5-Sekunden-Product-Reveal: ein minimalistisches High-End-Produkt auf einer sauberen cremefarbenen Fläche, weiches Seitenlicht, langsamer Kamera-Push-in, zurückhaltende Bewegung, keine Text-Overlays.',
|
||||
description:
|
||||
'Erstellt Videokompositionen, Animationen, Title Cards, Overlays, Untertitel, Voiceovers, audio-reaktive Visuals und Szenenübergänge in HyperFrames HTML.',
|
||||
},
|
||||
'image-poster': {
|
||||
examplePrompt:
|
||||
'Editorial-Poster für ein Indie-Filmfestival — eine kräftige abstrakte Silhouette auf warmem, leicht körnigem Papier; handgesetzter Sans-Serif-Titel oben, Festivaldaten und Ort unten in Monospace. Gedämpfte Ocker- und Tintenpalette.',
|
||||
description:
|
||||
'Einzelbild-Generierung für Poster, Key Art und Editorial-Illustrationen. Standard ist gpt-image-2, der Workflow ist aber provider-agnostisch.',
|
||||
},
|
||||
'invoice': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie eine Rechnung eines freiberuflichen Designstudios an einen Kunden für ein Brand-Identity-Projekt — drei Positionen, 10% Retainer, 9% Umsatzsteuer.',
|
||||
},
|
||||
'kanban-board': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie ein Kanban-Board für ein 5-köpfiges Growth-Team mitten im Sprint — Backlog, Doing, Review, Done.',
|
||||
},
|
||||
'magazine-poster': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie ein Editorial-Poster im Magazin-Stil — ‚You don\'t need a designer to ship your first draft anymore.‘ Zeitungspapier, sechs nummerierte Abschnitte.',
|
||||
},
|
||||
'meeting-notes': {
|
||||
examplePrompt:
|
||||
'Schreiben Sie Notizen aus einem 60-minütigen Weekly des Growth-Teams — Agenda, Entscheidungen, Action Items mit Verantwortlichen, nächstes Meeting.',
|
||||
},
|
||||
'mobile-app': {
|
||||
examplePrompt:
|
||||
'Ein Mobile-App-Screen, gerendert in einem pixelgenauen iPhone-15-Pro-Rahmen auf der Seite.',
|
||||
},
|
||||
'mobile-onboarding': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie einen 3-Screen-Mobile-Onboarding-Flow für eine Meditations-App — Welcome, Value Props, Sign-in.',
|
||||
},
|
||||
'motion-frames': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie einen animierten Hero — ein rotierender Type-Ring um einen Wireframe-Globus, mit der Headline ‚Reach every country.‘ Loop bei 12s, bereit für HyperFrames-Export.',
|
||||
},
|
||||
'pm-spec': {
|
||||
examplePrompt:
|
||||
'Schreiben Sie mir eine PRD für Two-Factor Auth in unserer SaaS-App — Problem, Scope, Meilensteine, offene Fragen.',
|
||||
},
|
||||
'pricing-page': {
|
||||
examplePrompt:
|
||||
'Eine eigenständige Pricing Page — Header, Plan-Stufen, Feature-Vergleichstabelle und FAQ.',
|
||||
},
|
||||
'replit-deck': {
|
||||
examplePrompt:
|
||||
'Single-file horizontal-swipe HTML deck im Stil der Landing-Page-Template-Galerie von Replit Slides.',
|
||||
},
|
||||
'saas-landing': {
|
||||
examplePrompt:
|
||||
'Einseitige SaaS-Landingpage mit Hero, Features, Social Proof, Pricing und CTA.',
|
||||
},
|
||||
'simple-deck': {
|
||||
examplePrompt:
|
||||
'Single-file horizontal-swipe HTML deck.',
|
||||
},
|
||||
'social-carousel': {
|
||||
examplePrompt:
|
||||
'Entwerfen Sie ein 3-Karten-Cinematic-Social-Carousel — ‚onwards.‘, ‚to the next one.‘, ‚looking ahead.‘. 1080×1080 Squares, direkt bereit für Instagram.',
|
||||
},
|
||||
'sprite-animation': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie eine sprite-basierte Animation mit Trivia zur Geschichte von Nintendo. Kombinieren Sie Pixel-Maskottchen, animierten Text und einen Hanafuda-Akzent. Farbe und Typografie sollen sich wie die Nintendo-Brand anfühlen.',
|
||||
},
|
||||
'team-okrs': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie einen OKR-Tracker für Q4 — drei Objectives, je drei Key Results, Progress Bars, Verantwortliche, Status-Pills.',
|
||||
},
|
||||
'tweaks': {
|
||||
examplePrompt:
|
||||
'Ergänzen Sie diese Landingpage um ein Tweak Panel — Accent Color, Type Scale, Density, Light/Dark — und persistieren Sie in localStorage, damit die Auswahl nach Refresh erhalten bleibt.',
|
||||
},
|
||||
'video-shortform': {
|
||||
examplePrompt:
|
||||
'5-Sekunden-Product-Reveal — eine Keramik-Kaffeetasse rotiert auf einem weichen Papierhintergrund, warmes Seitenlicht von links, feine Staubpartikel schweben im Lichtstrahl. Filmisch, 16:9, langsamer Kamera-Drift.',
|
||||
description:
|
||||
'Short-form-Video-Generierung für 3-10-Sekunden-Clips wie Product Reveals, Motion Teasers und Ambient Loops.',
|
||||
},
|
||||
'web-prototype': {
|
||||
examplePrompt:
|
||||
'Allzweck-Prototyp für Desktop-Web.',
|
||||
},
|
||||
'weekly-update': {
|
||||
examplePrompt:
|
||||
'Erstellen Sie ein Weekly-Update-Deck für das Growth-Team — was fertig wurde, was läuft, Blocker, Kennzahlen und Fragen für nächste Woche.',
|
||||
},
|
||||
'wireframe-sketch': {
|
||||
examplePrompt:
|
||||
'Skizzieren Sie ein handgezeichnetes Wireframe v0.1 für ein Portal — vier Varianten als Tabs auf Millimeterpapier, Marker-Headlines, Sticky-Note-Anmerkungen, schraffierte Chart-Platzhalter.',
|
||||
},
|
||||
};
|
||||
|
||||
const DE_DESIGN_SYSTEM_SUMMARIES: Record<string, string> = {
|
||||
airbnb: 'Reisemarktplatz. Warmer Korallenakzent, fotogetrieben, abgerundete UI.',
|
||||
airtable: 'Spreadsheet-Datenbank-Hybrid. Farbenfroh, freundlich, strukturierte Datenästhetik.',
|
||||
apple: 'Unterhaltungselektronik. Premium-Weißraum, SF Pro, filmische Bildsprache.',
|
||||
binance: 'Krypto-Börse. Kräftiger gelber Akzent auf Monochrom, Trading-Floor-Dringlichkeit.',
|
||||
bmw: 'Luxusautomobil. Dunkle Premium-Flächen, präzise deutsche Engineering-Ästhetik.',
|
||||
bugatti: 'Hypercar-Marke. Kinodunkle Leinwand, monochrome Strenge, monumentale Display-Type.',
|
||||
cal: 'Open-Source-Terminplanung. Saubere neutrale UI, entwicklerorientierte Einfachheit.',
|
||||
claude: 'Anthropics AI-Assistent. Warmer Terrakotta-Akzent, klares Editorial-Layout.',
|
||||
clay: 'Kreativagentur. Organische Formen, weiche Verläufe, art-directed Layout.',
|
||||
clickhouse: 'Schnelle Analytics-Datenbank. Gelb akzentuierter, technischer Dokumentationsstil.',
|
||||
cohere: 'Enterprise-AI-Plattform. Lebendige Verläufe, datenreiche Dashboard-Ästhetik.',
|
||||
coinbase: 'Krypto-Börse. Klare blaue Identität, vertrauensfokussiert, institutionelles Gefühl.',
|
||||
composio: 'Tool-Integrationsplattform. Modern dunkel mit farbigen Integrationsicons.',
|
||||
cursor: 'AI-first Code-Editor. Schlanke dunkle Oberfläche, Verlaufsakzente.',
|
||||
default:
|
||||
'Sauberer, produktorientierter Standard. Nutzen, wenn der Brief keine bestimmte Stimmung verlangt — gut für B2B-Tools, Dashboards und Utility-Pages.',
|
||||
elevenlabs: 'AI-Voice-Plattform. Dunkle filmische UI, Audio-Waveform-Ästhetik.',
|
||||
expo: 'React-Native-Plattform. Dunkles Theme, enge Laufweite, codezentriert.',
|
||||
ferrari: 'Luxusautomobil. Chiaroscuro-Editorial, Ferrari-Red-Akzente, filmisches Schwarz.',
|
||||
figma: 'Kollaboratives Design-Tool. Lebendige Mehrfarbigkeit, spielerisch und professionell.',
|
||||
framer: 'Website-Builder. Mutiges Schwarz und Blau, motion-first, designorientiert.',
|
||||
hashicorp: 'Infrastrukturautomatisierung. Sauberer Enterprise-Look, Schwarz und Weiß.',
|
||||
ibm: 'Enterprise-Technologie. Carbon Design System, strukturierte blaue Palette.',
|
||||
intercom: 'Customer Messaging. Freundliche blaue Palette, konversationelle UI-Muster.',
|
||||
kraken: 'Krypto-Trading. Dunkle UI mit violettem Akzent, datenreiche Dashboards.',
|
||||
lamborghini: 'Supercar-Marke. Echtschwarze Flächen, Goldakzente, dramatische Großbuchstaben-Typografie.',
|
||||
'linear-app': 'Projektmanagement. Ultraminimal, präzise, violetter Akzent.',
|
||||
lovable: 'AI-Full-Stack-Builder. Spielerische Verläufe, freundliche Dev-Ästhetik.',
|
||||
mastercard: 'Globales Zahlungsnetzwerk. Warme Cream-Leinwand, orbitale Pillenformen, Editorial-Wärme.',
|
||||
meta: 'Tech-Retail-Store. Fotografiezentriert, binäre Hell/Dunkel-Flächen, Meta-Blue CTAs.',
|
||||
minimax: 'AI-Modellanbieter. Mutige dunkle Oberfläche mit Neonakzenten.',
|
||||
mintlify: 'Dokumentationsplattform. Sauber, grün akzentuiert, fürs Lesen optimiert.',
|
||||
miro: 'Visuelle Zusammenarbeit. Heller gelber Akzent, Infinite-Canvas-Ästhetik.',
|
||||
'mistral-ai': 'Open-Weight-LLM-Anbieter. Französisch konstruiertes Minimalismusgefühl, violett getönt.',
|
||||
mongodb: 'Dokumentendatenbank. Grünes Leaf-Branding, Fokus auf Entwicklerdokumentation.',
|
||||
nike: 'Sporthandel. Monochrome UI, massive Großbuchstaben, Full-Bleed-Fotografie.',
|
||||
notion: 'All-in-one-Workspace. Warmer Minimalismus, Serif-Headings, weiche Flächen.',
|
||||
nvidia: 'GPU-Computing. Grün-schwarze Energie, technische Power-Ästhetik.',
|
||||
ollama: 'LLMs lokal ausführen. Terminal-first, monochrome Einfachheit.',
|
||||
'opencode-ai': 'AI-Coding-Plattform. Entwicklerzentriertes dunkles Theme.',
|
||||
pinterest: 'Visuelle Entdeckung. Roter Akzent, Masonry Grid, bildfokussiert.',
|
||||
playstation:
|
||||
'Gaming-Konsolen-Retail. Drei-Flächen-Channel-Layout, ruhige Autorität in Display-Type, cyanfarbene Hover-Skalierung.',
|
||||
posthog: 'Product Analytics. Spielerisches Branding, entwicklerfreundliche dunkle UI.',
|
||||
raycast: 'Produktivitätslauncher. Schlankes dunkles Chrome, lebendige Verlaufsakzente.',
|
||||
renault: 'Französisches Automobil. Lebendige Aurora-Verläufe, NouvelR-Typografie, starke Energie.',
|
||||
replicate: 'ML-Modelle per API ausführen. Saubere weiße Leinwand, code-orientiert.',
|
||||
resend: 'E-Mail-API. Minimalistisches dunkles Theme, Monospace-Akzente.',
|
||||
revolut: 'Digital Banking. Schlanke dunkle Oberfläche, Verlaufskarten, Fintech-Präzision.',
|
||||
runwayml: 'AI-Videogenerierung. Filmische dunkle UI, medienreiches Layout.',
|
||||
sanity: 'Headless CMS. Roter Akzent, content-first Editorial-Layout.',
|
||||
sentry: 'Fehler-Monitoring. Dunkles Dashboard, datenreich, pink-violetter Akzent.',
|
||||
shopify: 'E-Commerce-Plattform. Dark-first und filmisch, neongrüner Akzent, ultraleichte Type.',
|
||||
spacex: 'Raumfahrttechnologie. Strenges Schwarz-Weiß, Full-Bleed-Bildsprache, futuristisch.',
|
||||
spotify: 'Musikstreaming. Lebendiges Grün auf Dunkel, fette Type, album-art-driven.',
|
||||
starbucks:
|
||||
'Globale Kaffee-Retail-Marke. Vierstufiges grünes System, warme Cream-Leinwand, Full-Pill-Buttons.',
|
||||
stripe: 'Payment-Infrastruktur. Signatur-violette Verläufe, Weight-300-Eleganz.',
|
||||
supabase: 'Open-Source-Firebase-Alternative. Dunkles Smaragd-Theme, code-first.',
|
||||
superhuman: 'Schneller E-Mail-Client. Premium-dunkle UI, keyboard-first, violetter Glow.',
|
||||
tesla: 'Elektrisches Automobil. Radikale Reduktion, Full-Viewport-Fotografie, nahezu keine UI.',
|
||||
theverge:
|
||||
'Tech-Editorial-Medium. Acid-Mint- und Ultraviolett-Akzente, Manuka-Display, Rave-Flyer-Story-Tiles.',
|
||||
'together-ai': 'Open-Source-AI-Infrastruktur. Technisch, blueprint-artiges Design.',
|
||||
uber: 'Mobilitätsplattform. Kräftiges Schwarz-Weiß, enge Type, urbane Energie.',
|
||||
vercel: 'Frontend-Deployment. Schwarz-Weiß-Präzision, Geist Font.',
|
||||
vodafone: 'Globale Telekommarke. Monumentale Großbuchstaben-Display-Type, Vodafone-Red-Kapitelbänder.',
|
||||
voltagent: 'AI-Agent-Framework. Void-schwarze Leinwand, Smaragdakzent, terminal-nativ.',
|
||||
'warm-editorial':
|
||||
'Serifengeführte Magazin-Ästhetik. Terrakotta-Akzent auf warmem Off-White-Papier — gut für Long-form, Editorial und brandgeführte Marketingseiten.',
|
||||
warp: 'Modernes Terminal. Dunkle IDE-artige Oberfläche, blockbasierte Command-UI.',
|
||||
webflow: 'Visueller Web-Builder. Blau akzentuiert, polierte Marketing-Site-Ästhetik.',
|
||||
wired: 'Tech-Magazin. Papierweiße Broadsheet-Dichte, Custom-Serif-Display, Mono-Kicker, tintenblaue Links.',
|
||||
wise: 'Geldtransfer. Leuchtend grüner Akzent, freundlich und klar.',
|
||||
'x-ai': 'Elon Musks AI-Lab. Strenger Monochrom-Look, futuristischer Minimalismus.',
|
||||
xiaohongshu: 'Lifestyle-UGC-Social-Plattform. Singuläres Brand-Rot, großzügiger Radius, content-first.',
|
||||
zapier: 'Automatisierungsplattform. Warmes Orange, freundlich illustrationsgetrieben.',
|
||||
};
|
||||
|
||||
const DE_DESIGN_SYSTEM_CATEGORIES: Record<string, string> = {
|
||||
Starter: 'Starter',
|
||||
'AI & LLM': 'AI & LLM',
|
||||
'Developer Tools': 'Entwickler-Tools',
|
||||
'Productivity & SaaS': 'Produktivität & SaaS',
|
||||
'Backend & Data': 'Backend & Daten',
|
||||
'Design & Creative': 'Design & Kreativität',
|
||||
'Fintech & Crypto': 'Fintech & Krypto',
|
||||
'E-Commerce & Retail': 'E-Commerce & Handel',
|
||||
'Media & Consumer': 'Medien & Consumer',
|
||||
Automotive: 'Automotive',
|
||||
Uncategorized: 'Nicht kategorisiert',
|
||||
};
|
||||
|
||||
const DE_PROMPT_TEMPLATE_CATEGORIES: Record<string, string> = {
|
||||
Infographic: 'Infografik',
|
||||
'Anime / Manga': 'Anime / Manga',
|
||||
'App / Web Design': 'App- / Webdesign',
|
||||
Illustration: 'Illustration',
|
||||
'Profile / Avatar': 'Profil / Avatar',
|
||||
'Social Media Post': 'Social-Media-Post',
|
||||
General: 'Allgemein',
|
||||
Advertising: 'Werbung',
|
||||
'Motion Graphics': 'Motion Graphics',
|
||||
Cinematic: 'Filmisch',
|
||||
'VFX / Fantasy': 'VFX / Fantasy',
|
||||
Anime: 'Anime',
|
||||
'Social / Meme': 'Social / Meme',
|
||||
};
|
||||
|
||||
const DE_PROMPT_TEMPLATE_TAGS: Record<string, string> = {
|
||||
'3d-render': '3D-Render',
|
||||
action: 'Action',
|
||||
anime: 'Anime',
|
||||
cinematic: 'Filmisch',
|
||||
'cinematic-romance': 'Filmische Romanze',
|
||||
cyberpunk: 'Cyberpunk',
|
||||
fantasy: 'Fantasy',
|
||||
food: 'Food',
|
||||
nature: 'Natur',
|
||||
portrait: 'Porträt',
|
||||
product: 'Produkt',
|
||||
typography: 'Typografie',
|
||||
};
|
||||
|
||||
const DE_PROMPT_TEMPLATE_COPY: Record<string, Partial<Pick<PromptTemplateSummary, 'summary' | 'title'>>> = {
|
||||
'3d-stone-staircase-evolution-infographic': {
|
||||
title: '3D-Infografik einer Steintreppen-Evolution',
|
||||
summary:
|
||||
'Verwandelt eine flache Evolutions-Zeitachse in eine realistische 3D-Steintreppen-Infografik mit detaillierten Organismus-Renderings und strukturierten Seitenpanels.',
|
||||
},
|
||||
'anime-martial-arts-battle-illustration': {
|
||||
title: 'Anime-Kampfsport-Battle-Illustration',
|
||||
summary:
|
||||
'Erzeugt eine dynamische, wirkungsvolle Anime-Illustration von zwei weiblichen Figuren, die in einem traditionellen Dojo mit elementaren Energieeffekten kämpfen.',
|
||||
},
|
||||
'e-commerce-live-stream-ui-mockup': {
|
||||
title: 'E-Commerce-Livestream-UI-Mockup',
|
||||
summary:
|
||||
'Erzeugt ein realistisches Social-Media-Livestream-Interface über einem Porträt, inklusive anpassbarer Chat-Nachrichten, Geschenk-Popups und Produktkaufkarte.',
|
||||
},
|
||||
'illustrated-city-food-map': {
|
||||
title: 'Illustrierte Stadt-Food-Map',
|
||||
summary:
|
||||
'Erzeugt eine handgezeichnete Tourist Map im Aquarellstil mit nummerierten lokalen Spezialitäten, Sehenswürdigkeiten und Legende.',
|
||||
},
|
||||
'momotaro-explainer-slide-in-hybrid-style': {
|
||||
title: 'Momotaro-Erklärslide im Hybrid-Stil',
|
||||
summary:
|
||||
'Kombiniert die einfache, warme Ästhetik von Irasutoya-Illustrationen mit der hohen Informationsdichte japanischer Behörden-Slides.',
|
||||
},
|
||||
'profile-avatar-anime-girl-to-cinematic-photo': {
|
||||
title: 'Profil / Avatar - Anime-Girl zu filmischem Foto',
|
||||
summary:
|
||||
'Verwandelt eine Charakterreferenz-Illustration in ein realistisches, warm getöntes Vintage-Interieur-Porträt und bewahrt Outfit, Pose und Katze.',
|
||||
},
|
||||
'profile-avatar-casual-fashion-grid-photoshoot': {
|
||||
title: 'Profil / Avatar - Casual-Fashion-Grid-Fotoshooting',
|
||||
summary:
|
||||
'Strukturierter JSON-Prompt für eine 4-Foto-Collage eines lässigen Fashion-Shootings mit detaillierten Parametern für Person und Licht.',
|
||||
},
|
||||
'profile-avatar-cinematic-south-asian-male-portrait-with-vultures': {
|
||||
title: 'Profil / Avatar - Filmisches südasiatisches Männerporträt mit Geiern',
|
||||
summary:
|
||||
'Detailliertes filmisches Porträt eines jungen südasiatischen Mannes in einer düsteren Dark-Fantasy-Szene, umgeben von Geiern und Raben.',
|
||||
},
|
||||
'profile-avatar-cyberpunk-anime-portrait-with-neon-face-text': {
|
||||
title: 'Profil / Avatar - Cyberpunk-Anime-Porträt mit Neon-Gesichtstext',
|
||||
summary:
|
||||
'Stilvolles neongetränktes Anime-Porträt für Poster, Social-Media-Art oder futuristische Branding-Visuals.',
|
||||
},
|
||||
'profile-avatar-elegant-fantasy-girl-in-violet-garden': {
|
||||
title: 'Profil / Avatar - Elegantes Fantasy-Girl im violetten Garten',
|
||||
summary:
|
||||
'Erzeugt ein poliertes Anime-Fantasy-Porträt einer eleganten Frau mit glänzend gestyltem Haar, violett-schwarzer Kleidung und magischem Blumengarten.',
|
||||
},
|
||||
'profile-avatar-ethereal-blue-haired-fantasy-portrait': {
|
||||
title: 'Profil / Avatar - Ätherisches blauhaariges Fantasy-Porträt',
|
||||
summary:
|
||||
'Erzeugt ein weiches, leuchtendes Anime-Fantasy-Porträt für elegante vertikale Key Art oder Charakterillustrationen mit fließendem Haar.',
|
||||
},
|
||||
'profile-avatar-glamorous-woman-in-black-portrait': {
|
||||
title: 'Profil / Avatar - Glamouröses Frauenporträt in Schwarz',
|
||||
summary:
|
||||
'Erzeugt ein fotorealistisches Luxusporträt einer eleganten Frau in schwarzem Outfit, ideal für Fashion Editorials oder Beauty Imagery.',
|
||||
},
|
||||
'profile-avatar-hyper-realistic-selfie-texture-prompts': {
|
||||
title: 'Profil / Avatar - Hyperrealistische Selfie-Textur-Prompts',
|
||||
summary:
|
||||
'Detaillierte Prompt-Snippets für realistische Hauttexturen und authentisches Smartphone-Selfie-Framing mit sichtbaren Poren und natürlichem Licht.',
|
||||
},
|
||||
'profile-avatar-lavender-fantasy-mage-portrait': {
|
||||
title: 'Profil / Avatar - Lavendel-Fantasy-Magierinnenporträt',
|
||||
summary:
|
||||
'Erzeugt ein poliertes Anime-Fantasy-Porträt einer eleganten Magierprinzessin mit blondem Haar, violetten Blumen und Kristallkleidung.',
|
||||
},
|
||||
'profile-avatar-monochrome-studio-portrait': {
|
||||
title: 'Profil / Avatar - Monochromes Studio-Porträt',
|
||||
summary:
|
||||
'High-end Commercial-Photography-Prompt für ein monochromes Porträt mit markant geteiltem Hintergrund und dramatischem Studiolicht.',
|
||||
},
|
||||
'profile-avatar-old-photo-restoration-to-dslr-portrait': {
|
||||
title: 'Profil / Avatar - Alte Fotorestaurierung zu DSLR-Porträt',
|
||||
summary:
|
||||
'Restauriert ein beschädigtes Vintage-Familienfoto mit vier Personen zu einem sauberen, kolorierten, hochauflösenden realistischen Porträt.',
|
||||
},
|
||||
'profile-avatar-poetic-woman-in-garden-portrait': {
|
||||
title: 'Profil / Avatar - Poetisches Frauenporträt im Garten',
|
||||
summary:
|
||||
'Erzeugt ein realistisches Editorial-Porträt einer belesenen jungen Frau in einem sonnigen Garten, ideal für Lifestyle-Fotografie oder Literary Branding.',
|
||||
},
|
||||
'profile-avatar-professional-identity-portrait-wallpaper': {
|
||||
title: 'Profil / Avatar - Professionelles Identity-Porträt-Wallpaper',
|
||||
summary:
|
||||
'Erzeugt ein hochauflösendes Premium-Wallpaper mit einer Person in professioneller Kleidung, beruflichen Aktivitäten und Typografie.',
|
||||
},
|
||||
'profile-avatar-realistically-imperfect-ai-selfie': {
|
||||
title: 'Profil / Avatar - Realistisch unperfektes AI-Selfie',
|
||||
summary:
|
||||
'Kreativer GPT-Image-2-Prompt für ein „misslungenes“ Selfie, das wie ein zufälliger, niedrigqualitativer Smartphone-Schnappschuss wirkt.',
|
||||
},
|
||||
'profile-avatar-signed-marker-portrait-on-shikishi': {
|
||||
title: 'Profil / Avatar - Signiertes Marker-Porträt auf Shikishi',
|
||||
summary:
|
||||
'Erzeugt ein lebendiges signiertes Marker-Porträt auf quadratischem Shikishi-Board für Fan-Art-Autogramme und persönliche Dankesvisuals.',
|
||||
},
|
||||
'profile-avatar-snow-rabbit-empress-portrait': {
|
||||
title: 'Profil / Avatar - Schneehasen-Kaiserin-Porträt',
|
||||
summary:
|
||||
'Realistischer Fantasy-Porträtprompt für eine königliche, hasenmotivierte Frau in winterlichem Hanfu vor einem verschneiten Bergtempel.',
|
||||
},
|
||||
'profile-avatar-snow-rabbit-mask-hanfu-portrait': {
|
||||
title: 'Profil / Avatar - Schneehasenmasken-Hanfu-Porträt',
|
||||
summary:
|
||||
'Erzeugt ein filmisches Winter-Fantasy-Porträt einer maskierten Frau in weißem Hanfu mit Hasenmotiv, ideal für elegante Charakterkunst.',
|
||||
},
|
||||
'profile-avatar-snowy-rabbit-hanfu-portrait': {
|
||||
title: 'Profil / Avatar - Verschneites Hasen-Hanfu-Porträt',
|
||||
summary:
|
||||
'Erzeugt ein ultradetailliertes Fantasy-Beauty-Porträt einer hasenohrigen Frau in besticktem Hanfu für Charakterkunst oder Kostümdesign.',
|
||||
},
|
||||
'profile-avatar-snowy-rabbit-spirit-portrait': {
|
||||
title: 'Profil / Avatar - Verschneites Hasengeist-Porträt',
|
||||
summary:
|
||||
'Erzeugt ein ruhiges Fantasy-Porträt einer anonymen hasenohrigen Frau im Winter, ideal für atmosphärische Charakterkunst.',
|
||||
},
|
||||
'profile-avatar-song-dynasty-hanfu-portrait': {
|
||||
title: 'Profil / Avatar - Hanfu-Porträt der Song-Dynastie',
|
||||
summary:
|
||||
'Optimierter Prompt für ein detailliertes realistisches Porträt einer Schönheit im traditionellen Hanfu der Song-Dynastie in einem antiken Hof.',
|
||||
},
|
||||
'social-media-post-anime-pokemon-shop-outfit-teaser-poster': {
|
||||
title: 'Social-Media-Post - Anime-Pokémon-Shop-Outfit-Teaser',
|
||||
summary:
|
||||
'Erzeugt ein weiches pastelliges Anime-Fashion-Announcement-Poster mit verschwommenem Gesicht in einem Pokémon-Store.',
|
||||
},
|
||||
'social-media-post-cinematic-elevator-scene': {
|
||||
title: 'Social-Media-Post - Filmische Aufzugsszene',
|
||||
summary:
|
||||
'Prompt für eine düstere, filmische Szene einer Frau in einem metallischen Aufzug mit realistischem Licht und Reflexionen.',
|
||||
},
|
||||
'social-media-post-confused-elf-girl-at-pastel-desk': {
|
||||
title: 'Social-Media-Post - Verwirrtes Elf-Girl am Pastell-Schreibtisch',
|
||||
summary:
|
||||
'Erzeugt eine weiche pastellige Anime-Illustration eines Elf-Girls am Computer in einem gemütlichen Kawaii-Workspace.',
|
||||
},
|
||||
'social-media-post-editorial-fashion-photography': {
|
||||
title: 'Social-Media-Post - Editorial-Fashion-Fotografie',
|
||||
summary:
|
||||
'Stimmungsvoller, fashion-fokussierter Prompt für eine minimalistische Studioszene mit weichem Licht und warmen Tönen.',
|
||||
},
|
||||
'social-media-post-fashion-editorial-collage': {
|
||||
title: 'Social-Media-Post - Fashion-Editorial-Collage',
|
||||
summary:
|
||||
'Hochdetaillierter 2x2-Fotocollage-Prompt für Fashion-Editorial-Shots mit konsistentem Styling, spezifischem Licht und Referenzgesicht.',
|
||||
},
|
||||
'social-media-post-psg-transfer-announcement-poster': {
|
||||
title: 'Social-Media-Post - PSG-Transfer-Ankündigungsposter',
|
||||
summary:
|
||||
'Kräftiges professionelles Football-Signing-Poster zur Ankündigung eines Spielerwechsels zu Paris Saint-Germain.',
|
||||
},
|
||||
'social-media-post-showa-day-retro-culture-magazine-cover': {
|
||||
title: 'Social-Media-Post - Retro-Kultur-Magazincover zum Showa Day',
|
||||
summary:
|
||||
'Warme Editorial-Seite zu einem japanischen Feiertag mit Anime-Charakterkunst, nostalgischer Showa-Straßenszene und Magazinlayout.',
|
||||
},
|
||||
'social-media-post-social-media-fashion-outfit-generation': {
|
||||
title: 'Social-Media-Post - Fashion-Outfit-Generierung',
|
||||
summary:
|
||||
'Prompt zur Generierung einer Woche Fashion-Blogger-Outfit-Empfehlungen auf Basis eines Charakterprofils, inklusive Labels und Preisen.',
|
||||
},
|
||||
'social-media-post-travel-snapshot-collage-prompt': {
|
||||
title: 'Social-Media-Post - Travel-Snapshot-Collage',
|
||||
summary:
|
||||
'Detaillierter Prompt für eine nostalgische 12-Frame-Collage aus smartphoneartigen Reisefotos einer Solo-Reise.',
|
||||
},
|
||||
'social-media-post-vintage-sign-painter-sketch': {
|
||||
title: 'Social-Media-Post - Vintage-Sign-Painter-Skizze',
|
||||
summary:
|
||||
'Erzeugt eine handgezeichnete Marker-Skizze auf Papier mit realistischen Details wie Graphitlinien und Tintenverlauf.',
|
||||
},
|
||||
'vr-headset-exploded-view-poster': {
|
||||
title: 'VR-Headset-Explosionsansicht-Poster',
|
||||
summary:
|
||||
'Erzeugt ein Hightech-Explosionsdiagramm eines VR-Headsets mit detaillierten Komponenten-Callouts und Promotion-Text.',
|
||||
},
|
||||
'3d-animated-boy-building-lego': {
|
||||
title: '3D-animierter Junge baut Lego',
|
||||
summary:
|
||||
'Multi-Shot-Video-Prompt im 3D-Animationsstil über einen Jungen, der in einem Zimmer vorsichtig Lego-Steine zusammensetzt, inklusive Time-Lapse-Effekten.',
|
||||
},
|
||||
'a-decade-of-refinement-glow-up': {
|
||||
title: 'Ein Jahrzehnt Verfeinerung: Glow-Up',
|
||||
summary:
|
||||
'Transformation-Prompt für Seedance 2.0, der einen Mann von einem lockeren 2016-Setting zu einem luxuriösen Dubai-Lifestyle 2026 führt.',
|
||||
},
|
||||
'ancient-guardian-dragon-rescue': {
|
||||
title: 'Rettung durch einen uralten Wächterdrachen',
|
||||
summary:
|
||||
'Detaillierter filmischer Multi-Shot-Prompt über ein Mädchen in einem regnerischen Dorf, das von einem auftauchenden Drachen gerettet wird.',
|
||||
},
|
||||
'ancient-indian-kingdom-fpv-video': {
|
||||
title: 'FPV-Video eines alten indischen Königreichs',
|
||||
summary:
|
||||
'Schneller filmischer FPV-Drohnenprompt, der ein mystisches indisches Königreich mit Tempeln und Dschungeln zeigt.',
|
||||
},
|
||||
'animation-transfer-and-camera-tracking-prompt': {
|
||||
title: 'Prompt für Animation Transfer und Camera Tracking',
|
||||
summary:
|
||||
'Technischer Prompt für Seedance 2.0, der eine bestimmte Bewegungsreferenz auf eine Figur anwendet und zugleich festes Camera Tracking hält.',
|
||||
},
|
||||
'beat-synced-outfit-transformation-dance': {
|
||||
title: 'Beat-synchroner Outfit-Transformationstanz',
|
||||
summary:
|
||||
'Seedance-2.0-Prompt, der eine Figur anhand von Breakdown-Frames tanzen lässt und einen beat-synchronen Outfitwechsel ausführt.',
|
||||
},
|
||||
'character-intro-motion-graphics-sequence': {
|
||||
title: 'Character-Intro-Motion-Graphics-Sequenz',
|
||||
summary:
|
||||
'Komplexer mehrstufiger Motion-Graphics-Prompt zur Vorstellung eines Character-Teams mit UI-Overlays und Übergängen.',
|
||||
},
|
||||
'cinematic-birthday-celebration-sequence': {
|
||||
title: 'Filmische Geburtstagsfeier-Sequenz',
|
||||
summary:
|
||||
'Hochdetaillierter Multi-Shot-Video-Prompt für eine Geburtstagssequenz mit Fokus auf Charakterkonsistenz und emotionalem Storytelling.',
|
||||
},
|
||||
'cinematic-dragon-interaction-flight': {
|
||||
title: 'Filmische Dracheninteraktion und Flug',
|
||||
summary:
|
||||
'Detaillierter Storyboard-Prompt für ein Video mit emotionaler Interaktion zwischen einer Frau und einem Drachen, gefolgt von einem filmischen Flug.',
|
||||
},
|
||||
'cinematic-east-asian-woman-hand-dance': {
|
||||
title: 'Filmischer Handtanz einer ostasiatischen Frau',
|
||||
summary:
|
||||
'Hochdetaillierter filmischer Multi-Shot-Video-Prompt für einen stilisierten Handtanz mit time-coded Kamera- und Handlungsanweisungen.',
|
||||
},
|
||||
'cinematic-emotional-face-close-up': {
|
||||
title: 'Filmisches emotionales Face-Close-up',
|
||||
summary:
|
||||
'Hochdetaillierter technischer Seedance-2.0-Prompt mit Fokus auf realistische Hauttexturen und komplexe emotionale Gesichtstransitionen.',
|
||||
},
|
||||
'cinematic-marine-biologist-exploration': {
|
||||
title: 'Filmische Erkundung einer Meeresbiologin',
|
||||
summary:
|
||||
'Detaillierter filmischer Video-Prompt für eine Unterwasserszene, in der eine Meeresbiologin ein altes Schiffswrack in einem Korallenriff entdeckt.',
|
||||
},
|
||||
'cinematic-music-podcast-and-guitar-technique': {
|
||||
title: 'Filmischer Musik-Podcast und Gitarrentechnik',
|
||||
summary:
|
||||
'Fortgeschrittener filmischer Prompt für ein 4K-Musikpodcast-Video mit Fokus auf Gitarrentechnik, Pinch Harmonics und Studioästhetik.',
|
||||
},
|
||||
'cinematic-route-navigation-guide': {
|
||||
title: 'Filmischer Routen-Navigationsguide',
|
||||
summary:
|
||||
'Strukturierter Multi-Scene-Prompt für Seedance, um ein konsistentes Walking-Navigation-Video mit wiederkehrendem Tour-Guide zu erstellen.',
|
||||
},
|
||||
'cinematic-street-racing-sequence-for-seedance-2': {
|
||||
title: 'Filmische Street-Racing-Sequenz für Seedance 2',
|
||||
summary:
|
||||
'Detaillierter Multi-Shot-Prompt für eine nächtliche Street-Racing-Sequenz mit intensivem Fahrerfokus, dynamischer Kameraarbeit und explosiver Beschleunigung.',
|
||||
},
|
||||
'cinematic-vampire-alley-fight-sequence': {
|
||||
title: 'Filmische Vampir-Kampfszene in einer Gasse',
|
||||
summary:
|
||||
'Umfassender Action-Prompt für eine Kurzfilmszene mit dynamischer Kamera und Hochgeschwindigkeitskampf in einer neonbeleuchteten Gasse.',
|
||||
},
|
||||
'crimson-horizon-sci-fi-cinematic-sequence': {
|
||||
title: 'Crimson Horizon Sci-Fi-Filmsequenz',
|
||||
summary:
|
||||
'Umfassende 9-Shot-Filmsequenz für einen Sci-Fi-Film namens „Crimson Horizon“, vom Raketenstart bis zur unheimlichen Alien-Begegnung auf dem Mars.',
|
||||
},
|
||||
'cyberpunk-game-trailer-script': {
|
||||
title: 'Cyberpunk-Game-Trailer-Script',
|
||||
summary:
|
||||
'Ausführlicher Video-Prompt für einen Cyberpunk-Game-Trailer mit Charakterdesign, UI-Animationen und Umgebungswechsel vom weißen Void zur Favela.',
|
||||
},
|
||||
'forbidden-city-cat-satire': {
|
||||
title: 'Satire mit Katze in der Verbotenen Stadt',
|
||||
summary:
|
||||
'Komplexer Dark-Comedy-Prompt für Seedance 2.0 mit einem orangefarbenen Katzenbeamten und einem Hyänenkaiser in einer satirischen Qing-Dynastie-Szene.',
|
||||
},
|
||||
'hollywood-haute-couture-fantasy-video-prompt': {
|
||||
title: 'Hollywood-Haute-Couture-Fantasy-Video-Prompt',
|
||||
summary:
|
||||
'Detaillierter Multi-Scene-Video-Prompt für Seedance 2.0, ausgelegt auf einen Hollywood-Haute-Couture-Fantasy-Film mit 8K/Unreal-Engine-Ästhetik.',
|
||||
},
|
||||
'hunched-character-animation': {
|
||||
title: 'Animation einer gebeugten Figur',
|
||||
summary:
|
||||
'Anweisung für Seedance 2, eine In-place-Walking-Animation für eine bestimmte Charakterreferenz zu erstellen.',
|
||||
},
|
||||
'live-action-anime-adaptation-water-vs-thunder-breathing-duel': {
|
||||
title: 'Live-Action-Anime-Adaption: Wasser- vs. Donner-Atmungsduell',
|
||||
summary:
|
||||
'Hochdetaillierter 15-Sekunden-Prompt für eine Live-Action-Adaption eines Anime-Duells mit blauen Wasser- und goldenen Blitzeffekten.',
|
||||
},
|
||||
'luxury-supercar-cinematic-narrative': {
|
||||
title: 'Filmische Luxus-Supercar-Erzählung',
|
||||
summary:
|
||||
'Hochdetaillierter filmischer Multi-Shot-Prompt für Seedance 2.0 mit stilvollem Mann, Dobermännern und Vintage-Supercar in nebliger Bergszene.',
|
||||
},
|
||||
'magical-academy-storyboard-sequence': {
|
||||
title: 'Storyboard-Sequenz einer magischen Akademie',
|
||||
summary:
|
||||
'Detaillierter Storyboard-Prompt für eine filmische Sequenz über ein Magical Girl an einer Akademie, von Ankunft bis magischem Duell.',
|
||||
},
|
||||
'modern-rural-aesthetics-healing-short-film-video-prompt': {
|
||||
title: 'Healing-Kurzfilm im modernen Rural-Aesthetic-Stil',
|
||||
summary:
|
||||
'Detaillierter Three-Shot-Prompt für Seedance 2.0, der einen heilenden filmischen Kurzfilm im modernen Rural-Aesthetic-Stil erzeugt.',
|
||||
},
|
||||
'nightclub-flyer-atmospheric-animation': {
|
||||
title: 'Atmosphärische Animation eines Nightclub-Flyers',
|
||||
summary:
|
||||
'Subtiler Seedance-2.0-Animationsprompt, der Hintergrund- und Lichtelemente zum Leben erweckt, während das Motiv fixiert bleibt.',
|
||||
},
|
||||
'retro-hk-wuxia-film-aesthetic': {
|
||||
title: 'Retro-HK-Wuxia-Filmästhetik',
|
||||
summary:
|
||||
'Komplexer mehrteiliger Video-Prompt, der die 80er-/90er-Hongkong-Wuxia-Filmästhetik mit einer Verwandlung von Katze zu Mensch nachbildet.',
|
||||
},
|
||||
'seedance-2-0-15-second-cinematic-japanese-romance-short-film': {
|
||||
title: 'Seedance 2.0: 15-Sekunden-filmischer japanischer Romance-Kurzfilm',
|
||||
summary:
|
||||
'Hochdetaillierter 15-Sekunden-Multi-Scene-Prompt für einen filmischen, ultrarealistischen japanischen High-School-Romance-Kurzfilm.',
|
||||
},
|
||||
'seedance-2-0-80-year-old-rapper-mv': {
|
||||
title: 'Seedance 2.0: 80-jährige Rapperin im Musikvideo',
|
||||
summary:
|
||||
'Detaillierter 15-Sekunden-Prompt für ein horizontales Street-Rap-MV in 16:9 mit einer 80-jährigen Frau und kühlen Neonviolett-/Blautönen.',
|
||||
},
|
||||
'sequence-and-movement-instruction-for-martial-arts-video': {
|
||||
title: 'Sequenz- und Bewegungsanweisung für Kampfsportvideo',
|
||||
summary:
|
||||
'Video-Prompt für Seedance 2.0, der eine Sequenz anhand eines Character Sheets animiert und spezifische Bewegungen und Schritte betont.',
|
||||
},
|
||||
'soul-switching-mirror-magic-sequence': {
|
||||
title: 'Magische Spiegel-Sequenz mit Seelentausch',
|
||||
summary:
|
||||
'Narrativer Video-Prompt über ein magisches Seelentausch-Ereignis an einem Spiegel, mit Kameraanweisungen und emotionalen Cues.',
|
||||
},
|
||||
'toaster-rocket-jumpscare': {
|
||||
title: 'Toaster-Raketen-Jumpscare',
|
||||
summary:
|
||||
'Prompt für eine realistische Home-Video-Aufnahme eines alten Mannes, der erschrickt, als ein Toaster Brot wie eine Rakete abschießt.',
|
||||
},
|
||||
'traditional-dance-performance': {
|
||||
title: 'Traditionelle Tanzperformance',
|
||||
summary:
|
||||
'Umfassender Seedance-2.0-Video-Prompt für einen anmutigen traditionellen Tanz auf Basis von Choreografie- und Identitätsreferenzbildern.',
|
||||
},
|
||||
'vintage-disney-style-pirate-crocodile-animation': {
|
||||
title: 'Piraten-Krokodil-Animation im Vintage-Disney-Stil',
|
||||
summary:
|
||||
'Mehrszeniger narrativer Prompt für eine klassische Vintage-Disney-Animation mit einem Krokodilpiraten und Vogelpiraten auf einem Schiff.',
|
||||
},
|
||||
'viral-k-pop-dance-choreography': {
|
||||
title: 'Virale K-Pop-Dance-Choreografie',
|
||||
summary:
|
||||
'Detaillierter Seedance-2.0-Prompt, der eine Figur eine Choreografie auf Basis eines 16-Panel-Storyboard-Referenzbilds tanzen lässt.',
|
||||
},
|
||||
'wasteland-factory-chase': {
|
||||
title: 'Wasteland-Factory-Chase',
|
||||
summary:
|
||||
'Filmischer Prompt für eine High-Speed-Wüsten-Wasteland-Szene mit einer laufenden Industriefabrik auf Beinen und einer Verfolgung per Rebel Bike.',
|
||||
},
|
||||
};
|
||||
|
||||
export const GERMAN_CONTENT_IDS = {
|
||||
skills: Object.keys(DE_SKILL_COPY),
|
||||
designSystems: Object.keys(DE_DESIGN_SYSTEM_SUMMARIES),
|
||||
designSystemCategories: Object.keys(DE_DESIGN_SYSTEM_CATEGORIES),
|
||||
promptTemplates: Object.keys(DE_PROMPT_TEMPLATE_COPY),
|
||||
promptTemplateCategories: Object.keys(DE_PROMPT_TEMPLATE_CATEGORIES),
|
||||
promptTemplateTags: Object.keys(DE_PROMPT_TEMPLATE_TAGS),
|
||||
};
|
||||
|
||||
function isGerman(locale: Locale): boolean {
|
||||
return locale === 'de';
|
||||
}
|
||||
|
||||
function normalizeText(text: string): string {
|
||||
return text.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
export function localizeSkillPrompt(locale: Locale, skill: SkillSummary): string | undefined {
|
||||
if (isGerman(locale)) {
|
||||
const translated = DE_SKILL_COPY[skill.id]?.examplePrompt;
|
||||
if (translated) return translated;
|
||||
}
|
||||
return skill.examplePrompt ? normalizeText(skill.examplePrompt) : undefined;
|
||||
}
|
||||
|
||||
export function localizeSkillDescription(locale: Locale, skill: SkillSummary): string {
|
||||
if (isGerman(locale)) {
|
||||
const translated = DE_SKILL_COPY[skill.id]?.description;
|
||||
if (translated) return translated;
|
||||
}
|
||||
return normalizeText(skill.description);
|
||||
}
|
||||
|
||||
export function localizeDesignSystemSummary(
|
||||
locale: Locale,
|
||||
system: DesignSystemSummary,
|
||||
): string {
|
||||
if (isGerman(locale)) {
|
||||
const translated = DE_DESIGN_SYSTEM_SUMMARIES[system.id];
|
||||
if (translated) return translated;
|
||||
}
|
||||
return system.summary || system.category || '';
|
||||
}
|
||||
|
||||
export function localizeDesignSystemCategory(locale: Locale, category: string): string {
|
||||
if (!isGerman(locale)) return category;
|
||||
return DE_DESIGN_SYSTEM_CATEGORIES[category] ?? category;
|
||||
}
|
||||
|
||||
export function localizePromptTemplateCategory(locale: Locale, category: string): string {
|
||||
if (!isGerman(locale)) return category;
|
||||
return DE_PROMPT_TEMPLATE_CATEGORIES[category] ?? category;
|
||||
}
|
||||
|
||||
export function localizePromptTemplateSummary(
|
||||
locale: Locale,
|
||||
template: PromptTemplateSummary,
|
||||
): PromptTemplateSummary {
|
||||
if (!isGerman(locale)) return template;
|
||||
const translated = DE_PROMPT_TEMPLATE_COPY[template.id];
|
||||
const tags = template.tags?.map((tag) => DE_PROMPT_TEMPLATE_TAGS[tag] ?? tag);
|
||||
return {
|
||||
...template,
|
||||
title: translated?.title ?? template.title,
|
||||
summary: translated?.summary ?? template.summary,
|
||||
category: localizePromptTemplateCategory(locale, template.category || 'General'),
|
||||
tags,
|
||||
};
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
useState,
|
||||
type ReactNode,
|
||||
} from 'react';
|
||||
import { de } from './locales/de';
|
||||
import { en } from './locales/en';
|
||||
import { esES } from './locales/es-ES';
|
||||
import { fa } from './locales/fa';
|
||||
|
|
@ -25,6 +26,7 @@ type DictKey = keyof Dict;
|
|||
|
||||
const DICTS: Record<Locale, Dict> = {
|
||||
'en': en,
|
||||
'de': de,
|
||||
'zh-CN': zhCN,
|
||||
'zh-TW': zhTW,
|
||||
'pt-BR': ptBR,
|
||||
|
|
|
|||
49
apps/web/src/i18n/locales.test.ts
Normal file
49
apps/web/src/i18n/locales.test.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { en } from './locales/en';
|
||||
import { LOCALES, LOCALE_LABEL, type Dict, type Locale } from './types';
|
||||
|
||||
const EXPECTED_LOCALES = ['en', 'de', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa'];
|
||||
|
||||
function placeholders(value: string): string[] {
|
||||
const names: string[] = [];
|
||||
for (const match of value.matchAll(/\{(\w+)\}/g)) {
|
||||
if (match[1]) {
|
||||
names.push(match[1]);
|
||||
}
|
||||
}
|
||||
return names.sort();
|
||||
}
|
||||
|
||||
async function loadDict(locale: Locale): Promise<Dict> {
|
||||
const module = await import(`./locales/${locale}.ts`);
|
||||
const dict = Object.values(module).find((value): value is Dict => {
|
||||
return Boolean(value) && typeof value === 'object';
|
||||
});
|
||||
if (!dict) {
|
||||
throw new Error(`No dictionary export found for locale ${locale}`);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
describe('i18n locales', () => {
|
||||
it('registers every supported locale in the language menu', () => {
|
||||
expect(LOCALES).toEqual(EXPECTED_LOCALES);
|
||||
expect((LOCALE_LABEL as Record<string, string>).de).toBe('Deutsch');
|
||||
});
|
||||
|
||||
it('keeps locale dictionaries aligned with English keys and placeholders', async () => {
|
||||
const englishKeys = Object.keys(en).sort();
|
||||
|
||||
for (const locale of LOCALES) {
|
||||
const dict = await loadDict(locale);
|
||||
expect(Object.keys(dict).sort()).toEqual(englishKeys);
|
||||
|
||||
for (const key of englishKeys) {
|
||||
const dictKey = key as keyof Dict;
|
||||
expect(placeholders(dict[dictKey]), `${locale}.${key}`).toEqual(
|
||||
placeholders(en[dictKey]),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
629
apps/web/src/i18n/locales/de.ts
Normal file
629
apps/web/src/i18n/locales/de.ts
Normal file
|
|
@ -0,0 +1,629 @@
|
|||
import type { Dict } from '../types';
|
||||
|
||||
export const de: Dict = {
|
||||
'common.cancel': 'Abbrechen',
|
||||
'common.save': 'Speichern',
|
||||
'common.close': 'Schließen',
|
||||
'common.delete': 'Löschen',
|
||||
'common.rename': 'Umbenennen',
|
||||
'common.preview': 'Vorschau',
|
||||
'common.share': 'Teilen',
|
||||
'common.search': 'Suchen',
|
||||
'common.searchEllipsis': 'Suchen…',
|
||||
'common.loading': 'Wird geladen…',
|
||||
'common.all': 'Alle',
|
||||
'common.none': 'Keine',
|
||||
'common.default': 'Standard',
|
||||
'common.installed': 'installiert',
|
||||
'common.notInstalled': 'nicht installiert',
|
||||
'common.active': 'aktiv',
|
||||
'common.offline': 'offline',
|
||||
'common.selected': 'ausgewählt',
|
||||
'common.create': 'Erstellen',
|
||||
'common.openPreview': 'Vorschau öffnen',
|
||||
'common.exitFullscreen': 'Vollbild verlassen',
|
||||
'common.fullscreen': 'Vollbild',
|
||||
'common.openInNewTab': 'In neuem Tab öffnen',
|
||||
'common.exportPdf': 'Als PDF exportieren',
|
||||
'common.exportZip': 'Als .zip herunterladen',
|
||||
'common.exportHtml': 'Als eigenständiges HTML exportieren',
|
||||
'common.justNow': 'gerade eben',
|
||||
'common.minutesAgo': 'vor {n} Min.',
|
||||
'common.hoursAgo': 'vor {n} Std.',
|
||||
'common.daysAgo': 'vor {n} T.',
|
||||
'common.now': 'jetzt',
|
||||
'common.minutesShort': '{n} Min.',
|
||||
'common.hoursShort': '{n} Std.',
|
||||
'common.daysShort': '{n} T.',
|
||||
'common.untitled': 'Ohne Titel',
|
||||
|
||||
'app.brand': 'Open Design',
|
||||
'app.brandPill': 'Forschungsvorschau',
|
||||
'app.brandSubtitle': 'von Nexu Labs',
|
||||
'app.welcomeLoading': 'Workspace wird geladen…',
|
||||
|
||||
'settings.welcomeKicker': 'Willkommen',
|
||||
'settings.welcomeTitle': 'Open Design einrichten',
|
||||
'settings.welcomeSubtitle':
|
||||
'Wählen Sie aus, wie Generierungen ausgeführt werden sollen. Sie können dies jederzeit über die Schaltfläche „Einstellungen“ in der oberen Leiste ändern.',
|
||||
'settings.kicker': 'Einstellungen',
|
||||
'settings.title': 'Ausführung & Modell',
|
||||
'settings.subtitle':
|
||||
'Wählen Sie zwischen einer lokalen Code-Agent-CLI und der Anthropic API (BYOK). Ihr API-Key wird nur in diesem Browser gespeichert.',
|
||||
'settings.modeAria': 'Ausführungsmodus',
|
||||
'settings.modeDaemon': 'Lokale CLI',
|
||||
'settings.modeDaemonHelp': 'Über eine Code-Agent-CLI auf Ihrem Rechner ausführen',
|
||||
'settings.modeDaemonOffline': 'Daemon läuft nicht',
|
||||
'settings.modeDaemonOfflineMeta': 'Daemon offline',
|
||||
'settings.modeDaemonInstalledMeta': '{count} installiert',
|
||||
'settings.modeApi': 'Anthropic API',
|
||||
'settings.modeApiMeta': 'BYOK',
|
||||
'settings.codeAgent': 'Code-Agent',
|
||||
'settings.codeAgentHint':
|
||||
'Durch Scannen Ihres PATH erkannt. Wählen Sie die CLI, über die Generierungen laufen sollen.',
|
||||
'settings.rescan': '↻ Neu scannen',
|
||||
'settings.rescanTitle': 'PATH erneut scannen',
|
||||
'settings.noAgentsDetected':
|
||||
'Noch keine Agents erkannt. Installieren Sie Claude Code, Codex, Gemini CLI, OpenCode, Cursor Agent, Qwen oder GitHub Copilot CLI und klicken Sie dann auf Neu scannen.',
|
||||
'settings.apiSection': 'Anthropic API',
|
||||
'settings.apiKey': 'API-Key',
|
||||
'settings.showKey': 'Key anzeigen',
|
||||
'settings.hideKey': 'Key ausblenden',
|
||||
'settings.show': 'Anzeigen',
|
||||
'settings.hide': 'Ausblenden',
|
||||
'settings.model': 'Modell',
|
||||
'settings.baseUrl': 'Base URL',
|
||||
'settings.apiHint':
|
||||
'Aufrufe gehen direkt von diesem Browser an die festgelegte Base URL. Kein Proxy. Der Key verlässt localStorage nie.',
|
||||
'settings.skipForNow': 'Vorerst überspringen',
|
||||
'settings.getStarted': 'Loslegen',
|
||||
'settings.envConfigure': 'Ausführungsmodus konfigurieren',
|
||||
'settings.localCli': 'Lokale CLI',
|
||||
'settings.anthropicApi': 'Anthropic API',
|
||||
'settings.noAgentSelected': 'kein Agent ausgewählt',
|
||||
'settings.language': 'Sprache',
|
||||
'settings.languageHint': 'Wechseln Sie die Sprache der Oberfläche. Wird in diesem Browser gespeichert.',
|
||||
'settings.modelPicker': 'Modell',
|
||||
'settings.reasoningPicker': 'Reasoning-Aufwand',
|
||||
'settings.modelPickerHint':
|
||||
'Wird aus der CLI geladen, wenn sie einen `models`-Befehl anbietet. „Standard“ überlässt die Auswahl der CLI-Konfiguration; mit „Benutzerdefiniert…“ können Sie jede von der CLI akzeptierte Modell-ID eingeben.',
|
||||
'settings.modelCustom': 'Benutzerdefiniert (unten eingeben)…',
|
||||
'settings.modelCustomLabel': 'Benutzerdefinierte Modell-ID',
|
||||
'settings.modelCustomPlaceholder': 'z. B. anthropic/claude-sonnet-4-6',
|
||||
'settings.mediaProviders': 'Medienanbieter',
|
||||
'settings.mediaProvidersHint':
|
||||
'API-Keys für Bild-, Video- und Audiogenerierung. Lokal gespeichert und mit dem lokalen Daemon synchronisiert.',
|
||||
'settings.mediaProviderApiKey': 'API-Key',
|
||||
'settings.mediaProviderBaseUrl': 'Base URL',
|
||||
'settings.mediaProviderConfigured': 'Konfiguriert',
|
||||
'settings.mediaProviderUnset': 'Nicht gesetzt',
|
||||
'settings.mediaProviderClear': 'Leeren',
|
||||
'settings.mediaProviderPlaceholder': 'API-Key einfügen',
|
||||
'settings.mediaProviderBaseUrlPlaceholder': 'Standard-Base-URL überschreiben',
|
||||
|
||||
'entry.tabDesigns': 'Designs',
|
||||
'entry.tabExamples': 'Beispiele',
|
||||
'entry.tabDesignSystems': 'Designsysteme',
|
||||
'entry.openSettingsTitle': 'Einstellungen',
|
||||
'entry.openSettingsAria': 'Einstellungen öffnen',
|
||||
'entry.resizeAria': 'Seitenleiste skalieren',
|
||||
'entry.loadingWorkspace': 'Workspace wird geladen…',
|
||||
'entry.tabImageTemplates': 'Bild-Prompts',
|
||||
'entry.tabVideoTemplates': 'Video-Prompts',
|
||||
'promptTemplates.searchPlaceholder': 'Templates suchen…',
|
||||
'promptTemplates.countLabel': '{n} Ergebnisse',
|
||||
'promptTemplates.emptyImage': 'Noch keine Bild-Prompt-Templates installiert.',
|
||||
'promptTemplates.emptyVideo': 'Noch keine Video-Prompt-Templates installiert.',
|
||||
'promptTemplates.emptyNoMatch': 'Keine Templates passen zu Ihrer Suche.',
|
||||
'promptTemplates.attributionFooter': 'Aus öffentlichen Prompt-Bibliotheken adaptiert. Jede Karte verlinkt zum ursprünglichen Autor.',
|
||||
'promptTemplates.openPreviewTitle': 'Prompt und Vorschau öffnen',
|
||||
'promptTemplates.sourcePrefix': 'Quelle:',
|
||||
'promptTemplates.fetchError': 'Dieser Template-Inhalt konnte nicht geladen werden.',
|
||||
'promptTemplates.promptLabel': 'Prompt-Text',
|
||||
'promptTemplates.copyPrompt': 'Prompt kopieren',
|
||||
'promptTemplates.copyDone': 'Kopiert!',
|
||||
'promptTemplates.modelHint': 'Vorgeschlagenes Modell: {model}',
|
||||
'promptTemplates.openSource': 'Original anzeigen',
|
||||
'promptTemplates.openFullscreen': 'Vollbildvorschau öffnen',
|
||||
'promptTemplates.closeFullscreen': 'Vollbildvorschau schließen',
|
||||
|
||||
'newproj.tabPrototype': 'Prototyp',
|
||||
'newproj.tabDeck': 'Slide Deck',
|
||||
'newproj.tabTemplate': 'Aus Template',
|
||||
'newproj.tabOther': 'Andere',
|
||||
'newproj.titlePrototype': 'Neuer Prototyp',
|
||||
'newproj.titleDeck': 'Neues Slide Deck',
|
||||
'newproj.titleTemplate': 'Mit Template starten',
|
||||
'newproj.titleImage': 'Neues Bild',
|
||||
'newproj.titleVideo': 'Neues Video',
|
||||
'newproj.titleAudio': 'Neues Audio',
|
||||
'newproj.titleOther': 'Neues Projekt',
|
||||
'newproj.namePlaceholder': 'Projektname',
|
||||
'newproj.fidelityLabel': 'Detailgrad',
|
||||
'newproj.fidelityWireframe': 'Wireframe',
|
||||
'newproj.fidelityHigh': 'High Fidelity',
|
||||
'newproj.toggleSpeakerNotes': 'Sprechernotizen verwenden',
|
||||
'newproj.toggleSpeakerNotesHint': 'Weniger Text auf Slides — Gesprächspunkte in Notizen halten.',
|
||||
'newproj.toggleAnimations': 'Animationen einbeziehen',
|
||||
'newproj.toggleAnimationsHint':
|
||||
'Bewegung (Einstiege, Hover, Übergänge) zusätzlich zum Template hinzufügen.',
|
||||
'newproj.templateLabel': 'Template',
|
||||
'newproj.noTemplatesTitle': 'Noch keine Templates',
|
||||
'newproj.noTemplatesBody':
|
||||
'Öffnen Sie ein Projekt und nutzen Sie dann das Teilen-Menü im File Viewer, um es in ein Template umzuwandeln. Templates erscheinen hier.',
|
||||
'newproj.savedTemplate': 'Gespeichertes Template',
|
||||
'newproj.fileSingular': 'Datei',
|
||||
'newproj.filePlural': 'Dateien',
|
||||
'newproj.create': 'Erstellen',
|
||||
'newproj.createFromTemplate': 'Aus Template erstellen',
|
||||
'newproj.createDisabledTitle':
|
||||
'Speichern Sie zuerst ein Projekt als Template (Teilen-Menü in einem beliebigen Projekt).',
|
||||
'newproj.importClaudeZip': 'Claude Design ZIP importieren',
|
||||
'newproj.importClaudeZipTitle': 'Einen Claude Design .zip-Export importieren',
|
||||
'newproj.importingClaudeZip': 'Import läuft…',
|
||||
'newproj.privacyFooter': 'Standardmäßig können nur Sie Ihr Projekt sehen.',
|
||||
'newproj.designSystem': 'Designsystem',
|
||||
'newproj.dsNoneFreeform': 'Keines — frei',
|
||||
'newproj.dsNoneSubtitleEmpty': 'Keine System-Tokens, eigene Palette wählen',
|
||||
'newproj.dsNoneSubtitleSelected': 'System-Tokens überspringen. Der Agent wählt eine eigene Palette.',
|
||||
'newproj.dsCategoryFallback': 'Designsystem',
|
||||
'newproj.dsSearch': 'Designsysteme suchen…',
|
||||
'newproj.dsModeAria': 'Auswahlmodus',
|
||||
'newproj.dsModeSingle': 'Einzeln',
|
||||
'newproj.dsModeMulti': 'Mehrfach',
|
||||
'newproj.dsNoneTitle': 'Keines — frei',
|
||||
'newproj.dsNoneSub': 'System-Tokens überspringen. Der Agent wählt eine eigene Palette.',
|
||||
'newproj.dsEmpty': 'Keine Designsysteme passen zu „{query}“.',
|
||||
'newproj.dsFootSingular': 'dient nur als Inspiration.',
|
||||
'newproj.dsFootPlural': 'dienen nur als Inspiration.',
|
||||
'newproj.dsFootClear': 'Leeren',
|
||||
'newproj.dsBadgeDefault': 'STANDARD',
|
||||
'newproj.dsPrimaryFallback': 'Primär',
|
||||
'newproj.surfaceImage': 'Bild',
|
||||
'newproj.surfaceVideo': 'Video',
|
||||
'newproj.surfaceAudio': 'Audio',
|
||||
'newproj.modelLabel': 'Modell',
|
||||
'newproj.aspectLabel': 'Format',
|
||||
'newproj.imageStyleLabel': 'Stilnotizen',
|
||||
'newproj.imageStylePlaceholder': 'Editorial-Foto, weiches Tageslicht, gedämpfte Palette',
|
||||
'newproj.videoLengthLabel': 'Länge',
|
||||
'newproj.videoLengthSeconds': '{n}s',
|
||||
'newproj.audioKindLabel': 'Audiotyp',
|
||||
'newproj.audioKindMusic': 'Musik',
|
||||
'newproj.audioKindSpeech': 'Sprache / TTS',
|
||||
'newproj.audioKindSfx': 'SFX',
|
||||
'newproj.audioDurationLabel': 'Dauer',
|
||||
'newproj.audioDurationSeconds': '{n}s',
|
||||
'newproj.voiceLabel': 'Stimme',
|
||||
'newproj.voicePlaceholder': 'Provider-Voice-ID, optional',
|
||||
|
||||
'designs.subRecent': 'Aktuell',
|
||||
'designs.subYours': 'Ihre Designs',
|
||||
'designs.filterAria': 'Projekte filtern',
|
||||
'designs.searchPlaceholder': 'Suchen…',
|
||||
'designs.emptyNoProjects': 'Noch keine Projekte. Erstellen Sie links eines.',
|
||||
'designs.emptyNoMatch': 'Keine Projekte passen zu Ihrer Suche.',
|
||||
'designs.deleteTitle': 'Projekt löschen',
|
||||
'designs.deleteConfirm': '„{name}“ löschen?',
|
||||
'designs.cardFreeform': 'frei',
|
||||
'designs.status.notStarted': 'Nicht gestartet',
|
||||
'designs.status.queued': 'In Warteschlange',
|
||||
'designs.status.running': 'Läuft',
|
||||
'designs.status.awaitingInput': 'Eingabe nötig',
|
||||
'designs.status.succeeded': 'Abgeschlossen',
|
||||
'designs.status.failed': 'Fehlgeschlagen',
|
||||
'designs.status.canceled': 'Abgebrochen',
|
||||
'designs.viewToggleAria': 'Ansichtsmodus',
|
||||
'designs.viewGrid': 'Rasteransicht',
|
||||
'designs.viewKanban': 'Board-Ansicht',
|
||||
'designs.kanbanEmptyColumn': 'Keine Designs',
|
||||
'designs.deleteAria': 'Projekt {name} löschen',
|
||||
|
||||
'examples.typeLabel': 'Typ',
|
||||
'examples.surfaceLabel': 'Oberfläche',
|
||||
'examples.surfaceWeb': 'Web',
|
||||
'examples.surfaceImage': 'Bild',
|
||||
'examples.surfaceVideo': 'Video',
|
||||
'examples.surfaceAudio': 'Audio',
|
||||
'examples.scenarioLabel': 'Szenario',
|
||||
'examples.modeAll': 'Alle',
|
||||
'examples.modePrototypeDesktop': 'Prototypen · Desktop',
|
||||
'examples.modePrototypeMobile': 'Prototypen · Mobil',
|
||||
'examples.modeDeck': 'Folien',
|
||||
'examples.modeDocument': 'Dokumente & Templates',
|
||||
'examples.scenarioGeneral': 'Allgemein',
|
||||
'examples.scenarioEngineering': 'Engineering',
|
||||
'examples.scenarioProduct': 'Produkt',
|
||||
'examples.scenarioDesign': 'Design',
|
||||
'examples.scenarioMarketing': 'Marketing',
|
||||
'examples.scenarioSales': 'Vertrieb',
|
||||
'examples.scenarioFinance': 'Finanzen',
|
||||
'examples.scenarioHr': 'Personal',
|
||||
'examples.scenarioOperations': 'Betrieb',
|
||||
'examples.scenarioSupport': 'Support',
|
||||
'examples.scenarioLegal': 'Recht',
|
||||
'examples.scenarioEducation': 'Bildung',
|
||||
'examples.scenarioPersonal': 'Persönlich',
|
||||
'examples.emptyNoSkills': 'Keine Skills verfügbar. Läuft der Daemon?',
|
||||
'examples.emptyNoMatch': 'Keine Beispiele passen zu diesen Filtern.',
|
||||
'examples.openPreview': '⤢ Vorschau öffnen',
|
||||
'examples.loadingPreview': 'Vorschau wird geladen…',
|
||||
'examples.hoverPreview': 'Für Vorschau hovern',
|
||||
'examples.usePrompt': 'Diesen Prompt verwenden',
|
||||
'examples.previewModalTitle': 'Vollständige Vorschau öffnen (Modal)',
|
||||
'examples.shareTitle': 'Dieses Beispiel teilen',
|
||||
'examples.shareLoadFirst': 'Zuerst hovern, um die Vorschau zu laden',
|
||||
'examples.shareMenu': 'Teilen ▾',
|
||||
'examples.exportPdfAllSlides': 'Als PDF exportieren (alle Slides)',
|
||||
'examples.exportPptxLocked': 'Als PPTX exportieren… (zuerst Template öffnen)',
|
||||
'examples.tagSlideDeck': 'Foliendeck',
|
||||
'examples.tagTemplate': 'Template',
|
||||
'examples.tagDesignSystem': 'Designsystem',
|
||||
'examples.tagMobilePrototype': 'Mobiler Prototyp',
|
||||
'examples.tagDesktopPrototype': 'Desktop-Prototyp',
|
||||
'examples.tagImage': 'Bild',
|
||||
'examples.tagVideo': 'Video',
|
||||
'examples.tagAudio': 'Audio',
|
||||
'examples.previewLabel': 'Vorschau',
|
||||
|
||||
'ds.surfaceLabel': 'Oberfläche',
|
||||
'ds.surfaceWeb': 'Web',
|
||||
'ds.surfaceImage': 'Bild',
|
||||
'ds.surfaceVideo': 'Video',
|
||||
'ds.surfaceAudio': 'Audio',
|
||||
'ds.searchPlaceholder': 'Designsysteme suchen…',
|
||||
'ds.emptyNoMatch': 'Keine Designsysteme passen zu Ihrer Suche.',
|
||||
'ds.badgeDefault': 'STANDARD',
|
||||
'ds.preview': 'Vorschau',
|
||||
'ds.previewTitle': 'Designsystem-Vorschau',
|
||||
'ds.categoryAll': 'Alle',
|
||||
'ds.categoryUncategorized': 'Nicht kategorisiert',
|
||||
'ds.showcase': 'Showcase',
|
||||
'ds.tokens': 'Tokens',
|
||||
|
||||
'avatar.title': 'Konto & Einstellungen',
|
||||
'avatar.localCli': 'Lokale CLI',
|
||||
'avatar.anthropicApi': 'Anthropic API',
|
||||
'avatar.useLocal': 'Lokale CLI verwenden',
|
||||
'avatar.useApi': 'Anthropic API verwenden',
|
||||
'avatar.codeAgent': 'Code-Agent',
|
||||
'avatar.rescan': 'PATH neu scannen',
|
||||
'avatar.settings': 'Einstellungen',
|
||||
'avatar.backToProjects': 'Zurück zu Projekten',
|
||||
'avatar.metaActive': 'aktiv',
|
||||
'avatar.metaOffline': 'offline',
|
||||
'avatar.metaSelected': 'ausgewählt',
|
||||
'avatar.noAgentSelected': 'kein Agent ausgewählt',
|
||||
'avatar.modelSection': 'Modell',
|
||||
'avatar.modelLabel': 'Modell',
|
||||
'avatar.reasoningLabel': 'Reasoning',
|
||||
'avatar.customSuffix': '(benutzerdefiniert)',
|
||||
|
||||
'project.backToProjects': 'Zurück zu Projekten',
|
||||
'project.metaFreeform': 'frei',
|
||||
'chat.tabChat': 'Chat',
|
||||
'chat.tabComments': 'Kommentare',
|
||||
'chat.commentsSoon': 'Kommentare — demnächst',
|
||||
'chat.conversationsTitle': 'Konversationen',
|
||||
'chat.conversationsAria': 'Konversationsverlauf',
|
||||
'chat.newConversation': 'Neue Konversation',
|
||||
'chat.newConversationsTitle': 'Neue Konversation',
|
||||
'chat.conversationsHeading': 'Konversationen',
|
||||
'chat.new': 'Neu',
|
||||
'chat.emptyConversations': 'Noch keine Konversationen.',
|
||||
'chat.deleteConversation': 'Konversation löschen',
|
||||
'chat.deleteConversationConfirm':
|
||||
'„{title}“ löschen? Dadurch werden die Nachrichten entfernt.',
|
||||
'chat.untitledConversation': 'Konversation ohne Titel',
|
||||
'chat.startTitle': 'Konversation starten',
|
||||
'chat.startHint':
|
||||
'Legen Sie Bilder als visuelle Referenz ab, fügen Sie sie ein oder tippen Sie @, um eine Datei aus diesem Projekt anzuhängen. Oder probieren Sie einen dieser Starts:',
|
||||
'chat.fillInputTitle': 'Klicken, um die Eingabe zu füllen',
|
||||
'chat.jumpToLatest': 'Zur neuesten springen',
|
||||
'chat.scrollToLatest': 'Zur neuesten scrollen',
|
||||
'chat.you': 'Sie',
|
||||
'chat.openFile': '{name} öffnen',
|
||||
'chat.composerPlaceholder':
|
||||
'Beschreiben Sie das gewünschte Design — Bilder einfügen/ablegen oder mit @ eine Datei referenzieren…',
|
||||
'chat.composerHint':
|
||||
'⌘/Ctrl + Enter zum Senden · Bilder einfügen · @ für Dateireferenzen',
|
||||
'chat.cliSettingsTitle': 'CLI- & Modelleinstellungen',
|
||||
'chat.cliSettingsAria': 'CLI- und Modelleinstellungen öffnen',
|
||||
'chat.attachTitle': 'Dateien anhängen (oder einfügen / ablegen)',
|
||||
'chat.attachAria': 'Dateien anhängen',
|
||||
'chat.importTitle': 'Quellen importieren (demnächst)',
|
||||
'chat.importLabel': 'Importieren',
|
||||
'chat.importComingSoon': 'Demnächst',
|
||||
'chat.importSoon': 'Bald',
|
||||
'chat.importFig': '.fig-Datei hochladen',
|
||||
'chat.importGitHub': 'GitHub verbinden',
|
||||
'chat.importWeb': 'Webelement erfassen',
|
||||
'chat.importFolder': 'Code-Ordner verknüpfen',
|
||||
'chat.importSkills': 'Skills und Designsysteme',
|
||||
'chat.importProject': 'Anderes Projekt referenzieren',
|
||||
'chat.send': 'Senden',
|
||||
'chat.stop': 'Stoppen',
|
||||
'chat.removeAria': '{name} entfernen',
|
||||
'chat.example1Title': 'Editorial Pitch Deck',
|
||||
'chat.example1Tag': 'Magazin',
|
||||
'chat.example1Prompt':
|
||||
'Ein 10-Slide-Editorial-Pitch-Deck für ein Designstudio, das eine Seed-Runde aufnimmt — Swiss-Grid-Layout, übergroße Serif-Headlines mit markanten Initialen, Monospace-Abschnittsnummern, großzügiger Negativraum und Full-Bleed-Fotoslides im Wechsel mit textlastigen Slides. Cover, Vision, Markt, Produkt, Traction, Team, Ask, Kontakt.',
|
||||
'chat.example2Title': 'SaaS-Analytics-Dashboard',
|
||||
'chat.example2Tag': 'Daten',
|
||||
'chat.example2Prompt':
|
||||
'Ein dichtes Analytics-Dashboard für ein Developer-Tools-SaaS — KPI-Leiste mit Week-over-Week-Deltas, zwei gestapelte Liniendiagramme (MRR und aktive Workspaces), eine Welt-Heatmap der Nutzung, ein Kohorten-Retention-Raster, eine Top-Customers-Bestenliste und ein Echtzeit-Event-Feed. Dark Theme, tabellarische Monospace-Ziffern, Sparkline-Akzente.',
|
||||
'chat.example3Title': 'Annual Report Long-Scroll',
|
||||
'chat.example3Tag': 'Editorial',
|
||||
'chat.example3Prompt':
|
||||
'Ein interaktiver Annual Report für eine Klima-Non-Profit-Organisation — Long-Scroll-Editorial-Layout mit großen Pull-Quote-Blöcken, Datenvisualisierungen (gestapelte Balken, animierte Counter, Choropleth-Karte der Projektstandorte), Fotobrechern, Spenderwand und finalem Call-to-Action. Moderne Serifenschrift für Body, Sans-Serif-Chartlabels, erdige Papierpalette.',
|
||||
|
||||
'preview.shareMenu': 'Teilen ▾',
|
||||
'preview.openInNewTab': 'In neuem Tab öffnen',
|
||||
'preview.exit': '⤓ Beenden',
|
||||
'preview.fullscreen': '⤢ Vollbild',
|
||||
'preview.closeTitle': 'Schließen (Esc)',
|
||||
'preview.loading': '{label} wird geladen…',
|
||||
|
||||
'misc.savedTemplate': 'Gespeichertes Template',
|
||||
'misc.primary': 'Primär',
|
||||
'misc.designSystem': 'Designsystem',
|
||||
|
||||
'workspace.designFiles': 'Design-Dateien',
|
||||
'workspace.closeTab': 'Tab schließen',
|
||||
'workspace.deleteFileConfirm': '„{name}“ aus dem Projektordner löschen?',
|
||||
'workspace.openFromDesignFiles': 'Datei öffnen aus',
|
||||
'workspace.designFilesLink': 'Design-Dateien',
|
||||
'workspace.loadingSketch': 'Sketch wird geladen…',
|
||||
'designFiles.title': 'Design-Dateien',
|
||||
'designFiles.upload': 'Dateien hochladen',
|
||||
'designFiles.pasteText': 'Als Textdatei einfügen',
|
||||
'designFiles.newSketch': 'Neuer Sketch',
|
||||
'designFiles.empty':
|
||||
'Noch nichts hier. Legen Sie unten Dateien ab oder erstellen Sie einen Sketch / fügen Sie Text ein.',
|
||||
'designFiles.refresh': 'Aktualisieren',
|
||||
'designFiles.delete': 'Löschen',
|
||||
'designFiles.searchPlaceholder': 'Dateien suchen…',
|
||||
'designFiles.up': 'Nach oben',
|
||||
'designFiles.back': 'Zurück',
|
||||
'designFiles.crumbs': 'Projekt',
|
||||
'designFiles.rowMenu': 'Zeilenmenü',
|
||||
'designFiles.openInTab': 'In Tab öffnen',
|
||||
'designFiles.download': 'Herunterladen',
|
||||
'designFiles.dropTitle': '⤓ Dateien hier ablegen',
|
||||
'designFiles.dropDesc':
|
||||
'Bilder, Docs, Referenzen, Figma-Links oder Ordner — Claude nutzt sie als Kontext.',
|
||||
'designFiles.upload.title': 'Dateien hochladen',
|
||||
'designFiles.paste.title': 'Text als Datei einfügen',
|
||||
'designFiles.upload.label': 'Hochladen',
|
||||
'designFiles.paste.label': 'Einfügen',
|
||||
'designFiles.previewOpen': 'Öffnen',
|
||||
'designFiles.previewClose': 'Vorschau schließen',
|
||||
'designFiles.modified': 'Geändert {time} · {size}',
|
||||
'designFiles.weeksAgo': 'vor {n} W.',
|
||||
'designFiles.sectionPages': 'Seiten',
|
||||
'designFiles.sectionScripts': 'Skripte',
|
||||
'designFiles.sectionImages': 'Bilder',
|
||||
'designFiles.sectionSketches': 'Sketches',
|
||||
'designFiles.sectionOther': 'Andere',
|
||||
'designFiles.kindHtml': 'HTML-Seite',
|
||||
'designFiles.kindImage': 'Bild',
|
||||
'designFiles.kindSketch': 'Sketch',
|
||||
'designFiles.kindText': 'Text',
|
||||
'designFiles.kindCode': 'Skript',
|
||||
'designFiles.kindPdf': 'PDF',
|
||||
'designFiles.kindDocument': 'Dokument',
|
||||
'designFiles.kindPresentation': 'Präsentation',
|
||||
'designFiles.kindSpreadsheet': 'Tabellenblatt',
|
||||
'designFiles.kindBinary': 'Binärdatei',
|
||||
'pasteDialog.title': 'Text einfügen',
|
||||
'pasteDialog.hint': 'Wird im Projektordner gespeichert. Wählen Sie einen beliebigen Namen.',
|
||||
'pasteDialog.fileNameLabel': 'Dateiname',
|
||||
'pasteDialog.namePlaceholder': 'notes.txt',
|
||||
'pasteDialog.contentLabel': 'Inhalt',
|
||||
'pasteDialog.contentPlaceholder': 'Beliebigen Text einfügen…',
|
||||
'pasteDialog.save': 'Speichern',
|
||||
'pasteDialog.cancel': 'Abbrechen',
|
||||
'sketch.save': 'Sketch speichern',
|
||||
'sketch.cancel': 'Abbrechen',
|
||||
'sketch.saving': 'Speichern…',
|
||||
'sketch.tooltipDirty': 'Ungespeicherte Änderungen',
|
||||
'sketch.tooltipClean': 'Gespeichert',
|
||||
'fileViewer.empty': 'Wählen Sie eine Datei zur Ansicht aus.',
|
||||
'fileViewer.loading': 'Wird geladen…',
|
||||
'fileViewer.exportPptx': 'Als PPTX exportieren',
|
||||
'fileViewer.openInNewTab': 'In neuem Tab öffnen',
|
||||
'fileViewer.copyPath': 'Pfad kopieren',
|
||||
'fileViewer.copied': 'Kopiert!',
|
||||
'fileViewer.share': 'Teilen',
|
||||
'fileViewer.binaryMeta': 'Binärdatei · {size}',
|
||||
'fileViewer.binaryNote':
|
||||
'Binärdatei ({size} Bytes). Laden Sie sie herunter oder öffnen Sie sie von der Festplatte, um sie zu prüfen.',
|
||||
'fileViewer.pdfMeta': 'PDF · {size}',
|
||||
'fileViewer.documentMeta': 'Dokument',
|
||||
'fileViewer.presentationMeta': 'Präsentation',
|
||||
'fileViewer.spreadsheetMeta': 'Tabellenblatt',
|
||||
'fileViewer.previewUnavailable': 'Vorschau nicht verfügbar. Laden Sie die Datei herunter oder öffnen Sie sie zur Prüfung.',
|
||||
'fileViewer.download': 'Herunterladen',
|
||||
'fileViewer.open': 'Öffnen',
|
||||
'fileViewer.imageMeta': 'Bild · {size}',
|
||||
'fileViewer.sketchMeta': 'Sketch · {size}',
|
||||
'fileViewer.markdownStreamingMeta': 'Streaming-Vorschau…',
|
||||
'fileViewer.markdownErrorMeta': 'Vorschau ist möglicherweise unvollständig (Generierungsfehler).',
|
||||
'fileViewer.markdownStreamingStatus': 'Streaming… zeige partielles Markdown.',
|
||||
'fileViewer.markdownErrorStatus': 'Generierungsfehler. Zeige letzten verfügbaren Inhalt.',
|
||||
'fileViewer.videoMeta': 'Video · {size}',
|
||||
'fileViewer.audioMeta': 'Audio · {size}',
|
||||
'fileViewer.reload': 'Neu laden',
|
||||
'fileViewer.reloadDisk': 'Von Festplatte neu laden',
|
||||
'fileViewer.copy': 'Kopieren',
|
||||
'fileViewer.copyTitle': 'Dateiinhalte kopieren',
|
||||
'fileViewer.saveDisabled': 'Speichern (Read-only-Viewer)',
|
||||
'fileViewer.save': 'Speichern',
|
||||
'fileViewer.preview': 'Vorschau',
|
||||
'fileViewer.source': 'Quelle',
|
||||
'fileViewer.tweaks': 'Tweaks',
|
||||
'fileViewer.comment': 'Kommentieren',
|
||||
'fileViewer.edit': 'Bearbeiten',
|
||||
'fileViewer.draw': 'Zeichnen',
|
||||
'fileViewer.zoomOut': 'Verkleinern',
|
||||
'fileViewer.zoomIn': 'Vergrößern',
|
||||
'fileViewer.resetZoom': 'Zoom zurücksetzen',
|
||||
'fileViewer.reloadAria': 'Neu laden',
|
||||
'fileViewer.previousSlide': 'Vorherige Slide',
|
||||
'fileViewer.nextSlide': 'Nächste Slide',
|
||||
'fileViewer.slideNavAria': 'Slide-Navigation',
|
||||
'fileViewer.present': 'Präsentieren',
|
||||
'fileViewer.presentInTab': 'In diesem Tab',
|
||||
'fileViewer.presentFullscreen': 'Vollbild',
|
||||
'fileViewer.presentNewTab': 'Neuer Tab',
|
||||
'fileViewer.exitPresentation': 'Präsentation beenden',
|
||||
'fileViewer.shareLabel': 'Teilen',
|
||||
'fileViewer.exportPdf': 'Als PDF exportieren',
|
||||
'fileViewer.exportPdfAllSlides': 'Als PDF exportieren (alle Slides)',
|
||||
'fileViewer.exportPptxBusy': 'Warten Sie, bis der aktuelle Turn abgeschlossen ist.',
|
||||
'fileViewer.exportPptxHint':
|
||||
'Senden Sie eine Anfrage an den Agent, um dieses Design in PPTX umzuwandeln.',
|
||||
'fileViewer.exportPptxNa': 'PPTX-Export ist hier nicht verfügbar.',
|
||||
'fileViewer.exportZip': 'Als .zip herunterladen',
|
||||
'fileViewer.exportHtml': 'Als eigenständiges HTML exportieren',
|
||||
'fileViewer.saveAsTemplate': 'Als Template speichern…',
|
||||
'fileViewer.savingTemplate': 'Template wird gespeichert…',
|
||||
'fileViewer.savedTemplate': 'Als „{name}“ gespeichert',
|
||||
'fileViewer.savedTemplateFail': 'Template konnte nicht gespeichert werden — bitte erneut versuchen.',
|
||||
'fileViewer.templateNamePrompt': 'Template-Name',
|
||||
'fileViewer.templateNameDefault': 'Template ohne Titel',
|
||||
'fileViewer.templateDescPrompt':
|
||||
'Kurze Beschreibung (optional — was macht dieses Template nützlich?)',
|
||||
'fileViewer.deployToVercel': 'Auf Vercel deployen',
|
||||
'fileViewer.redeployToVercel': 'Erneut deployen',
|
||||
'fileViewer.deployingToVercel': 'Deployment auf Vercel läuft…',
|
||||
'fileViewer.preparingPublicLink': 'Öffentlicher Link wird vorbereitet…',
|
||||
'fileViewer.copyDeployLink': 'Link kopieren',
|
||||
'fileViewer.deployModalTitle': 'Auf Vercel deployen',
|
||||
'fileViewer.deployModalSubtitle':
|
||||
'Deployen Sie dieses HTML-Artifact als Vercel Preview mit Ihrem eigenen Konto.',
|
||||
'fileViewer.vercelToken': 'Vercel Token',
|
||||
'fileViewer.vercelTokenGetLink': 'Vercel Token abrufen',
|
||||
'fileViewer.vercelTokenPlaceholder': 'Vercel Token einfügen',
|
||||
'fileViewer.vercelTokenReuseHint':
|
||||
'Gespeicherter Token wird verwendet. Geben Sie einen neuen Token ein, um ihn zu ersetzen.',
|
||||
'fileViewer.vercelTokenRequired': 'Geben und speichern Sie zuerst einen Vercel Token.',
|
||||
'fileViewer.vercelTeamId': 'Team-ID',
|
||||
'fileViewer.vercelTeamSlug': 'Team-Slug',
|
||||
'fileViewer.optional': 'Optional',
|
||||
'fileViewer.vercelPreviewOnly': 'Deployments sind vorerst nur Previews.',
|
||||
'fileViewer.savingConfig': 'Speichern…',
|
||||
'fileViewer.deployConfigSaveFailed': 'Vercel-Einstellungen konnten nicht gespeichert werden.',
|
||||
'fileViewer.deployFailed': 'Deployment fehlgeschlagen. Prüfen Sie die Vercel-Einstellungen und versuchen Sie es erneut.',
|
||||
'fileViewer.deployResultLabel': 'Bereitgestellte URL',
|
||||
'fileViewer.deployLinkPreparingLabel': 'Öffentlicher Link ausstehend',
|
||||
'fileViewer.deployLinkDelayed':
|
||||
'Ihre Site ist deployed. Vercel bereitet den öffentlichen Link noch vor.',
|
||||
'fileViewer.deployLinkProtectedLabel': 'Vercel Protection aktiviert',
|
||||
'fileViewer.deployLinkProtected':
|
||||
'Ihre Site wurde deployed, aber Vercel verlangt Authentifizierung für diesen Preview-Link. Deaktivieren Sie Deployment Protection oder verwenden Sie eine Custom Domain.',
|
||||
'fileViewer.retryLink': 'Jetzt erneut versuchen',
|
||||
|
||||
'questionForm.submit': 'Absenden',
|
||||
'questionForm.skip': 'Überspringen',
|
||||
'questionForm.locked': 'Beantwortet',
|
||||
|
||||
'conv.switch': 'Konversation wechseln',
|
||||
'conv.label': 'Konversation',
|
||||
'conv.heading': 'Konversationen',
|
||||
'conv.new': '+ Neu',
|
||||
'conv.empty': 'Noch keine Konversationen.',
|
||||
'conv.untitled': 'Konversation ohne Titel',
|
||||
'conv.renameTooltip': 'Doppelklicken zum Umbenennen',
|
||||
'conv.delete': 'Konversation löschen',
|
||||
'conv.deleteConfirm': '„{title}“ löschen? Dadurch werden die Nachrichten entfernt.',
|
||||
|
||||
'agentPicker.label': 'Agent',
|
||||
'agentPicker.modeChoose': 'Ausführungsmodus wählen',
|
||||
'agentPicker.localCli': 'Lokale CLI',
|
||||
'agentPicker.daemonOff': 'Daemon aus',
|
||||
'agentPicker.byok': 'Anthropic API · BYOK',
|
||||
'agentPicker.selectAgent': 'Erkannte Code-Agent-CLI auswählen',
|
||||
'agentPicker.noAgents': 'keine Agents im PATH',
|
||||
'agentPicker.notInstalled': 'nicht installiert',
|
||||
'agentPicker.rescan': 'Lokalen PATH erneut nach Agents scannen',
|
||||
|
||||
'tool.openInTab': '{name} in einem Tab öffnen',
|
||||
'tool.open': 'öffnen',
|
||||
'tool.todos': 'Todos',
|
||||
'tool.write': 'Write',
|
||||
'tool.edit': 'Edit',
|
||||
'tool.read': 'Read',
|
||||
'tool.bash': 'Bash',
|
||||
'tool.glob': 'Glob',
|
||||
'tool.grep': 'Grep',
|
||||
'tool.fetch': 'Fetch',
|
||||
'tool.search': 'Search',
|
||||
'tool.lines': '{n} Zeilen',
|
||||
'tool.changeSingular': 'Änderung',
|
||||
'tool.changePlural': 'Änderungen',
|
||||
'tool.in': 'in {path}',
|
||||
'tool.hide': 'ausblenden',
|
||||
'tool.output': 'Ausgabe',
|
||||
'tool.running': 'läuft…',
|
||||
'tool.error': 'Fehler',
|
||||
'tool.done': 'fertig',
|
||||
|
||||
'assistant.role': 'Assistent',
|
||||
'assistant.workingLabel': 'Arbeitet',
|
||||
'assistant.doneLabel': 'Fertig',
|
||||
'assistant.unfinishedLabel': 'Mit unerledigter Arbeit gestoppt',
|
||||
'assistant.unfinishedSummary': '{n} Aufgabe(n) offen',
|
||||
'assistant.unfinishedMore': '+{n} weitere',
|
||||
'assistant.continueRemaining': 'Offene Aufgaben fortsetzen',
|
||||
'assistant.outTokens': '{n} ausgehend',
|
||||
'assistant.producedFiles': 'Dateien aus diesem Turn',
|
||||
'assistant.openFile': 'Öffnen',
|
||||
'assistant.downloadFile': 'Herunterladen',
|
||||
'assistant.thinking': 'Denkt',
|
||||
'assistant.systemReminder': 'Systemhinweis',
|
||||
'assistant.waitingFirstOutput': 'Warte auf erste Ausgabe',
|
||||
'assistant.statusBootingAgent': 'Agent wird gestartet',
|
||||
'assistant.statusStarting': 'Startet',
|
||||
'assistant.statusRequesting': 'Anfrage wird gesendet',
|
||||
'assistant.statusThinking': 'Denkt',
|
||||
'assistant.statusStreaming': 'Streamt',
|
||||
'assistant.slowHint':
|
||||
'Dauert länger als üblich. Das Formular erscheint normalerweise nach 5–10 s — Sie können Stoppen und umformulieren.',
|
||||
'assistant.verbEditing': 'Bearbeitet',
|
||||
'assistant.verbWriting': 'Schreibt',
|
||||
'assistant.verbReading': 'Liest',
|
||||
'assistant.verbSearching': 'Sucht',
|
||||
'assistant.verbRunning': 'Führt aus',
|
||||
'assistant.verbTodos': 'Todos',
|
||||
'assistant.verbFetching': 'Holt',
|
||||
'assistant.verbCalling': 'Ruft auf',
|
||||
|
||||
'qf.answered': 'beantwortet',
|
||||
'qf.choose': 'Auswählen…',
|
||||
'qf.required': 'erforderlich',
|
||||
'qf.lockedSubmitted':
|
||||
'Antworten gesendet — der Agent nutzt sie für den Rest der Sitzung.',
|
||||
'qf.lockedPrev': 'Dieses Formular stammt aus einem vorherigen Turn.',
|
||||
'qf.hint':
|
||||
'Wählen Sie, was passt. Überspringen Sie optionale Felder, die Ihnen egal sind — der Agent nutzt sinnvolle Standards.',
|
||||
'qf.submitDefault': 'Antworten senden',
|
||||
'qf.submitDisabledTitle': 'Füllen Sie zuerst die erforderlichen Felder aus',
|
||||
'qf.submitTitle': 'Antworten senden',
|
||||
'qf.cardSelected': 'ausgewählt',
|
||||
'qf.cardRefs': 'Refs:',
|
||||
'qf.cardSampleText': 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern · 0123',
|
||||
|
||||
'sketch.toolSelect': 'Auswählen (no-op)',
|
||||
'sketch.toolPen': 'Stift',
|
||||
'sketch.toolText': 'Text',
|
||||
'sketch.toolRect': 'Rechteck',
|
||||
'sketch.toolArrow': 'Pfeil',
|
||||
'sketch.toolEraser': 'Radierer',
|
||||
'sketch.color': 'Farbe',
|
||||
'sketch.strokeSize': 'Strichstärke',
|
||||
'sketch.undo': 'Rückgängig',
|
||||
'sketch.clear': 'Leeren',
|
||||
'sketch.close': 'Schließen',
|
||||
'sketch.textPrompt': 'Text:',
|
||||
};
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
// Supported UI locales. Adding a new locale requires creating a new
|
||||
// dictionary in `./locales/` and registering it in `./index.tsx`.
|
||||
export type Locale = 'en' | 'zh-CN' | 'zh-TW' | 'pt-BR' | 'es-ES' | 'ru' | 'fa';
|
||||
export type Locale = 'en' | 'de' | 'zh-CN' | 'zh-TW' | 'pt-BR' | 'es-ES' | 'ru' | 'fa';
|
||||
|
||||
export const LOCALES: Locale[] = ['en', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa'];
|
||||
export const LOCALES: Locale[] = ['en', 'de', 'zh-CN', 'zh-TW', 'pt-BR', 'es-ES', 'ru', 'fa'];
|
||||
|
||||
export const LOCALE_LABEL: Record<Locale, string> = {
|
||||
'en': 'English',
|
||||
'de': 'Deutsch',
|
||||
'zh-CN': '简体中文',
|
||||
'zh-TW': '繁體中文',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
|
|
|
|||
|
|
@ -847,14 +847,14 @@ code {
|
|||
color: currentColor;
|
||||
font-size: 13px;
|
||||
font-weight: 650;
|
||||
line-height: 1.2;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.settings-nav-item small {
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.25;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.settings-content {
|
||||
min-width: 0;
|
||||
|
|
@ -1048,6 +1048,7 @@ code {
|
|||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.settings-language-code,
|
||||
.settings-language-option-code {
|
||||
|
|
@ -1059,6 +1060,7 @@ code {
|
|||
.settings-language-menu {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
max-width: calc(100vw - 24px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
|
@ -2200,6 +2202,8 @@ code {
|
|||
left: 0;
|
||||
z-index: 50;
|
||||
min-width: 180px;
|
||||
width: max-content;
|
||||
max-width: min(280px, calc(100vw - 48px));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 4px;
|
||||
|
|
@ -2210,7 +2214,7 @@ code {
|
|||
}
|
||||
.lang-menu-item {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 7px 10px;
|
||||
|
|
@ -2222,6 +2226,10 @@ code {
|
|||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
.lang-menu-label {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.lang-menu-item:hover { background: var(--bg-subtle); }
|
||||
.lang-menu-item.active { background: var(--bg-subtle); }
|
||||
.lang-menu-item .lang-menu-code {
|
||||
|
|
@ -2250,13 +2258,22 @@ code {
|
|||
gap: 16px;
|
||||
padding: 14px 28px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
min-width: 0;
|
||||
}
|
||||
.entry-header-tabs-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
.entry-tabs { display: flex; gap: 2px; }
|
||||
.entry-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.entry-tabs::-webkit-scrollbar { display: none; }
|
||||
.entry-tab {
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
|
@ -2266,6 +2283,8 @@ code {
|
|||
font-size: 14px;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
flex: 0 0 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.entry-tab:hover:not(:disabled) { background: var(--bg-subtle); color: var(--text); }
|
||||
.entry-tab.active {
|
||||
|
|
@ -2276,6 +2295,7 @@ code {
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.entry-tab-content {
|
||||
|
|
@ -2296,13 +2316,21 @@ code {
|
|||
gap: 12px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.tab-panel-toolbar .toolbar-left,
|
||||
.tab-panel-toolbar .toolbar-right {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
min-width: 0;
|
||||
}
|
||||
.tab-panel-toolbar .toolbar-left { display: flex; gap: 8px; align-items: center; }
|
||||
.tab-panel-toolbar .toolbar-right { display: flex; gap: 8px; align-items: center; }
|
||||
.tab-panel-toolbar .toolbar-search {
|
||||
position: relative;
|
||||
width: 280px;
|
||||
max-width: 30vw;
|
||||
flex: 1 1 240px;
|
||||
width: min(280px, 100%);
|
||||
max-width: 100%;
|
||||
}
|
||||
.tab-panel-toolbar .toolbar-search input {
|
||||
padding-left: 30px;
|
||||
|
|
@ -2332,7 +2360,11 @@ code {
|
|||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-pill);
|
||||
gap: 2px;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.subtab-pill::-webkit-scrollbar { display: none; }
|
||||
.subtab-pill button {
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
|
@ -2341,6 +2373,7 @@ code {
|
|||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.subtab-pill button:hover:not(.active) { background: rgba(255,255,255,0.6); border-color: transparent; color: var(--text); }
|
||||
.subtab-pill button.active {
|
||||
|
|
@ -2766,8 +2799,19 @@ code {
|
|||
.ds-row-swatch + .ds-row-swatch { border-left: 1px solid rgba(0, 0, 0, 0.05); }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.entry { grid-template-columns: 1fr; }
|
||||
.entry-side { border-right: none; border-bottom: 1px solid var(--border); }
|
||||
.entry {
|
||||
grid-template-columns: 1fr !important;
|
||||
height: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.entry-side {
|
||||
width: 100% !important;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.entry-side-resizer { display: none; }
|
||||
.example-card { grid-template-columns: 1fr; }
|
||||
.example-preview { height: 240px; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue