mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 01:21:24 +02:00
Neues Comic-Modul: aus Text-Inputs (Journal / Notes / Writing / Library
/ Calendar) entsteht ein mehrseitiger Comic, generiert mit gpt-image-2
über die bestehende /picture/generate-with-reference-Route. Plan in
docs/plans/comic-module.md (M1–M5 + optional M6–M8).
M1 schafft die Datenschicht ohne UI:
- Dexie v44 `comicStories` (space-scoped, Indices createdAt/style/
isFavorite/isArchived). Story hält `panelImageIds: string[]` und
`panelMeta: Record<panelImageId, {caption, dialogue, promptUsed,
sourceInput?}>` — Panels selbst sind picture.images-Rows mit
comicStoryId + comicPanelIndex Back-Refs.
- Fünf Stil-Presets (comic / manga / cartoon / graphic-novel / webtoon)
mit Prompt-Prefix-Templates in styles.ts; composePanelPrompt webt
Stil + Panel-Prompt + Caption + Dialog zusammen. Sprechblasen
werden von gpt-image-2 direkt ins Bild gerendert — kein SVG-Overlay.
- Encryption-Registry-Eintrag: title / description / storyContext /
tags / panelMeta als JSON-Blob. Struktur (id, style, character-
MediaIds, panelImageIds, Flags, visibility) bleibt plaintext.
- Module-Registry registriert appId='comic', verifyMediaOwnership auf
der /picture/generate-with-reference-Route akzeptiert jetzt
['me', 'wardrobe', 'comic'] — 'comic'-Slot ist reserviert für M6+
Anchor-/Backdrop-Uploads.
- Space-Allowlist: comic in brand (Marken-Storys), club (Vereins-
geschichte), family (Kinder-Abenteuer), team (Release-Comics),
practice (Patienten-Aufklärung). Personal via '*'-Sentinel.
- mana-apps.ts Eintrag mit comic-Icon (Sprechblase + Lightning-Bolt,
f97316→dc2626 Gradient). Lokal tier='guest' mit LOCAL TIER PATCH-
Comment wie Wardrobe, canonical ist 'beta'.
Visibility-System von Anfang an adopted (setVisibility-Methode im
Store, unlistedToken-Generierung inklusive). appendPanel() als
Vorarbeit für M2 bereits da, ohne Aufrufer.
5 Encryption-Roundtrip-Tests grün (panelMeta nested JSON, leeres
panelMeta, partielle panelMeta ohne sourceInput, null-description).
pnpm run check + validate:all sauber (207 Dexie-Tabellen klassifiziert,
comicStories unter den 106 encrypted).
Kein UI, keine Panel-Generierung, keine MCP-Tools — alles M2/M3/M5.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
2.3 KiB
TypeScript
53 lines
2.3 KiB
TypeScript
/**
|
|
* Prompt-prefix templates per visual style. The prefix is prepended to
|
|
* every panel prompt in `runPanelGenerate` (M2); gpt-image-2 sees the
|
|
* composite (stylePrefix + panelPrompt + captionHint + dialogueHint),
|
|
* never the enum itself. Keep prefixes short and directive — they're
|
|
* spent on every call.
|
|
*
|
|
* Adding a style = extending `ComicStyle` in types.ts + `STYLE_LABELS`
|
|
* in constants.ts + a prefix here. The three stay in lockstep because
|
|
* Record<ComicStyle, …> forces exhaustive coverage.
|
|
*/
|
|
|
|
import type { ComicStyle } from './types';
|
|
|
|
export const STYLE_PREFIXES: Record<ComicStyle, string> = {
|
|
comic:
|
|
'US comic book illustration, bold clean linework, vivid cell-shaded coloring, dramatic lighting, high contrast, comic-panel framing',
|
|
manga:
|
|
'Japanese manga illustration, black and white line art with screen tones, dynamic perspective, expressive character design, dramatic motion lines',
|
|
cartoon:
|
|
'soft pastel cartoon illustration, rounded friendly shapes, warm saturated colors, Saturday-morning animation style, simple clean backgrounds',
|
|
'graphic-novel':
|
|
'graphic novel illustration, painterly watercolor style, muted atmospheric palette, cinematic composition, moody naturalistic lighting',
|
|
webtoon:
|
|
'modern webtoon illustration, clean vertical-scroll framing, bright saturated colors, soft cel-shading, expressive character close-ups',
|
|
};
|
|
|
|
/**
|
|
* Compose the final gpt-image-2 prompt for a single panel. Caption and
|
|
* dialogue (both optional) are rendered directly into the image by
|
|
* gpt-image-2 — no SVG overlay. Decision #4 in docs/plans/comic-module.md.
|
|
*
|
|
* The text-rendering language is whatever the user typed (gpt-image-2
|
|
* handles multiple languages, English is most stable but German works
|
|
* for short strings). UI surfaces an English-preferred hint.
|
|
*/
|
|
export function composePanelPrompt(input: {
|
|
style: ComicStyle;
|
|
panelPrompt: string;
|
|
caption?: string;
|
|
dialogue?: string;
|
|
}): string {
|
|
const parts: string[] = [STYLE_PREFIXES[input.style], input.panelPrompt.trim()];
|
|
const caption = input.caption?.trim();
|
|
const dialogue = input.dialogue?.trim();
|
|
if (caption) {
|
|
parts.push(`narration caption at the top reading: "${caption}"`);
|
|
}
|
|
if (dialogue) {
|
|
parts.push(`character speaking in a speech bubble saying: "${dialogue}"`);
|
|
}
|
|
return parts.join('. ');
|
|
}
|