clay implemented

This commit is contained in:
echo 2026-05-22 12:35:38 +02:00
parent 2160449f43
commit 1d8178f5d6
5 changed files with 501 additions and 45 deletions

1
odin/gui_diagnostics.txt Normal file
View File

@ -0,0 +1 @@
screen=Story workflow=Story_Input next=generate script local dirty=no autosave=yes(20s) content=pages:0,panels:0,layouts:0,chars:0 paths=P:yes,E:yes project=./gui_project.comic.json export=./gui_export.pdf log=0,newest uptime=38.2s

View File

@ -14,26 +14,510 @@
"target_audience": "general", "target_audience": "general",
"art_style": "manga", "art_style": "manga",
"script": { "script": {
"title": "", "title": "Midnight Rush",
"synopsis": "", "synopsis": "Generated comic synopsis",
"characters": [ "characters": [
], ],
"pages": [ "pages": [
{
"page_number": 1,
"layout_type": 0,
"panels": [
{
"panel_id": "panel_001_001",
"panel_number": 1,
"shot_type": 2,
"description": "Wide shot of New York City skyline at night, neon lights reflecting on wet streets. Two cars, a red Ferrari and a black Lamborghini, are side by side at a traffic light on a multi-lane avenue.",
"characters_present": [
],
"dialogue": [
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_001_002",
"panel_number": 2,
"shot_type": 2,
"description": "Close-up on the Ferrari driver, a young man in a leather jacket with a determined expression. His hand grips the gear shift.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "This is it.",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_001_003",
"panel_number": 3,
"shot_type": 2,
"description": "Close-up on the Lamborghini driver, a woman with sunglasses and a smirk. She revs the engine.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "Ready to lose, pretty boy?",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_001_004",
"panel_number": 4,
"shot_type": 2,
"description": "Traffic light turns green. Both cars accelerate, tires screeching, smoke billowing. Speed lines emphasize motion.",
"characters_present": [
],
"dialogue": [
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_001_005",
"panel_number": 5,
"shot_type": 2,
"description": "Medium shot of the cars weaving through traffic. The Ferrari barely misses a taxi, sparks flying from the curb.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "Whoa!",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_001_006",
"panel_number": 6,
"shot_type": 2,
"description": "The Lamborghini cuts in front of a bus, horn blaring. The driver laughs.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "Ha! Too slow!",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
}
]
},
{
"page_number": 2,
"layout_type": 0,
"panels": [
{
"panel_id": "panel_002_001",
"panel_number": 1,
"shot_type": 2,
"description": "Both cars enter a sharp curve. The Ferrari drifts close to a parked car, side mirror clipping it off. Glass shatters.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "Sorry!",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_002_002",
"panel_number": 2,
"shot_type": 2,
"description": "The Lamborghini takes the inside line, gaining a car length. The Ferrari driver grits his teeth.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "See ya!",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_002_003",
"panel_number": 3,
"shot_type": 2,
"description": "Straightaway ahead. The Ferrari spots a shortcut through an alley. He swerves into it.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "Not yet!",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_002_004",
"panel_number": 4,
"shot_type": 2,
"description": "The alley is narrow, trash cans flying as the Ferrari speeds through. A cat jumps out of the way.",
"characters_present": [
],
"dialogue": [
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_002_005",
"panel_number": 5,
"shot_type": 2,
"description": "The Ferrari exits the alley just ahead of the Lamborghini. Both cars race toward the finish line (a bridge entrance).",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "What?!",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
},
{
"panel_id": "panel_002_006",
"panel_number": 6,
"shot_type": 2,
"description": "The Ferrari crosses the bridge first, winning. The drivers slow down, windows rolled down. The woman nods in respect.",
"characters_present": [
],
"dialogue": [
{
"speaker_id": "",
"text": "Nice move.",
"bubble_type": 0,
"emotion": 4
},
{
"speaker_id": "",
"text": "You're not bad yourself.",
"bubble_type": 0,
"emotion": 4
}
],
"caption": "",
"sound_effects": [
],
"transition_from_previous": 0
}
]
}
] ]
}, },
"characters": [ "characters": [
], ],
"panel_images": { "panel_images": {
"panel_001_003": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_003_panel_001_003.png",
"width": 1024,
"height": 1024,
"seed": 3,
"prompt": "local panel 3"
},
"panel_002_001": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_007_panel_002_001.png",
"width": 1024,
"height": 1024,
"seed": 7,
"prompt": "local panel 7"
},
"panel_002_006": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_012_panel_002_006.png",
"width": 1024,
"height": 1024,
"seed": 12,
"prompt": "local panel 12"
},
"panel_001_004": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_004_panel_001_004.png",
"width": 1024,
"height": 1024,
"seed": 4,
"prompt": "local panel 4"
},
"panel_002_005": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_011_panel_002_005.png",
"width": 1024,
"height": 1024,
"seed": 11,
"prompt": "local panel 11"
},
"panel_001_005": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_005_panel_001_005.png",
"width": 1024,
"height": 1024,
"seed": 5,
"prompt": "local panel 5"
},
"panel_002_004": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_010_panel_002_004.png",
"width": 1024,
"height": 1024,
"seed": 10,
"prompt": "local panel 10"
},
"panel_001_006": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_006_panel_001_006.png",
"width": 1024,
"height": 1024,
"seed": 6,
"prompt": "local panel 6"
},
"panel_001_001": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_001_panel_001_001.png",
"width": 1024,
"height": 1024,
"seed": 1,
"prompt": "local panel 1"
},
"panel_002_003": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_009_panel_002_003.png",
"width": 1024,
"height": 1024,
"seed": 9,
"prompt": "local panel 9"
},
"panel_001_002": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_002_panel_001_002.png",
"width": 1024,
"height": 1024,
"seed": 2,
"prompt": "local panel 2"
},
"panel_002_002": {
"url": "file:///tmp/comic-gui-local-panels-0387429411/panel_008_panel_002_002.png",
"width": 1024,
"height": 1024,
"seed": 8,
"prompt": "local panel 8"
}
}, },
"panel_errors": { "panel_errors": {
}, },
"page_layouts": [ "page_layouts": [
{
"page_number": 1,
"pattern_id": "grid-2x2",
"panels": [
{
"panel_id": "panel_001_001",
"panel_number": 1,
"layout_cell": {
"x": 0.02000000,
"y": 0.02000000,
"w": 0.47000000,
"h": 0.47000000
}
},
{
"panel_id": "panel_001_002",
"panel_number": 2,
"layout_cell": {
"x": 0.50999999,
"y": 0.02000000,
"w": 0.47000000,
"h": 0.47000000
}
},
{
"panel_id": "panel_001_003",
"panel_number": 3,
"layout_cell": {
"x": 0.02000000,
"y": 0.50999999,
"w": 0.47000000,
"h": 0.47000000
}
},
{
"panel_id": "panel_001_004",
"panel_number": 4,
"layout_cell": {
"x": 0.50999999,
"y": 0.50999999,
"w": 0.47000000,
"h": 0.47000000
}
}
],
"width": 2480,
"height": 3508
},
{
"page_number": 2,
"pattern_id": "dialogue-heavy",
"panels": [
{
"panel_id": "panel_001_005",
"panel_number": 5,
"layout_cell": {
"x": 0.02000000,
"y": 0.02000000,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_001_006",
"panel_number": 6,
"layout_cell": {
"x": 0.50999999,
"y": 0.02000000,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_002_001",
"panel_number": 1,
"layout_cell": {
"x": 0.02000000,
"y": 0.25999999,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_002_002",
"panel_number": 2,
"layout_cell": {
"x": 0.50999999,
"y": 0.25999999,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_002_003",
"panel_number": 3,
"layout_cell": {
"x": 0.02000000,
"y": 0.50000000,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_002_004",
"panel_number": 4,
"layout_cell": {
"x": 0.50999999,
"y": 0.50000000,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_002_005",
"panel_number": 5,
"layout_cell": {
"x": 0.02000000,
"y": 0.74000001,
"w": 0.47000000,
"h": 0.22000000
}
},
{
"panel_id": "panel_002_006",
"panel_number": 6,
"layout_cell": {
"x": 0.50999999,
"y": 0.74000001,
"w": 0.47000000,
"h": 0.22000000
}
}
],
"width": 2480,
"height": 3508
}
], ],
"speech_bubbles": { "speech_bubbles": {
@ -42,7 +526,7 @@
"page_size": 0, "page_size": 0,
"color_profile": 0, "color_profile": 0,
"workflow": { "workflow": {
"current_step": 0, "current_step": 5,
"completed_steps": [ "completed_steps": [
], ],

Binary file not shown.

View File

@ -6,7 +6,6 @@ import "core:fmt"
import "core:math" import "core:math"
import "core:strings" import "core:strings"
import rl "vendor:raylib" import rl "vendor:raylib"
import "../shared"
// --- Font IDs (indices into raylib_fonts) --- // --- Font IDs (indices into raylib_fonts) ---
CLAY_FONT_BODY :: u16(0) CLAY_FONT_BODY :: u16(0)

View File

@ -301,7 +301,6 @@ run_gui_app :: proc(state: ^core.Comic_State) -> shared.App_Error {
// Clay Layout Declaration // Clay Layout Declaration
main_w := shared.compute_main_width(screen_w) main_w := shared.compute_main_width(screen_w)
status_w := (main_w - 2) / 2 status_w := (main_w - 2) / 2
lower_y := shared.compute_lower_y(screen_h)
clay.BeginLayout() clay.BeginLayout()
@ -317,11 +316,11 @@ run_gui_app :: proc(state: ^core.Comic_State) -> shared.App_Error {
if clay.UI(clay.ID("MainArea"))({ if clay.UI(clay.ID("MainArea"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}, layoutDirection = .TopToBottom}, layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}, layoutDirection = .TopToBottom},
}) { }) {
declare_topbar(&app, main_w, screen_w) declare_topbar(&app)
declare_project_setup(&app, main_w) declare_project_setup(&app)
declare_actions_row(&app, can_generate_panels, can_layout, can_export, project_path_ok, export_path_ok, has_deepseek_key) declare_actions_row(&app, can_generate_panels, can_layout, can_export, project_path_ok, export_path_ok, has_deepseek_key)
declare_status_card(&app, status_w, lower_y) declare_status_card(&app)
declare_detail_area(&app, main_w, status_w, screen_w, lower_y, lower_y - 140, compact_mode) declare_detail_area(&app, status_w)
} }
} }
@ -399,7 +398,7 @@ declare_sidebar :: proc(app: ^GUI_App_State, screen_h: i32) {
} }
// Topbar Declaration // Topbar Declaration
declare_topbar :: proc(app: ^GUI_App_State, main_w: i32, screen_w: i32) { declare_topbar :: proc(app: ^GUI_App_State) {
if clay.UI(clay.ID("Topbar"))({ if clay.UI(clay.ID("Topbar"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFit({min = 72, max = 72})}, padding = {top = 12, right = 20, bottom = 12, left = 20}, childGap = 16, childAlignment = {y = .Center}}, layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFit({min = 72, max = 72})}, padding = {top = 12, right = 20, bottom = 12, left = 20}, childGap = 16, childAlignment = {y = .Center}},
backgroundColor = CLAY_BG_TOPBAR, backgroundColor = CLAY_BG_TOPBAR,
@ -468,7 +467,7 @@ declare_topbar :: proc(app: ^GUI_App_State, main_w: i32, screen_w: i32) {
} }
// Project Setup Declaration // Project Setup Declaration
declare_project_setup :: proc(app: ^GUI_App_State, main_w: i32) { declare_project_setup :: proc(app: ^GUI_App_State) {
if clay.UI(clay.ID("ProjectSetup"))(clay_card_style()) { if clay.UI(clay.ID("ProjectSetup"))(clay_card_style()) {
clay_title_text("Project Setup") clay_title_text("Project Setup")
// Story Idea // Story Idea
@ -577,7 +576,7 @@ declare_actions_row :: proc(app: ^GUI_App_State, can_gen_panels, can_layout, can
} }
// Status Card // Status Card
declare_status_card :: proc(app: ^GUI_App_State, status_w: i32, lower_y: i32) { declare_status_card :: proc(app: ^GUI_App_State) {
ready_count, total_count := ready_stage_count(app.controller) ready_count, total_count := ready_stage_count(app.controller)
progress := f32(0) progress := f32(0)
if total_count > 0 { progress = f32(ready_count) / f32(total_count) } if total_count > 0 { progress = f32(ready_count) / f32(total_count) }
@ -624,7 +623,7 @@ declare_status_card :: proc(app: ^GUI_App_State, status_w: i32, lower_y: i32) {
} }
// Detail Area // Detail Area
declare_detail_area :: proc(app: ^GUI_App_State, main_w, status_w, screen_w, lower_y, summary_y: i32, compact_mode: bool) { declare_detail_area :: proc(app: ^GUI_App_State, status_w: i32) {
if clay.UI(clay.ID("DetailArea"))({ if clay.UI(clay.ID("DetailArea"))({
layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}, layoutDirection = .LeftToRight, childGap = 2}, layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}, layoutDirection = .LeftToRight, childGap = 2},
}) { }) {
@ -635,35 +634,6 @@ declare_detail_area :: proc(app: ^GUI_App_State, main_w, status_w, screen_w, low
cornerRadius = clay.CornerRadiusAll(CLAY_RADIUS_MD), cornerRadius = clay.CornerRadiusAll(CLAY_RADIUS_MD),
}) { }) {
declare_screen_summary(app) declare_screen_summary(app)
screen := app.controller.active_screen
if screen == .Script || screen == .Layout || screen == .Panels || screen == .Bubbles {
show_txt := "Show:Top"
sort_txt := "Sort:Asc"
if screen == .Script {
if app.summary_opts.script_show_all { show_txt = "Show:All" }
if app.summary_opts.script_desc { sort_txt = "Sort:Desc" }
} else {
if app.summary_opts.layout_show_all { show_txt = "Show:All" }
if app.summary_opts.layout_desc { sort_txt = "Sort:Desc" }
}
if clay.UI(clay.ID("SummaryBtnRow"))({layout = clay_row_layout()}) {
declare_button_small("btn_summary_show", show_txt)
declare_button_small("btn_summary_sort", sort_txt)
if screen == .Script {
declare_button_small("btn_summary_prev", "< Pg")
declare_button_small("btn_summary_next", "Pg >")
} else if screen == .Panels {
declare_button_small("btn_summary_prev", "< Pn")
declare_button_small("btn_summary_next", "Pn >")
} else if screen == .Layout {
declare_button_small("btn_summary_prev", "< Ly")
declare_button_small("btn_summary_next", "Ly >")
} else if screen == .Bubbles {
declare_button_small("btn_summary_prev", "< Pn")
declare_button_small("btn_summary_next", "Pn >")
}
}
}
} }
// Detail/log panel (right) detail panels or action log // Detail/log panel (right) detail panels or action log
@ -1483,8 +1453,10 @@ declare_layout_detail :: proc(app: ^GUI_App_State) {
}) { }) {
for i in 0..<len(layout_val.panels) { for i in 0..<len(layout_val.panels) {
cell := layout_val.panels[i].layout_cell cell := layout_val.panels[i].layout_cell
w_pct := f32(cell.w * 100); if w_pct > 100 { w_pct = 100 } else if w_pct < 0 { w_pct = 0 }
h_pct := f32(cell.h * 100); if h_pct > 100 { h_pct = 100 } else if h_pct < 0 { h_pct = 0 }
if clay.UI(clay.ID(fmt.tprintf("wire_cell_%d", i)))({ if clay.UI(clay.ID(fmt.tprintf("wire_cell_%d", i)))({
layout = {sizing = {width = clay.SizingPercent(f32(cell.w * 100)), height = clay.SizingPercent(f32(cell.h * 100))}, padding = {top = 2, left = 2, right = 2, bottom = 2}}, layout = {sizing = {width = clay.SizingPercent(w_pct), height = clay.SizingPercent(h_pct)}, padding = {top = 2, left = 2, right = 2, bottom = 2}},
backgroundColor = CLAY_ACCENT_SURFACE, backgroundColor = CLAY_ACCENT_SURFACE,
cornerRadius = clay.CornerRadiusAll(2), cornerRadius = clay.CornerRadiusAll(2),
border = {color = CLAY_ACCENT_MUTED, width = clay.BorderOutside(1)}, border = {color = CLAY_ACCENT_MUTED, width = clay.BorderOutside(1)},