Pabloler21 commited on
Commit
41c845f
·
1 Parent(s): 1337168

fix(game): give stage real height, center dialogue, brighten scene

Browse files
Files changed (4) hide show
  1. app.py +2 -1
  2. render.py +5 -5
  3. styles.css +65 -38
  4. tests/test_render.py +6 -6
app.py CHANGED
@@ -1089,7 +1089,8 @@ with gr.Blocks(title="Hollow") as demo:
1089
  label="", show_label=False, height=210, buttons=[],
1090
  autoscroll=True,
1091
  )
1092
- bond_panel = gr.HTML(value=_render_bond(20, "Hollow"))
 
1093
  with gr.Row(elem_id="game-inputrow"):
1094
  msg_input = gr.Textbox(
1095
  placeholder="tell it something you remember...",
 
1089
  label="", show_label=False, height=210, buttons=[],
1090
  autoscroll=True,
1091
  )
1092
+ bond_panel = gr.HTML(value=_render_bond(20, "Hollow"),
1093
+ elem_classes="bond-panel")
1094
  with gr.Row(elem_id="game-inputrow"):
1095
  msg_input = gr.Textbox(
1096
  placeholder="tell it something you remember...",
render.py CHANGED
@@ -91,17 +91,17 @@ def render_entity(affinity: int, mode: str = "idle", seq: int = 0,
91
  t = min(a, 45) / 45 # fully materialized by bond 45
92
  # veil the SHARP child in shadow instead of blurring it (blur reads as
93
  # a broken/loading image): dark and fog-shrouded at low bond, emerging
94
- brightness = round(0.62 + 0.38 * t, 2)
95
- opacity = round(0.78 + 0.22 * t, 2)
96
  almost_on = a >= 76
97
  flash_key = f"flash-{seq % 2}"
98
  tone_class = _tone_class(tone)
99
 
100
- # a faint inner/outer glow so the silhouette separates from the fog
101
  look = (
102
  f"filter:brightness({brightness}) "
103
- f"drop-shadow(0 0 18px rgba(130,110,160,{round(0.18 + 0.22*t,2)})) "
104
- f"drop-shadow(0 0 42px rgba(90,70,120,{round(0.10 + 0.15*t,2)}));"
105
  f"opacity:{opacity};"
106
  )
107
 
 
91
  t = min(a, 45) / 45 # fully materialized by bond 45
92
  # veil the SHARP child in shadow instead of blurring it (blur reads as
93
  # a broken/loading image): dark and fog-shrouded at low bond, emerging
94
+ brightness = round(0.72 + 0.28 * t, 2)
95
+ opacity = round(0.82 + 0.18 * t, 2)
96
  almost_on = a >= 76
97
  flash_key = f"flash-{seq % 2}"
98
  tone_class = _tone_class(tone)
99
 
100
+ # a stronger inner/outer glow so the silhouette reads against the fog
101
  look = (
102
  f"filter:brightness({brightness}) "
103
+ f"drop-shadow(0 0 20px rgba(140,120,170,{round(0.25 + 0.25*t,2)})) "
104
+ f"drop-shadow(0 0 50px rgba(100,80,140,{round(0.15 + 0.20*t,2)}));"
105
  f"opacity:{opacity};"
106
  )
107
 
styles.css CHANGED
@@ -1331,19 +1331,25 @@ footer { display: none !important; }
1331
  overflow: hidden;
1332
  background: #04040a;
1333
  z-index: 50;
1334
- display: flex;
1335
- align-items: center;
1336
- justify-content: center;
1337
  }
1338
  #game-view.hide, #game-view.hidden { display: none !important; }
1339
 
1340
- /* the letterboxed stage — every game element is positioned inside this */
1341
  #game-stage {
1342
- position: relative;
1343
- width: min(1280px, 95vw);
1344
- aspect-ratio: 16 / 10;
1345
- max-height: 82vh;
1346
- overflow: visible;
 
 
 
 
 
 
 
 
 
1347
  }
1348
 
1349
  /* Gradio wrappers inside the stage must not create their own boxes */
@@ -1367,7 +1373,7 @@ footer { display: none !important; }
1367
  inset: -10%;
1368
  background-size: cover;
1369
  background-position: center 38%;
1370
- filter: grayscale(1) blur(42px) brightness(0.36);
1371
  transform: scale(1.08);
1372
  z-index: 0;
1373
  }
@@ -1379,8 +1385,8 @@ footer { display: none !important; }
1379
  pointer-events: none;
1380
  z-index: 1;
1381
  background:
1382
- radial-gradient(ellipse at 50% 40%, transparent 42%, rgba(4,3,8,0.72) 100%),
1383
- linear-gradient(to bottom, rgba(6,4,12,0.55) 0%, transparent 15%);
1384
  }
1385
 
1386
  /* a subtle inner frame edge so the scene feels contained like the intro */
@@ -1389,13 +1395,13 @@ footer { display: none !important; }
1389
  inset: 0;
1390
  pointer-events: none;
1391
  z-index: 2;
1392
- box-shadow: inset 0 0 90px rgba(0,0,0,0.55);
1393
  }
1394
 
1395
  /* top bar: title + controls — sits just above the stage */
1396
  #game-topbar {
1397
  position: absolute;
1398
- top: -46px;
1399
  left: 0;
1400
  right: 0;
1401
  z-index: 10;
@@ -1429,7 +1435,7 @@ footer { display: none !important; }
1429
  z-index: 8;
1430
  width: min(260px, 22vw);
1431
  min-width: 180px;
1432
- max-height: 70%;
1433
  transition: max-height 0.45s ease, opacity 0.35s ease;
1434
  overflow: hidden;
1435
  opacity: 0.88;
@@ -1439,7 +1445,7 @@ footer { display: none !important; }
1439
  padding: 8px 10px;
1440
  }
1441
  .game-drawer:hover { opacity: 1; }
1442
- .game-drawer.open { max-height: 70%; }
1443
  .game-drawer:not(.open) {
1444
  max-height: 38px;
1445
  cursor: pointer;
@@ -1474,7 +1480,7 @@ footer { display: none !important; }
1474
  z-index: 4;
1475
  width: min(360px, 26vw);
1476
  min-width: 220px;
1477
- height: min(520px, 62%);
1478
  pointer-events: none;
1479
  display: flex;
1480
  align-items: flex-end;
@@ -1513,27 +1519,30 @@ footer { display: none !important; }
1513
  position: absolute;
1514
  inset: 5% -10% 0 -10%;
1515
  background: radial-gradient(ellipse 55% 70% at 50% 82%,
1516
- rgba(170,150,200,0.32) 0%, transparent 72%);
1517
  pointer-events: none;
1518
- opacity: 0.9;
1519
  mix-blend-mode: screen;
1520
  }
1521
 
1522
  /* bottom subtitle / dialogue panel */
1523
  #game-dialogue {
1524
  position: absolute;
1525
- left: 50%;
 
1526
  bottom: 10px;
1527
- transform: translateX(-50%);
1528
  z-index: 9;
1529
- width: min(780px, 74vw);
1530
  display: flex;
1531
  flex-direction: column;
 
1532
  gap: 6px;
1533
  }
1534
 
1535
  #game-dialogue .chatbot {
1536
- height: 210px !important;
 
 
1537
  background: rgba(12,9,18,0.62) !important;
1538
  border: 10px solid transparent !important;
1539
  border-image: var(--stone-frame) 30 !important;
@@ -1542,6 +1551,7 @@ footer { display: none !important; }
1542
  backdrop-filter: blur(3px);
1543
  -webkit-backdrop-filter: blur(3px);
1544
  padding: 12px 16px !important;
 
1545
  }
1546
 
1547
  #game-dialogue .bot,
@@ -1549,7 +1559,7 @@ footer { display: none !important; }
1549
  #game-dialogue .bot .message,
1550
  #game-dialogue .bot p {
1551
  font-style: italic !important;
1552
- font-size: 1.14rem !important;
1553
  color: #d8d2e6 !important;
1554
  text-shadow: 0 0 16px rgba(120,70,160,0.22);
1555
  }
@@ -1559,7 +1569,7 @@ footer { display: none !important; }
1559
  #game-dialogue .user .message,
1560
  #game-dialogue .user p {
1561
  font-style: normal !important;
1562
- font-size: 1.02rem !important;
1563
  color: #e6e0f0 !important;
1564
  }
1565
 
@@ -1571,6 +1581,8 @@ footer { display: none !important; }
1571
  display: flex;
1572
  gap: 8px;
1573
  align-items: flex-end;
 
 
1574
  }
1575
 
1576
  #game-inputrow textarea,
@@ -1580,35 +1592,50 @@ footer { display: none !important; }
1580
  padding: 8px 10px !important;
1581
  }
1582
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1583
  /* tone classes — the world blooms or rots */
1584
- .tone-warm #game-bg { filter: grayscale(1) blur(42px) brightness(0.46); }
1585
  .tone-warm #game-vig {
1586
  background:
1587
- radial-gradient(ellipse at 50% 40%, transparent 46%, rgba(4,3,8,0.55) 100%),
1588
- linear-gradient(to bottom, rgba(6,4,12,0.32) 0%, transparent 15%);
1589
  }
1590
- .tone-warm .entity-img { filter: brightness(1.10) drop-shadow(0 0 16px rgba(180,160,210,0.25)) !important; }
1591
 
1592
- .tone-neutral #game-bg { filter: grayscale(1) blur(42px) brightness(0.36); }
1593
 
1594
- .tone-wounded #game-bg { filter: grayscale(1) blur(42px) brightness(0.28); }
1595
  .tone-wounded #game-vig {
1596
  background:
1597
- radial-gradient(ellipse at 50% 40%, transparent 36%, rgba(4,3,8,0.82) 100%),
1598
- linear-gradient(to bottom, rgba(6,4,12,0.68) 0%, transparent 15%);
1599
  }
1600
- .tone-wounded .entity-img { opacity: 0.82 !important; }
1601
 
1602
  .tone-hostile #game-bg {
1603
- filter: grayscale(1) blur(42px) brightness(0.22);
1604
  }
1605
  .tone-hostile #game-vig {
1606
  background:
1607
- radial-gradient(ellipse at 50% 40%, transparent 30%, rgba(30,4,8,0.82) 100%),
1608
- linear-gradient(to bottom, rgba(40,6,12,0.55) 0%, transparent 20%);
1609
  }
1610
  .tone-hostile .entity-img {
1611
- filter: sepia(0.22) saturate(1.35) brightness(0.90) drop-shadow(0 0 18px rgba(120,40,40,0.35)) !important;
1612
  }
1613
 
1614
  /* recall migration — the claimed memory drifts toward the child */
 
1331
  overflow: hidden;
1332
  background: #04040a;
1333
  z-index: 50;
 
 
 
1334
  }
1335
  #game-view.hide, #game-view.hidden { display: none !important; }
1336
 
1337
+ /* the letterboxed stage — absolute, centered, real height so children work */
1338
  #game-stage {
1339
+ position: absolute !important;
1340
+ left: 50% !important;
1341
+ top: 50% !important;
1342
+ transform: translate(-50%, -50%) !important;
1343
+ width: min(1280px, 95vw) !important;
1344
+ height: min(calc(95vw * 0.625), 82vh) !important;
1345
+ max-height: 82vh !important;
1346
+ overflow: visible !important;
1347
+ background: transparent !important;
1348
+ border: none !important;
1349
+ box-shadow: none !important;
1350
+ padding: 0 !important;
1351
+ margin: 0 !important;
1352
+ gap: 0 !important;
1353
  }
1354
 
1355
  /* Gradio wrappers inside the stage must not create their own boxes */
 
1373
  inset: -10%;
1374
  background-size: cover;
1375
  background-position: center 38%;
1376
+ filter: grayscale(1) blur(38px) brightness(0.52);
1377
  transform: scale(1.08);
1378
  z-index: 0;
1379
  }
 
1385
  pointer-events: none;
1386
  z-index: 1;
1387
  background:
1388
+ radial-gradient(ellipse at 50% 42%, transparent 46%, rgba(4,3,8,0.62) 100%),
1389
+ linear-gradient(to bottom, rgba(6,4,12,0.45) 0%, transparent 13%);
1390
  }
1391
 
1392
  /* a subtle inner frame edge so the scene feels contained like the intro */
 
1395
  inset: 0;
1396
  pointer-events: none;
1397
  z-index: 2;
1398
+ box-shadow: inset 0 0 70px rgba(0,0,0,0.42);
1399
  }
1400
 
1401
  /* top bar: title + controls — sits just above the stage */
1402
  #game-topbar {
1403
  position: absolute;
1404
+ top: -44px;
1405
  left: 0;
1406
  right: 0;
1407
  z-index: 10;
 
1435
  z-index: 8;
1436
  width: min(260px, 22vw);
1437
  min-width: 180px;
1438
+ max-height: 55vh;
1439
  transition: max-height 0.45s ease, opacity 0.35s ease;
1440
  overflow: hidden;
1441
  opacity: 0.88;
 
1445
  padding: 8px 10px;
1446
  }
1447
  .game-drawer:hover { opacity: 1; }
1448
+ .game-drawer.open { max-height: 55vh; }
1449
  .game-drawer:not(.open) {
1450
  max-height: 38px;
1451
  cursor: pointer;
 
1480
  z-index: 4;
1481
  width: min(360px, 26vw);
1482
  min-width: 220px;
1483
+ height: min(520px, 55vh);
1484
  pointer-events: none;
1485
  display: flex;
1486
  align-items: flex-end;
 
1519
  position: absolute;
1520
  inset: 5% -10% 0 -10%;
1521
  background: radial-gradient(ellipse 55% 70% at 50% 82%,
1522
+ rgba(170,150,200,0.35) 0%, transparent 72%);
1523
  pointer-events: none;
1524
+ opacity: 0.95;
1525
  mix-blend-mode: screen;
1526
  }
1527
 
1528
  /* bottom subtitle / dialogue panel */
1529
  #game-dialogue {
1530
  position: absolute;
1531
+ left: 0;
1532
+ right: 0;
1533
  bottom: 10px;
 
1534
  z-index: 9;
1535
+ width: 100%;
1536
  display: flex;
1537
  flex-direction: column;
1538
+ align-items: center;
1539
  gap: 6px;
1540
  }
1541
 
1542
  #game-dialogue .chatbot {
1543
+ width: min(780px, 74vw) !important;
1544
+ height: 200px !important;
1545
+ margin: 0 auto !important;
1546
  background: rgba(12,9,18,0.62) !important;
1547
  border: 10px solid transparent !important;
1548
  border-image: var(--stone-frame) 30 !important;
 
1551
  backdrop-filter: blur(3px);
1552
  -webkit-backdrop-filter: blur(3px);
1553
  padding: 12px 16px !important;
1554
+ box-sizing: border-box !important;
1555
  }
1556
 
1557
  #game-dialogue .bot,
 
1559
  #game-dialogue .bot .message,
1560
  #game-dialogue .bot p {
1561
  font-style: italic !important;
1562
+ font-size: 1.12rem !important;
1563
  color: #d8d2e6 !important;
1564
  text-shadow: 0 0 16px rgba(120,70,160,0.22);
1565
  }
 
1569
  #game-dialogue .user .message,
1570
  #game-dialogue .user p {
1571
  font-style: normal !important;
1572
+ font-size: 1.0rem !important;
1573
  color: #e6e0f0 !important;
1574
  }
1575
 
 
1581
  display: flex;
1582
  gap: 8px;
1583
  align-items: flex-end;
1584
+ width: min(780px, 74vw);
1585
+ margin: 0 auto;
1586
  }
1587
 
1588
  #game-inputrow textarea,
 
1592
  padding: 8px 10px !important;
1593
  }
1594
 
1595
+ #game-dialogue .bond-panel {
1596
+ width: min(780px, 74vw) !important;
1597
+ margin: 0 auto !important;
1598
+ }
1599
+
1600
+ #game-dialogue .voice-channel,
1601
+ #game-dialogue .voice-channel * {
1602
+ height: 0 !important;
1603
+ min-height: 0 !important;
1604
+ padding: 0 !important;
1605
+ margin: 0 !important;
1606
+ border: none !important;
1607
+ overflow: hidden !important;
1608
+ }
1609
+
1610
  /* tone classes — the world blooms or rots */
1611
+ .tone-warm #game-bg { filter: grayscale(1) blur(38px) brightness(0.62); }
1612
  .tone-warm #game-vig {
1613
  background:
1614
+ radial-gradient(ellipse at 50% 42%, transparent 52%, rgba(4,3,8,0.45) 100%),
1615
+ linear-gradient(to bottom, rgba(6,4,12,0.28) 0%, transparent 13%);
1616
  }
1617
+ .tone-warm .entity-img { filter: brightness(1.12) drop-shadow(0 0 18px rgba(190,170,220,0.30)) !important; }
1618
 
1619
+ .tone-neutral #game-bg { filter: grayscale(1) blur(38px) brightness(0.52); }
1620
 
1621
+ .tone-wounded #game-bg { filter: grayscale(1) blur(38px) brightness(0.38); }
1622
  .tone-wounded #game-vig {
1623
  background:
1624
+ radial-gradient(ellipse at 50% 42%, transparent 38%, rgba(4,3,8,0.78) 100%),
1625
+ linear-gradient(to bottom, rgba(6,4,12,0.65) 0%, transparent 13%);
1626
  }
1627
+ .tone-wounded .entity-img { opacity: 0.85 !important; }
1628
 
1629
  .tone-hostile #game-bg {
1630
+ filter: grayscale(1) blur(38px) brightness(0.30);
1631
  }
1632
  .tone-hostile #game-vig {
1633
  background:
1634
+ radial-gradient(ellipse at 50% 42%, transparent 32%, rgba(30,4,8,0.80) 100%),
1635
+ linear-gradient(to bottom, rgba(40,6,12,0.52) 0%, transparent 20%);
1636
  }
1637
  .tone-hostile .entity-img {
1638
+ filter: sepia(0.22) saturate(1.35) brightness(0.95) drop-shadow(0 0 18px rgba(120,40,40,0.35)) !important;
1639
  }
1640
 
1641
  /* recall migration — the claimed memory drifts toward the child */
tests/test_render.py CHANGED
@@ -69,8 +69,8 @@ class TestRenderEntity:
69
 
70
  def test_low_affinity_is_dark_and_faint(self):
71
  out = render_entity(0)
72
- assert "brightness(0.62)" in out
73
- assert "opacity:0.78" in out
74
  assert "scale(" not in out # size never changes — frame always fits
75
 
76
  def test_full_affinity_is_bright_full(self):
@@ -137,10 +137,10 @@ class TestRenderEntityUX:
137
  def test_recognizable_silhouette_at_start(self):
138
  # bond 20 (session start) must already read as a child, not a smudge
139
  out = render_entity(20)
140
- # t = 20/45 ≈ 0.444; brightness = 0.62 + 0.38*0.444 ≈ 0.79
141
- assert "brightness(0.79)" in out
142
- # opacity = 0.78 + 0.22*0.444 ≈ 0.88
143
- assert "opacity:0.88" in out
144
 
145
  def test_scene_tone_class_present(self):
146
  assert 'class="entity-scene tone-warm"' in render_entity(50, tone=20)
 
69
 
70
  def test_low_affinity_is_dark_and_faint(self):
71
  out = render_entity(0)
72
+ assert "brightness(0.72)" in out
73
+ assert "opacity:0.82" in out
74
  assert "scale(" not in out # size never changes — frame always fits
75
 
76
  def test_full_affinity_is_bright_full(self):
 
137
  def test_recognizable_silhouette_at_start(self):
138
  # bond 20 (session start) must already read as a child, not a smudge
139
  out = render_entity(20)
140
+ # t = 20/45 ≈ 0.444; brightness = 0.72 + 0.28*0.444 ≈ 0.84
141
+ assert "brightness(0.84)" in out
142
+ # opacity = 0.82 + 0.18*0.444 ≈ 0.90
143
+ assert "opacity:0.9" in out
144
 
145
  def test_scene_tone_class_present(self):
146
  assert 'class="entity-scene tone-warm"' in render_entity(50, tone=20)