Native Windows-first manga construction studio.
Planning files:
MASTER_PLAN.md- product + architecture + build order + release gatesBUSINESS.md- pricing, credits, go-to-market, and business assumptionsCONTENT_PLAN.md- launch library targets, sourcing, and pack expansionPROVIDER_NOTES.md- current managed AI providers and swap rulesDEVELOPMENT.md- build workflow, presets, env vars, debugging
App scaffold:
CMakeLists.txt- root build definitionCMakePresets.json-default(Debug) andrelease(Release) presetsvcpkg.json- manifest for native dependenciesscripts/bootstrap-vcpkg.ps1- clones, bootstraps, and hotfixes localvcpkgscripts/run-native.ps1- mounts a no-space build drive, then configures/builds/launches the appsrc/app/- first Qt 6 Widgets workstation shell
- Run
scripts/bootstrap-vcpkg.ps1 - Install
cmakeandninjaif missing - Configure with
scripts/run-native.ps1 configure(defaults todefaultpreset, i.e. Debug) - Build with
scripts/run-native.ps1 build - Launch with
scripts/run-native.ps1 launch
| Command | What it does |
|---|---|
mangastudio_native.exe |
Normal launch. Loads autosave / crash recovery prompts as needed. |
mangastudio_native.exe --selftest |
Runs the in-process self-test, prints result to log, exits 0 = pass. |
mangastudio_native.exe --crash-for-test |
Only honored when MANGASTUDIO_ENABLE_CRASH_TEST=1 is set. Schedules a deliberate null-deref in 2 s to exercise the SEH filter and .dmp writer. |
| Var | Effect |
|---|---|
MANGASTUDIO_LOG_CONSOLE=1 |
Mirror log lines to stderr in addition to the file logger. |
MANGASTUDIO_PROFILE=1 |
Enable the in-process profiler (scope-timer macros + top-N summary). |
MANGASTUDIO_ENABLE_CRASH_TEST=1 |
Unlocks the --crash-for-test CLI flag. Double-gated with the flag itself. |
- The helper script uses a temporary
substdrive becauseQt + vcpkg + CMakecan mis-handle repo paths with spaces duringqtbaseconfigure. - The real repo stays where it is; the drive alias is only used for build commands.
- Use the
releasepreset for any actual GUI run. The Debug build of Qt 6.10 has aFormat_Monocursor bug that crashes the app ~40 s after launch. Thereleasepreset is not optional for the GUI; it's only optional for non-GUI selftest runs. - See
DEVELOPMENT.mdfor the build-from-this-shell workflow, the VsDevCmd requirement, and the storage layout.
The page canvas accepts three stroke tools plus Select/Panel/Balloon/Text/Tone, all on the top toolbar.
| Tool | Shortcut | Color | Notes |
|---|---|---|---|
| Select | 1 |
– | Click a panel/balloon/object/stroke to select it. Delete removes the selected stroke. |
| Panel | 2 |
– | Drag a rect to create a new panel; click on an existing panel to split it. |
| Balloon | 3 |
– | Click inside a panel to add a speech balloon at that point. |
| Text | 4 |
– | Focuses the text dock on the active balloon for inline edits. |
| Tone | 5 |
– | Cycle tone presets (None, Light dots, Shadow hatch, Dense dots). |
| Pencil | 6 |
#1a1410 |
Default sketching tool. Pressure-sensitive on tablet. |
| Ink | 7 |
#000000 |
Hard outline. Pressure-sensitive on tablet. |
| Eraser | 8 |
– | Compositing-mode clear over the per-page raster cache. |
Pencil and Ink accept tablet pressure via QTabletEvent::pressure(); the mouse fallback uses a constant pressure = 1.0. Strokes go through a low-pass cursor smoother and are stored as per-segment points with width = baseWidth * (0.4 + 0.6 * pressure) per segment.
The View menu holds nine checkable overlays, persisted in studio-session.json under document.view and restored on the next launch:
- Show bleed
- Show safe
- Show heading
- Show rulers
- Show guides
- Show panel frames
- Show dialogue
- Show tone
- Show cast labels
View → Reset Workspace restores every overlay to its default (all on).
- Ctrl + scroll wheel — zoom (anchored at cursor). Range: 25 % to 400 %.
- Scroll wheel — pan vertically.
- Shift + scroll wheel — pan horizontally.
- Middle-mouse drag — pan.
- Ctrl + 0 — reset zoom and pan.
- The status bar shows the current zoom level (e.g.
Zoom: 150%).
The Page menu and the canvas right-click menu both open the Apply panel template picker. It loads 14 built-in templates and any custom ones you've saved. Pick a template, click Apply to replace the active page's panel layout, or click Customize... to enter template-edit mode and tweak the result.
Built-in templates ship in library/panel-templates.built-in.json (copied to %AppData%\MangaStudio\MangaStudio\library\ on first launch). Custom templates land in panel-templates.user.json and re-appear in the picker on every launch.
Enter from the picker (Customize...), from Page → Customize Current Layout..., or from the canvas right-click menu. While active:
- An orange banner appears under the page.
- The Inspector dock shows a gutter spin box (0.000 to 0.200) and Save as custom... / Exit buttons.
- Drag on an empty area of the page to add a new panel.
- Delete on a selected panel removes it; the panel's strokes and balloons are preserved as page-level "loose" content.
- Ctrl + S opens the "Save as custom" name/tags dialog.
- Esc exits customize mode.
Custom templates show up in the picker with their category badge and tag chips in the tooltip.
%AppData%\MangaStudio\MangaStudio\library\
panel-templates.built-in.json <- seeded from repo on first launch
panel-templates.user.json <- your custom templates
balloon-styles.built-in.json <- seeded from repo on first launch
balloon-styles.user.json <- your custom balloon styles
screentones.built-in.json <- seeded from repo on first launch
screentones.user.json <- your custom screentones
sfx.built-in.json <- seeded from repo on first launch
sfx.user.json <- your custom SFX
text-styles.built-in.json <- seeded from repo on first launch
text-styles.user.json <- your custom text styles
The Cast menu opens the Apply balloon style picker (shortcut Ctrl + Shift + B). It loads 12 built-in styles and any custom ones you've saved. Pick a style, click Apply to apply it to the currently selected balloon, or use Apply Balloon Style to All on Page from the Cast menu to retag every balloon on the current page.
Built-in styles ship in library/balloon-styles.built-in.json (copied to %AppData%\MangaStudio\MangaStudio\library\ on first launch). Custom styles land in balloon-styles.user.json and re-appear in the picker on every launch.
The 12 built-in styles cover the main families:
| Category | Styles |
|---|---|
| Speech | Rounded (default), Rectangle, Oval |
| Shout | Jagged, Burst, Spike |
| Thought | Cloud, Wavy |
| Whisper | Dashed |
| Caption | Box (light-on-dark), Box (light) |
| SFX | Heart (romance) |
When a balloon is selected and the Balloon tool is active, the Inspector dock shows the Balloon style editor:
- Shape combo (Rect, Rounded, Oval, Cloud, Jagged, Whisper, Burst, Caption, Spike, Spiked, Wavy, Heart)
- Tail position combo (None, Auto, Top-left/right, Bottom-left/right, Left, Right, Top, Bottom)
- Border width spin box (0.001 to 0.020)
- Corner radius spin box (0.00 to 0.30)
- Dashed checkbox
- Fill color and Border color pickers
- Reset returns to the style's defaults
- Save as custom... writes a new user-sourced entry
The header shows the current style name and library id, with a • customized marker when any override is active.
The Materials menu opens the Apply screentone picker (shortcut Ctrl + Shift + T). It loads 12 built-in tones and any custom ones you've saved. Pick a tone, click Apply to apply it to the active panel, or use Apply Screentone to All on Page from the Materials menu to retag every panel on the current page.
Built-in tones ship in library/screentones.built-in.json (copied to %AppData%\MangaStudio\MangaStudio\library\ on first launch). Custom tones land in screentones.user.json and re-appear in the picker on every launch.
The 12 built-in tones cover the main families:
| Category | Styles |
|---|---|
| Dots | Light, Medium, Dense |
| Hatch | Shadow, Cross hatch |
| Lines | Speed, Diagonal |
| Texture | Bricks, Noise grain, Mesh grid, Starry sky, Gradient fade |
When a panel is selected and the Tone tool is active, the Inspector dock shows the Screentone editor:
- Density spin box (0.05 to 1.0, step 0.05)
- Angle spin box (0 to 180 degrees, step 5)
- Scale spin box (0.5 to 4.0, step 0.1)
- Color picker
- Reset returns to the style's defaults
- Save as custom... writes a new user-sourced entry
The header shows the current style name and library id, with a • customized marker when any override is active.
The Materials → Add SFX from Library… action (shortcut Ctrl + Shift + S) opens the SFX picker with 8 built-in styles and any custom ones you've saved. Pick a style, click Apply, and a new SFX material is added to the project's materials list, ready to drop onto a panel. Materials → Apply SFX to Armed Material… lets you swap the style of the currently armed SFX material without adding a new one.
Built-in SFX styles ship in library/sfx.built-in.json (copied to %AppData%\MangaStudio\MangaStudio\library\ on first launch). Custom SFX land in sfx.user.json and re-appear in the picker on every launch.
The 8 built-in SFX cover the main families:
| Category | Styles |
|---|---|
| Impact | Impact burst, Boom burst, Shockwave burst |
| Action | Slash burst |
| Elemental | Freeze burst, Electric burst |
| Magic | Sparkle burst |
| Emphasis | Star burst |
When an SFX material is armed, the Inspector dock shows the SFX editor:
- Shape combo (10 shapes: impact burst, slash, boom, sparkle, freeze, electric, star, flame, punch, shockwave)
- Scale spin box (0.25 to 4.0)
- Rotation spin box (-180 to 180 degrees)
- Primary color and Accent color pickers
- Reset returns to the style's defaults
- Save as custom… writes a new user-sourced entry
The header shows the current style name and library id, with a • customized marker when any override is active.
The Cast → Apply Text Style… action (shortcut Ctrl + Shift + Y) opens the text style picker with 8 built-in presets and any custom ones you've saved. Pick a style, click Apply, and the active balloon's text adopts the chosen font, size, weight, italic, color, and letter spacing. Cast → Reset Active Balloon Text clears the overrides; Save Active Balloon Text as Custom… writes a new user-sourced entry.
Built-in text styles ship in library/text-styles.built-in.json (copied to %AppData%\MangaStudio\MangaStudio\library\ on first launch). Custom text styles land in text-styles.user.json and re-appear in the picker on every launch.
The 8 built-in text styles cover the main families:
| Category | Styles |
|---|---|
| Title | Manga title, Chapter heading |
| Speech | Standard speech, Whisper, Shout |
| Narration | Caption |
| SFX | SFX small, SFX large |
When a balloon is active, the Inspector dock shows the Text style editor:
- Font combo (
QFontComboBox— all installed system fonts) - Size spin box (6 to 96 pt)
- Bold and Italic checkboxes
- Color picker
- Letter spacing spin box (-5 to 20 px)
- Reset returns to the style's defaults
- Save as custom… writes a new user-sourced entry
The header shows the current style name and library id, with a • customized marker when any override is active.
The picker previews each template by redrawing the panel layout on a small canvas; the source geometry is a 0..1 normalized rect, so previews stay accurate at any picker size.
Characters are first-class objects with a lock lifecycle.
Concept → Draft → Approved → Locked
- Concept: character exists but cannot appear in any page.
- Draft: user is editing prompts and reference images.
- Approved: structured prompt is populated; character is eligible for page placement and pose bank generation.
- Locked: lock notes recorded; cannot be silently mutated.
Re-approval: Locked → Approved creates a version snapshot, bumps currentVersion, and clears the lock record. Old placed objects are flagged for review, not auto-mutated.
| Action | Shortcut | Description |
|---|---|---|
| New Character… | Ctrl+Shift+N |
Create a blank Concept character |
| New Character from Library… | Ctrl+Shift+C |
Pick from built-in or custom library entries |
| Remove Character | — | Remove from cast (with confirmation) |
| Generate Pose Bank (stub) | — | Stub pose bank (requires Approved/Locked) |
| Open Character Lock Inspector | — | Show character editor in Inspector dock |
When a character is selected in the Cast dock, the Character Lock Inspector shows:
- State badge (colored: gray=Concept, blue=Draft, green=Approved, gold=Locked)
- Version label (v1, v2, …)
- Name and Role text fields
- Concept text, Structured prompt, and Negative prompt text areas
- Reference images list + Add/Remove buttons
- Style anchors list + Add/Remove buttons
- State transition buttons: Move to Draft, Approve, Lock, Reopen, Re-approve
- Generate Pose Bank (stub)
- Revert dropdown + button (from version history)
- Save as Custom… (writes to cast.user.json)
- Hint label showing current-state guidance
Built-in library entries start in Concept state. When added to cast, the user transitions through Draft → Approved → Locked.
Built-in categories: Lead, Rival, Mentor, Comic relief, Villain, Narrator.
Storage layout:
%AppData%\MangaStudio\MangaStudio\library\cast.built-in.json— seeded on first launch%AppData%\MangaStudio\MangaStudio\library\cast.user.json— personal custom entries
| Field | Type | Description |
|---|---|---|
id |
QString | Unique character id |
name |
QString | Display name |
role |
QString | Lead / Rival / Mentor / … |
conceptText |
QString | Free-form concept description |
structuredPromptText |
QString | Structured prompt for AI generation |
negativePromptText |
QString | Negative prompt |
approvalState |
CharacterApprovalState | Concept / Draft / Approved / Locked |
currentVersion |
int | Version number (bumps on re-approval) |
lockRecord |
CharacterLockRecord | Lock metadata (notes, approved-by, linked artifacts) |
referenceImageRefs |
QStringList | Reference image paths or descriptions |
styleAnchors |
QStringList | Style anchor tags |
history |
QList<CharacterVersion> | Version snapshots for re-approval |
source |
QString | "Library" or "User" |
tags |
QString | Comma-separated tags |
Materials are placed into panels as structured scene objects with transforms.
- Drag-and-drop: drag from Materials dock onto a panel in the canvas
- Double-click: double-click in Materials dock to arm, then click on canvas
- Materials are placed at the drop point with default size (0.08 × 0.08 normalized)
Each placed object has:
| Property | Range | Description |
|---|---|---|
| Depth | -100..100 | Layer ordering (higher = on top) |
| Rotation | -360°..360° | Object rotation in degrees |
| Scale | 0.1..10.0 | Object scale factor |
| Opacity | 0.0..1.0 | Object opacity |
These are editable in the Object Editor in the Inspector dock when an object is selected.
File → Import Material (PNG)... (Ctrl+Shift+I) imports an image file into the materials list. The file path is stored in MaterialAsset::filePath.
MaterialCard— library-level metadata (name, category, source)MaterialAsset— asset-level metadata (file path, tags, default scale/rotation/depth)SceneObjectNode— placed object in a panel (with depth, rotation, scale, opacity, materialAssetId)
The Assist Platform manages AI-assisted generation jobs with a local mock broker (no real cloud). It provides the full state machine and revision flow without any external dependencies.
Draft → CreditReservePending → CreditReserved
CreditReserved → DispatchPending → Dispatched → Running
Running → ReconcilePending → Succeeded → Offered
Offered → Accepted | Rejected
Accepted → Reverted
CreditReserved → Cancelled → RefundPending → Refunded
Running → CancelRequested → Cancelled | Offered
ReconcilePending → FailedRetryable | RefundPending → Refunded
FailedRetryable → (retry) → Draft
AssistJobState— 18 states from Draft through RefundedAssistJob— full job record with revisions, credit transactions, retry trackingAssistRevision— provider artifact outputCreditReservation/CreditTransaction— billing trackingAssistGatewayClient— abstract interface for provider adaptersMockAssistBroker— timer-based mock for local testing
| Method | Description |
|---|---|
addAssistJob(job) |
Add a new job to the queue |
removeAssistJob(jobId) |
Remove a job |
requestCreditsForJob(jobId) |
Draft → CreditReserved (via gateway) |
dispatchAssistJob(jobId) |
CreditReserved → Running |
reconcileAssistJob(jobId) |
Running → Offered |
acceptAssistRevision(jobId) |
Offered → Accepted |
rejectAssistRevision(jobId) |
Offered → Rejected |
revertAssistJob(jobId) |
Accepted → Reverted |
cancelAssistJob(jobId) |
Cancel + refund |
retryAssistJob(jobId) |
FailedRetryable → Draft |
cleanupTerminalJobs() |
Remove all terminal-state jobs |
totalCreditsSpent() |
Sum of accepted job costs |
The Story dock provides a workspace for story-level planning:
- Logline — editable story logline text
- Page notes — per-page notes (synced with active page)
- Panel beats — clickable list of panel beats for the current page (click to select panel)
- Composition hint — per-panel AI composition suggestions with "Apply Hint to Panel" button
Each PanelNode now includes:
notes— freeform panel notescompositionHint— AI composition suggestion text
Both fields are serialized/deserialized and round-trip correctly.
ExportPipeline handles page-to-image and page-to-PDF export.
Key types:
ExportFormat— Png or PdfExportProfile— DPI, margins (trim/bleed/safe), page selection, output directoryExportPreflightResult— preflight check results (warnings, errors, stats)
Standard manga dimensions: 127mm × 182mm (tankōbon)
| Method | Description |
|---|---|
runPreflight() |
Check for missing beats, empty balloons, no content |
exportPage(index, profile) |
Export single page to PNG or PDF |
exportAllPages(profile) |
Export all (or selected) pages with progress signals |
renderPage(index, w, h) |
Render page to QImage at given pixel dimensions |
Preflight scans all panels and reports:
- Pages with no content
- Panels with no beat description
- Balloons with empty text
- Panels with no objects/strokes/balloons
SnapshotManifest tracks all project snapshots with rich metadata:
projectId,projectName,version— project identitymaxRetained— pruning limit (default 10)lastPrunedAt— timestamp of last cleanup- Per-snapshot:
id,label,state,description,createdAt,author,pageCount,fileSizeBytes,checksum
projects/untitled-story/
├── blobs/
├── cache/
├── snapshots/ # individual snapshot folders
├── exports/ # export output
├── backups/ # backup copies
└── snapshot-manifest.json