Files
story-edit-web/web
邓雨鹏 021080dd56 feat(timeline): P2 并行编排——scene 多轨编辑器 + 白模重叠预览
剧情 Timeline P2 前端 + 共享内核(与 SGame 源真同步):
- ir_core/IR_SCHEMA/样张:scene v0.3 + scene 校验 + 导出 gate(D3),与 SGame 仓逐字一致
- timeline.js:appendScene 按 authored start 铺多轨 clip(自然重叠预览),move from 同 actor 跨轨续连(D4);
  drawStage 改逐 actor 查对话→多人气泡同时计时;导出 _clipDur 纯函数;show() 加 startId 参;常量加 CAMERA_DUR
- scene_edit.js(新):演出段编辑模态——拖 clip 改 start(吸附 0.1s)、拖右缘改 dur、增删 clip/轨道、
  选中属性条精确编辑、客户端轻量 lint(镜像 validate.py)、▶ 预览此段(复用播放核)
- graph.js:scene 节点(KIND_CN/summary/nodeInner 列轨道)+双击进编辑模态
- form.js:右栏 renderScene 精确数值编辑(轨道/clip 的 start/dur/kind/目标)+打开编辑器按钮
- app.py export:捕获 CompileError 并入 report(scene 被拦时不再 500)
- test_scene.js:离线 10 断言全过(重叠确凿/晚 1.5s 起步/from 续连);gitignore 忽略本地 _localdemo.db

待浏览器目测拖拽编辑落 IR + 白模重叠演出。
2026-06-13 22:34:29 +08:00
..

Story 事件协作 Web 编辑器M5

设计:docs/plans/2026-06-06-story-event-pipeline-design.md§5.1/§6, D1D4/D8 计划:docs/plans/2026-06-08-story-event-M5-web-editor-plan.md

少数人各凭专属口令(口令即身份,改动自动署名)在网页里审校/编辑剧情事件 → 静态校验 + 剧本试走(零引擎)→ 一键编译 所有 confirmed 事件成 .events.json + .i18n.tsv 打包下载。校验/编译走 ir_core,与 CLI ir_compile.py)逐字节同口径。

起服务

cd tools/event_authoring/web
pip install -r requirements.txt
# Windows PowerShell: $env:STORY_WEB_USERS="bia:口令A,ljl:口令B"
set STORY_WEB_USERS=bia:口令A,ljl:口令B   # 必填;未配置则拒绝启动
uvicorn app:app --host 0.0.0.0 --port 8787

浏览器打开 http://<host>:8787,输入自己的专属口令进入(服务端按口令认人, updated_by 自动署名;口令要求 ≥8 位且互不相同cookie 只存随机会话 token 不存口令; 从 STORY_WEB_USERS 移除某人即吊销其所有会话)。

用法

  1. 导入 IR:右上「导入 IR」粘贴单个或数组形式的 IR JSONsamples/*.ir.json)。
  2. 审校/编辑:左栏选事件 → 中栏分支树 → 点节点在右栏改文案/增删节点/下拉改分支/角色表/点位下拉。
  3. 校验:与 CLI 同口径(断链、选项无兜底、未登记 kind、未声明角色、点位缺失、out_ref 失效…)。
  4. 试走:从首节点走,点选项/掷随机/手选战斗胜负,实时累计银两/道具/友好度账面与结局。
  5. 确认/丢弃改事件状态pending/confirmed/discarded
  6. 导出 confirmed:编译所有 confirmed → story_export.zip;任一 confirmed 校验不过则整体拒绝。

导出后把 {group}.events.json 放进 Assets/StreamingAssets/Story/Config/(或 Qiyu/ 子目录), {group}.i18n.tsv 的韩文翻译合并进 Assets/StreamingAssets/i18n/ko.tsv

数据

  • 事件存 SQLite story_events.db(本目录,已 gitignore末次写入生效不做锁
  • 词典 ../ir_dictionary.json、点位集 Assets/StreamingAssets/Story/PointSets/*.points.json 只读引用。

Docker 部署M6

单容器FastAPI + 静态前端 + SQLite + 纯 Python 编译器)。构建上下文是 tools/event_authoring(需含 ir_core/ir_dictionary.json/web)。

cd tools/event_authoring/web
STORY_WEB_USERS="bia:口令A,ljl:口令B" docker compose up -d --build
# 或不用 compose
#   docker build -f web/Dockerfile -t story-event-web ..
#   docker run -d -p 8787:8787 -e STORY_WEB_USERS="bia:口令A,ljl:口令B" \
#     -v "$PWD/web/data:/data" \
#     -v "$PWD/Assets/StreamingAssets/Story/PointSets:/pointsets:ro" story-event-web
  • ./data:/dataSQLite 持久化,容器重建不丢事件,勿删 …/PointSets:/pointsets:ro(开发侧点位集只读;缺失时坐标校验降级为警告)。
  • 环境变量STORY_WEB_USERS(必填,名字1:口令1,名字2:口令2,未配置拒绝启动)、 STORY_WEB_PORT(宿主端口,默认 8787STORY_DB_PATH(默认 /data/story_events.db)、STORY_POINTSETS_DIR(默认 /pointsets)、 可选 TZ=Asia/Shanghai(否则 updated_at 按 UTC 显示)。
  • NAS + VPSNAS 跑容器VPS 用反代/frp/Cloudflare Tunnel 把 8787 映射出去。点位集更新只需 同步文件到 NAS 的 /pointsets 卷路径,无需重建镜像。备份=拷 data/story_events.db

API鉴权后

POST /api/login · GET /api/dictionary · GET /api/pointsets · POST /api/import · GET /api/events?status= · GET /api/events/{group} · PUT /api/events/{group} · POST /api/events/{group}/status · POST /api/validate · POST /api/export

非目标(见设计)

容器化部署M6、多人账号/并发锁、手拖画布、引擎侧新语义、把坐标嵌进 events.json。