feat(new8/batch2): 《深海回音》abyss +《雨夜专案》detective 全套交付(多agent流水线:策划→资产→开发→测试→真资产复跑)

- abyss:game.js 242 断言全绿(剧本A-F六路径/氧气门三形态/sonarGate仲裁/结算死窗/双轨看门狗/radio 8项修复继承);资产 148句+11key变体(电台滤波带内能量47-62%→69-80%)
- detective:game.js 265 断言真资产下全绿(矩阵不变式独立重算/指证全路径/评级12组注入/VERDICT死窗/二周目变体);真资产复跑回炉3处实现修复(无进展轨墙钟化/菜单暂停记账/停止播报真停声——mock时长掩盖的正确性bug)
- 资产:TTS 539条×2格式、Mureka 7首 $0.21(累计$1.08/$2.00)、SYN12+SA3 19件(QC抓出1例AAC过冲并修复)、封面×2、check_all_assets 10游戏全绿(abyss 298/298、detective 279/279)
- 平台接线:大厅双卡片、BUCKETS 增 abyss/detective 桶(H4 断言更新 10 游戏)、voice_text.json 10游戏991句
- 回归:14 套件全绿(10 playtest+guide+engine-voice+engine-input+api-smoke 12/12)
- 设计偏差登记:abyss 7条/detective 9条(全为设计内部冲突按承诺清单/归因真话律取优)
This commit is contained in:
xsl
2026-09-10 01:40:31 +08:00
parent cd4c5ec65a
commit 31372615b2
1183 changed files with 8445 additions and 10 deletions
+106
View File
@@ -0,0 +1,106 @@
"""web/abyss 封面:1080x1920,深潜救援主题——深海近黑蓝底、声呐同心圆、
单点脉冲光与竖排标题《深海回音》。可复现脚本(固定 seed,无外部网络依赖)。
用法(PIL 探测顺序:系统 python3 → .venv-tts → 装 pillow 后任一):
python3 web/abyss/gen/gen_cover.py
"""
import math
import os
import random
from PIL import Image, ImageDraw, ImageFilter, ImageFont
W, H = 1080, 1920
FONT_CANDIDATES = [
"/home/xsl/SoundGame/web/rhythm/gen/NotoSansSC-Bold.ttf",
"/home/xsl/SoundGame/app/src/reflex/gen/NotoSansSC-Bold.ttf",
]
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "cover.png")
def load_font(size):
for p in FONT_CANDIDATES:
if os.path.exists(p):
return ImageFont.truetype(p, size)
raise SystemExit("未找到中文字体,请放一份 NotoSansSC-Bold.ttf 到 web/rhythm/gen/")
def main():
rng = random.Random(922) # 固定 seed:可复现
img = Image.new("RGB", (W, H), (3, 8, 16))
d = ImageDraw.Draw(img)
# 背景竖向渐变:海面微光 -> 沟底近黑(下潜方向)
for y in range(H):
t = y / H
d.line([(0, y), (W, y)],
fill=(int(16 - 13 * t), int(34 - 26 * t), int(56 - 40 * t)))
# 远景悬浮微粒(深海水雪 marine snow)
dot = Image.new("RGBA", (W, H), (0, 0, 0, 0))
dd = ImageDraw.Draw(dot)
for _ in range(150):
x, y = rng.randint(0, W - 1), rng.randint(0, H - 1)
r = rng.choice([1, 1, 2])
dd.ellipse([x - r, y - r, x + r, y + r],
fill=(180, 210, 230, rng.randint(14, 46)))
img.paste(dot, (0, 0), dot)
d = ImageDraw.Draw(img)
# 中央:声呐同心圆(你发出的脉冲),青色环从光点向外扩散
cx, cy = W // 2, 600
for i, (r, alpha, wd) in enumerate([(348, 30, 3), (272, 48, 4), (196, 70, 5), (124, 96, 6)]):
d.ellipse([cx - r, cy - r, cx + r, cy + r],
outline=(56, 189, 248, alpha) if i % 2 == 0 else (125, 211, 252, alpha),
width=wd)
glow = Image.new("RGBA", (W, H), (0, 0, 0, 0))
gd = ImageDraw.Draw(glow)
gd.ellipse([cx - 44, cy - 44, cx + 44, cy + 44], fill=(186, 230, 253, 200))
gd.ellipse([cx - 88, cy - 88, cx + 88, cy + 88], fill=(56, 189, 248, 60))
glow = glow.filter(ImageFilter.GaussianBlur(10))
img.paste(glow, (0, 0), glow)
d = ImageDraw.Draw(img)
d.ellipse([cx - 20, cy - 20, cx + 20, cy + 20], fill=(240, 249, 255))
# 一记微弱回波:右下偏移的暗环(「深海回音」具象)
rx, ry = cx + 250, cy + 170
for r, alpha in [(150, 40), (104, 60), (64, 84)]:
ring = Image.new("RGBA", (W, H), (0, 0, 0, 0))
rd = ImageDraw.Draw(ring)
rd.ellipse([rx - r, ry - r, rx + r, ry + r],
outline=(94, 234, 212, alpha), width=3)
ring = ring.filter(ImageFilter.GaussianBlur(1.2))
img.paste(ring, (0, 0), ring)
d = ImageDraw.Draw(img)
# 标题(居中)与副题
f_title = load_font(172)
f_sub = load_font(54)
f_small = load_font(38)
def ctext(y, s, font, fill, spacing=8):
bbox = d.textbbox((0, 0), s, font=font)
w = bbox[2] - bbox[0]
x = (W - w) / 2
for ch in s:
d.text((x, y), ch, font=font, fill=fill)
bb = d.textbbox((0, 0), ch, font=font)
x += (bb[2] - bb[0]) + spacing
ctext(1020, "深海回音", f_title, (224, 242, 254), spacing=16)
ctext(1272, "声呐里,是被困潜艇的五个人", f_sub, (110, 134, 166))
# 手势图例(极简两行)
hints = ["单击 发声呐脉冲", "左右滑 抉择", "上滑 氧气与进度", "下滑 菜单", "双击 重听"]
for i, s in enumerate(hints):
col, row = i % 3, i // 3
d.text((110 + col * 300, 1420 + row * 76), s, font=f_small, fill=(92, 112, 142))
ctext(1700, "氧气在倒数。每次下潜,都是抉择。", f_small, (76, 94, 122))
img.save(OUT)
print(OUT, img.size)
if __name__ == "__main__":
main()