polats Claude Opus 4.8 (1M context) commited on
Commit
7411f15
·
1 Parent(s): 2e524a0

Resize Pixi canvases on tab select (tabs start hidden at 0x0)

Browse files

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files changed (3) hide show
  1. __pycache__/app.cpython-313.pyc +0 -0
  2. app.py +5 -2
  3. web/tiny.js +16 -0
__pycache__/app.cpython-313.pyc CHANGED
Binary files a/__pycache__/app.cpython-313.pyc and b/__pycache__/app.cpython-313.pyc differ
 
app.py CHANGED
@@ -41,15 +41,18 @@ with gr.Blocks(title="Tiny Army") as demo:
41
  "legend is true.* Built on Gradio; sprites + engine reused from "
42
  "auto-battler, rendered with Pixi.")
43
  with gr.Tabs():
44
- with gr.Tab("Battle"):
45
  gr.HTML(f'<div id="battle-stage" style="{STAGE}"></div>')
46
- with gr.Tab("Sprite Animations"):
47
  with gr.Row():
48
  char = gr.Dropdown(CHARACTERS, value=CHARACTERS[0][1], label="Character")
49
  anim = gr.Dropdown(ANIMS, value="idle", label="Animation")
50
  gr.HTML(f'<div id="sprite-stage" style="{STAGE.replace("56vh", "48vh")}"></div>')
51
  char.change(None, [char, anim], None, js="(c,a)=>window.tinyShowSprite(c,a)")
52
  anim.change(None, [char, anim], None, js="(c,a)=>window.tinyShowSprite(c,a)")
 
 
 
53
  with gr.Tab("Barracks"):
54
  with gr.Row():
55
  unit = gr.Textbox("Bram the Warrior", label="Unit")
 
41
  "legend is true.* Built on Gradio; sprites + engine reused from "
42
  "auto-battler, rendered with Pixi.")
43
  with gr.Tabs():
44
+ with gr.Tab("Battle") as battle_tab:
45
  gr.HTML(f'<div id="battle-stage" style="{STAGE}"></div>')
46
+ with gr.Tab("Sprite Animations") as sprite_tab:
47
  with gr.Row():
48
  char = gr.Dropdown(CHARACTERS, value=CHARACTERS[0][1], label="Character")
49
  anim = gr.Dropdown(ANIMS, value="idle", label="Animation")
50
  gr.HTML(f'<div id="sprite-stage" style="{STAGE.replace("56vh", "48vh")}"></div>')
51
  char.change(None, [char, anim], None, js="(c,a)=>window.tinyShowSprite(c,a)")
52
  anim.change(None, [char, anim], None, js="(c,a)=>window.tinyShowSprite(c,a)")
53
+ # Pixi canvases start hidden (0×0); re-measure them when a tab is shown.
54
+ battle_tab.select(None, None, None, js="()=>window.tinyResize&&window.tinyResize()")
55
+ sprite_tab.select(None, None, None, js="()=>window.tinyResize&&window.tinyResize()")
56
  with gr.Tab("Barracks"):
57
  with gr.Row():
58
  unit = gr.Textbox("Bram the Warrior", label="Unit")
web/tiny.js CHANGED
@@ -16,6 +16,19 @@ function whenEl(id, cb) {
16
  o.observe(document.body, { childList: true, subtree: true })
17
  }
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  // ── Sprite Animations tab ────────────────────────────────────────────────────
20
  let charMap = null
21
  async function loadChars() {
@@ -34,6 +47,7 @@ whenEl('sprite-stage', async (el) => {
34
  const app = new PIXI.Application()
35
  await app.init({ background: 0x10151b, resizeTo: el, antialias: false })
36
  el.appendChild(app.canvas)
 
37
  let sprite = null
38
  window.tinyShowSprite = async (slug, anim) => {
39
  const map = await loadChars()
@@ -51,6 +65,7 @@ whenEl('sprite-stage', async (el) => {
51
  sprite.scale.set(sc)
52
  sprite.position.set(app.screen.width / 2, app.screen.height * 0.6)
53
  app.stage.addChild(sprite); sprite.play()
 
54
  }
55
  if (pending) window.tinyShowSprite(...pending)
56
  })
@@ -70,6 +85,7 @@ whenEl('battle-stage', async (el) => {
70
  const app = new PIXI.Application()
71
  await app.init({ background: 0x0b0e12, resizeTo: el, antialias: true })
72
  el.appendChild(app.canvas)
 
73
  const g = new PIXI.Graphics(); app.stage.addChild(g)
74
  let battle, seed = 1, overAt = 0
75
  const fresh = () => { battle = makeTeamBattle({ seed: seed++, players: PLAYERS, enemies: ENEMIES }); overAt = 0 }
 
16
  o.observe(document.body, { childList: true, subtree: true })
17
  }
18
 
19
+ // Pixi apps live in tabs that start hidden (0×0); Gradio fires a tab `select`
20
+ // event wired to window.tinyResize so the canvas re-measures when shown.
21
+ let spriteApp = null, battleApp = null, spriteObj = null
22
+ function centerSprite() {
23
+ if (!spriteApp || !spriteObj) return
24
+ spriteObj.position.set(spriteApp.screen.width / 2, spriteApp.screen.height * 0.6)
25
+ }
26
+ window.tinyResize = () => {
27
+ try { spriteApp && spriteApp.resize() } catch {}
28
+ try { battleApp && battleApp.resize() } catch {}
29
+ centerSprite()
30
+ }
31
+
32
  // ── Sprite Animations tab ────────────────────────────────────────────────────
33
  let charMap = null
34
  async function loadChars() {
 
47
  const app = new PIXI.Application()
48
  await app.init({ background: 0x10151b, resizeTo: el, antialias: false })
49
  el.appendChild(app.canvas)
50
+ spriteApp = app
51
  let sprite = null
52
  window.tinyShowSprite = async (slug, anim) => {
53
  const map = await loadChars()
 
65
  sprite.scale.set(sc)
66
  sprite.position.set(app.screen.width / 2, app.screen.height * 0.6)
67
  app.stage.addChild(sprite); sprite.play()
68
+ spriteObj = sprite
69
  }
70
  if (pending) window.tinyShowSprite(...pending)
71
  })
 
85
  const app = new PIXI.Application()
86
  await app.init({ background: 0x0b0e12, resizeTo: el, antialias: true })
87
  el.appendChild(app.canvas)
88
+ battleApp = app
89
  const g = new PIXI.Graphics(); app.stage.addChild(g)
90
  let battle, seed = 1, overAt = 0
91
  const fresh = () => { battle = makeTeamBattle({ seed: seed++, players: PLAYERS, enemies: ENEMIES }); overAt = 0 }