LeafCat79 commited on
Commit
4a2fd58
·
verified ·
1 Parent(s): 9df72d7

Redesign Space interface

Browse files
Files changed (2) hide show
  1. README.md +1 -1
  2. app.py +275 -105
README.md CHANGED
@@ -1,7 +1,7 @@
1
  ---
2
  title: Image Generator for HTML Games
3
  emoji: 🎮
4
- colorFrom: blue
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 6.14.0
 
1
  ---
2
  title: Image Generator for HTML Games
3
  emoji: 🎮
4
+ colorFrom: indigo
5
  colorTo: green
6
  sdk: gradio
7
  sdk_version: 6.14.0
app.py CHANGED
@@ -2385,84 +2385,253 @@ def check_hf_token() -> str:
2385
  return f"HF_TOKEN check failed: {short_error(exc)}"
2386
 
2387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2388
  with gr.Blocks(title="Image Generator for HTML Games") as demo:
2389
- gr.Markdown(
2390
- "# Image Generator for HTML Games\n"
2391
- "Generate game assets and embed them only when the submitted game exposes deterministic "
2392
- "`GAME_ASSETS.<role>` hooks or exact role filenames such as `sprite_player.png`. "
2393
- "Primitive canvas geometry is preserved and never silently guessed."
2394
- )
2395
- gr.Markdown(model_configuration_summary())
 
 
 
 
 
 
2396
 
2397
- generation_state = gr.State({})
2398
 
2399
- with gr.Row():
2400
- with gr.Column(scale=1):
2401
- roles = gr.Textbox(
2402
- label="Image roles to generate",
2403
- lines=8,
2404
- placeholder=ROLE_PLACEHOLDER,
2405
- value=DEFAULT_ROLES,
2406
- info="One per line: role: image description. Example: player: blue robot hero",
2407
- )
2408
- game_type = gr.Dropdown(
2409
- label="Game type",
2410
- choices=[
2411
- "Top-down action / RPG",
2412
- "Platformer / side-scroller",
2413
- "Isometric strategy / simulation",
2414
- "First-person",
2415
- "Card / board game",
2416
- "Other / custom",
2417
- ],
2418
- value="Top-down action / RPG",
2419
- )
2420
- perspective = gr.Dropdown(
2421
- label="Camera perspective",
2422
- choices=[
2423
- "Top-down / overhead",
2424
- "Side view",
2425
- "Isometric 3/4 view",
2426
- "First-person",
2427
- "Front-facing",
2428
- "Auto-detect from code",
2429
- ],
2430
- value="Top-down / overhead",
2431
- )
2432
- theme = gr.Textbox(
2433
- label="Theme and shared visual style",
2434
- lines=2,
2435
- placeholder="Describe the setting, palette, medium, mood, and constraints.",
2436
- )
2437
- generate_btn = gr.Button("Generate Images + Embed Game", variant="primary")
2438
- status = gr.Markdown("Ready.")
2439
- token_btn = gr.Button("Check HF Token")
2440
- token_status = gr.Markdown("")
2441
- gallery = gr.Gallery(label="Generated assets", columns=2, height=300)
2442
- selected_role = gr.Dropdown(
2443
- label="Asset to regenerate",
2444
- choices=[],
2445
- interactive=True,
2446
- )
2447
- regenerate_btn = gr.Button("Regenerate selected asset")
2448
- approved_roles = gr.CheckboxGroup(
2449
- label="Visually approved assets",
2450
- choices=[],
2451
- info="Approve assets only after checking subject, perspective, style, and transparency.",
2452
- )
 
 
 
2453
 
2454
- with gr.Column(scale=2):
2455
- html_input = gr.Textbox(
2456
- label="Original HTML game code",
2457
- lines=18,
2458
- placeholder="Paste your full HTML game code here.",
2459
- value=STARTER_HTML,
2460
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2461
  output_code = gr.Code(
2462
  label="Rewritten HTML with embedded images",
2463
  language="html",
2464
  lines=18,
2465
  )
 
 
 
 
 
2466
  prompt_preview = gr.Textbox(
2467
  label="Interpreted image prompts",
2468
  lines=8,
@@ -2479,42 +2648,43 @@ with gr.Blocks(title="Image Generator for HTML Games") as demo:
2479
  interactive=False,
2480
  )
2481
 
2482
- gr.Markdown("## Game preview")
2483
- preview = gr.HTML("")
2484
-
2485
- generate_btn.click(
2486
- fn=generate_images_and_game,
2487
- inputs=[html_input, roles, game_type, perspective, theme],
2488
- outputs=[
2489
- output_code,
2490
- status,
2491
- gallery,
2492
- prompt_preview,
2493
- model_report,
2494
- quality_report,
2495
- preview,
2496
- generation_state,
2497
- selected_role,
2498
- approved_roles,
2499
- ],
2500
- )
2501
- regenerate_btn.click(
2502
- fn=regenerate_selected_asset,
2503
- inputs=[generation_state, selected_role, approved_roles],
2504
- outputs=[
2505
- output_code,
2506
- status,
2507
- gallery,
2508
- prompt_preview,
2509
- model_report,
2510
- quality_report,
2511
- preview,
2512
- generation_state,
2513
- approved_roles,
2514
- ],
2515
- )
2516
- token_btn.click(fn=check_hf_token, inputs=None, outputs=token_status)
 
2517
 
2518
 
2519
  if __name__ == "__main__":
2520
- demo.launch()
 
2385
  return f"HF_TOKEN check failed: {short_error(exc)}"
2386
 
2387
 
2388
+ APP_CSS = """
2389
+ :root {
2390
+ --canvas: #070a12;
2391
+ --surface: #0d1320;
2392
+ --surface-raised: #111a2b;
2393
+ --border: #25324a;
2394
+ --border-bright: #344766;
2395
+ --text: #f4f7fb;
2396
+ --muted: #9aa8bd;
2397
+ --accent: #72f2cf;
2398
+ --accent-strong: #42dbb5;
2399
+ --violet: #a89bff;
2400
+ }
2401
+
2402
+ .gradio-container {
2403
+ background:
2404
+ radial-gradient(circle at 8% 0%, rgba(82, 65, 170, .22), transparent 31rem),
2405
+ radial-gradient(circle at 92% 12%, rgba(26, 173, 145, .12), transparent 26rem),
2406
+ var(--canvas) !important;
2407
+ color: var(--text) !important;
2408
+ max-width: none !important;
2409
+ padding: 0 !important;
2410
+ }
2411
+
2412
+ .app-shell { max-width: 1440px; margin: 0 auto; padding: 28px 28px 64px; }
2413
+
2414
+ .hero {
2415
+ position: relative;
2416
+ overflow: hidden;
2417
+ padding: 34px 38px;
2418
+ margin-bottom: 22px;
2419
+ border: 1px solid var(--border-bright);
2420
+ border-radius: 24px;
2421
+ background: linear-gradient(135deg, rgba(20, 30, 51, .96), rgba(11, 17, 29, .95));
2422
+ box-shadow: 0 22px 60px rgba(0, 0, 0, .25);
2423
+ }
2424
+
2425
+ .hero::after {
2426
+ content: "";
2427
+ position: absolute;
2428
+ right: -70px;
2429
+ top: -100px;
2430
+ width: 320px;
2431
+ height: 320px;
2432
+ border-radius: 50%;
2433
+ background: radial-gradient(circle, rgba(114, 242, 207, .18), transparent 66%);
2434
+ }
2435
+
2436
+ .eyebrow {
2437
+ color: var(--accent);
2438
+ font-size: 12px;
2439
+ font-weight: 800;
2440
+ letter-spacing: .16em;
2441
+ text-transform: uppercase;
2442
+ }
2443
+
2444
+ .hero h1 {
2445
+ max-width: 820px;
2446
+ margin: 10px 0 12px;
2447
+ color: #fff;
2448
+ font-size: clamp(34px, 5vw, 62px);
2449
+ line-height: .98;
2450
+ letter-spacing: -.045em;
2451
+ }
2452
+
2453
+ .hero p { max-width: 760px; margin: 0; color: #b9c5d7; font-size: 17px; line-height: 1.6; }
2454
+ .hero-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
2455
+ .hero-chips span {
2456
+ padding: 7px 11px;
2457
+ border: 1px solid #30415d;
2458
+ border-radius: 999px;
2459
+ background: rgba(8, 13, 23, .65);
2460
+ color: #cfdaea;
2461
+ font-size: 12px;
2462
+ font-weight: 700;
2463
+ }
2464
+
2465
+ .step-heading { margin: 28px 0 12px; }
2466
+ .step-heading span { color: var(--accent); font: 800 12px/1 sans-serif; letter-spacing: .14em; text-transform: uppercase; }
2467
+ .step-heading h2 { margin: 7px 0 3px; color: var(--text); font-size: 24px; letter-spacing: -.025em; }
2468
+ .step-heading p { margin: 0; color: var(--muted); font-size: 14px; }
2469
+
2470
+ .panel {
2471
+ border: 1px solid var(--border) !important;
2472
+ border-radius: 18px !important;
2473
+ background: linear-gradient(180deg, rgba(17, 26, 43, .92), rgba(12, 18, 31, .96)) !important;
2474
+ box-shadow: 0 12px 36px rgba(0, 0, 0, .18);
2475
+ padding: 18px !important;
2476
+ }
2477
+
2478
+ .gradio-container label, .gradio-container .label-wrap { color: #dce5f2 !important; font-weight: 700 !important; }
2479
+ .gradio-container .info { color: var(--muted) !important; }
2480
+ .gradio-container textarea,
2481
+ .gradio-container input,
2482
+ .gradio-container select,
2483
+ .gradio-container [role="listbox"] {
2484
+ color: var(--text) !important;
2485
+ background: #090f1b !important;
2486
+ border-color: var(--border) !important;
2487
+ }
2488
+ .gradio-container textarea:focus,
2489
+ .gradio-container input:focus { border-color: var(--accent-strong) !important; box-shadow: 0 0 0 2px rgba(66, 219, 181, .12) !important; }
2490
+
2491
+ #generate-button {
2492
+ min-height: 52px;
2493
+ border: 0 !important;
2494
+ border-radius: 12px !important;
2495
+ background: linear-gradient(135deg, var(--accent), #91f6a9) !important;
2496
+ color: #06110e !important;
2497
+ font-weight: 850 !important;
2498
+ box-shadow: 0 10px 28px rgba(66, 219, 181, .18);
2499
+ }
2500
+ #generate-button:hover { transform: translateY(-1px); filter: brightness(1.05); }
2501
+ .secondary-action { border-color: var(--border-bright) !important; background: #151f31 !important; color: #e7eef8 !important; }
2502
+ .status-card { margin-top: 10px; padding: 12px 14px; border-left: 3px solid var(--accent); border-radius: 8px; background: rgba(114, 242, 207, .06); }
2503
+ .status-card p { margin: 0; color: #c9d6e6; }
2504
+ .gallery-panel .grid-wrap { background: transparent !important; }
2505
+ .preview-panel iframe { border: 1px solid var(--border-bright) !important; border-radius: 12px !important; }
2506
+ .diagnostics { margin-top: 20px; border-color: var(--border) !important; background: var(--surface) !important; }
2507
+ .pipeline-note { color: var(--muted); font-size: 13px; }
2508
+ .footer-note { margin-top: 28px; color: #718096; text-align: center; font-size: 12px; }
2509
+
2510
+ @media (max-width: 780px) {
2511
+ .app-shell { padding: 14px 14px 42px; }
2512
+ .hero { padding: 26px 22px; border-radius: 18px; }
2513
+ .hero h1 { font-size: 38px; }
2514
+ .hero p { font-size: 15px; }
2515
+ .panel { padding: 13px !important; }
2516
+ }
2517
+ """
2518
+
2519
+
2520
  with gr.Blocks(title="Image Generator for HTML Games") as demo:
2521
+ with gr.Column(elem_classes=["app-shell"]):
2522
+ gr.HTML(
2523
+ """
2524
+ <header class="hero">
2525
+ <div class="eyebrow">Game asset studio</div>
2526
+ <h1>Turn your game code into a visual world.</h1>
2527
+ <p>Describe the art direction, generate camera-aware assets, and embed them into deterministic image hooks—without rewriting your game logic.</p>
2528
+ <div class="hero-chips">
2529
+ <span>Camera-aware prompts</span><span>Game-ready PNGs</span><span>Safe code integration</span>
2530
+ </div>
2531
+ </header>
2532
+ """
2533
+ )
2534
 
2535
+ generation_state = gr.State({})
2536
 
2537
+ gr.HTML(
2538
+ '<div class="step-heading"><span>Step 01</span><h2>Set up your generation</h2>'
2539
+ '<p>Paste the game first, then define the assets and shared art direction.</p></div>'
2540
+ )
2541
+ with gr.Row(equal_height=False):
2542
+ with gr.Column(scale=3, elem_classes=["panel"]):
2543
+ html_input = gr.Textbox(
2544
+ label="Original HTML game code",
2545
+ lines=22,
2546
+ placeholder="Paste your full HTML game code here.",
2547
+ value=STARTER_HTML,
2548
+ info="Use GAME_ASSETS.<role> or sprite_<role>.png for deterministic embedding.",
2549
+ )
2550
+ with gr.Column(scale=2, elem_classes=["panel"]):
2551
+ roles = gr.Textbox(
2552
+ label="Assets to create",
2553
+ lines=8,
2554
+ placeholder=ROLE_PLACEHOLDER,
2555
+ value=DEFAULT_ROLES,
2556
+ info="One per line: role: image description",
2557
+ )
2558
+ with gr.Row():
2559
+ game_type = gr.Dropdown(
2560
+ label="Game type",
2561
+ choices=[
2562
+ "Top-down action / RPG",
2563
+ "Platformer / side-scroller",
2564
+ "Isometric strategy / simulation",
2565
+ "First-person",
2566
+ "Card / board game",
2567
+ "Other / custom",
2568
+ ],
2569
+ value="Top-down action / RPG",
2570
+ )
2571
+ perspective = gr.Dropdown(
2572
+ label="Camera perspective",
2573
+ choices=[
2574
+ "Top-down / overhead",
2575
+ "Side view",
2576
+ "Isometric 3/4 view",
2577
+ "First-person",
2578
+ "Front-facing",
2579
+ "Auto-detect from code",
2580
+ ],
2581
+ value="Top-down / overhead",
2582
+ )
2583
+ theme = gr.Textbox(
2584
+ label="Theme and shared visual style",
2585
+ lines=3,
2586
+ placeholder="Example: moonlit forest, indigo and moss palette, crisp pixel art, readable silhouettes",
2587
+ )
2588
+ generate_btn = gr.Button(
2589
+ "Generate assets + build game",
2590
+ variant="primary",
2591
+ elem_id="generate-button",
2592
+ )
2593
+ status = gr.Markdown("Ready for your game code.", elem_classes=["status-card"])
2594
 
2595
+ gr.HTML(
2596
+ '<div class="step-heading"><span>Step 02</span><h2>Review generated assets</h2>'
2597
+ '<p>Check subject, perspective, style, and transparency before approving an asset.</p></div>'
2598
+ )
2599
+ with gr.Row(equal_height=False):
2600
+ with gr.Column(scale=3, elem_classes=["panel", "gallery-panel"]):
2601
+ gallery = gr.Gallery(label="Generated assets", columns=2, height=420)
2602
+ with gr.Column(scale=2, elem_classes=["panel"]):
2603
+ selected_role = gr.Dropdown(
2604
+ label="Asset to regenerate",
2605
+ choices=[],
2606
+ interactive=True,
2607
+ )
2608
+ regenerate_btn = gr.Button(
2609
+ "Regenerate selected asset",
2610
+ elem_classes=["secondary-action"],
2611
+ )
2612
+ approved_roles = gr.CheckboxGroup(
2613
+ label="Visually approved assets",
2614
+ choices=[],
2615
+ info="Approval is a manual review marker; automated checks cannot prove artistic correctness.",
2616
+ )
2617
+
2618
+ gr.HTML(
2619
+ '<div class="step-heading"><span>Step 03</span><h2>Play and export</h2>'
2620
+ '<p>Test the integrated game, then copy the rewritten HTML when it looks right.</p></div>'
2621
+ )
2622
+ with gr.Column(elem_classes=["panel", "preview-panel"]):
2623
+ preview = gr.HTML("")
2624
+ with gr.Column(elem_classes=["panel"]):
2625
  output_code = gr.Code(
2626
  label="Rewritten HTML with embedded images",
2627
  language="html",
2628
  lines=18,
2629
  )
2630
+
2631
+ with gr.Accordion("Generation details and diagnostics", open=False, elem_classes=["diagnostics"]):
2632
+ gr.Markdown(model_configuration_summary(), elem_classes=["pipeline-note"])
2633
+ token_btn = gr.Button("Check HF token", elem_classes=["secondary-action"])
2634
+ token_status = gr.Markdown("")
2635
  prompt_preview = gr.Textbox(
2636
  label="Interpreted image prompts",
2637
  lines=8,
 
2648
  interactive=False,
2649
  )
2650
 
2651
+ gr.HTML(
2652
+ '<div class="footer-note">Deterministic hooks only · Game logic remains untouched · Human visual review required</div>'
2653
+ )
2654
+
2655
+ generate_btn.click(
2656
+ fn=generate_images_and_game,
2657
+ inputs=[html_input, roles, game_type, perspective, theme],
2658
+ outputs=[
2659
+ output_code,
2660
+ status,
2661
+ gallery,
2662
+ prompt_preview,
2663
+ model_report,
2664
+ quality_report,
2665
+ preview,
2666
+ generation_state,
2667
+ selected_role,
2668
+ approved_roles,
2669
+ ],
2670
+ )
2671
+ regenerate_btn.click(
2672
+ fn=regenerate_selected_asset,
2673
+ inputs=[generation_state, selected_role, approved_roles],
2674
+ outputs=[
2675
+ output_code,
2676
+ status,
2677
+ gallery,
2678
+ prompt_preview,
2679
+ model_report,
2680
+ quality_report,
2681
+ preview,
2682
+ generation_state,
2683
+ approved_roles,
2684
+ ],
2685
+ )
2686
+ token_btn.click(fn=check_hf_token, inputs=None, outputs=token_status)
2687
 
2688
 
2689
  if __name__ == "__main__":
2690
+ demo.launch(css=APP_CSS)