diff --git a/docs/superpowers/plans/2026-08-13-story-theater.md b/docs/superpowers/plans/2026-08-13-story-theater.md
new file mode 100644
index 0000000..10b2cd8
--- /dev/null
+++ b/docs/superpowers/plans/2026-08-13-story-theater.md
@@ -0,0 +1,758 @@
+# 故事剧场化实现计划(三幕演出 + 动作卡全互动呈现)
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 把每关从"文字问答"升级为"儿童小剧场":开场演出(旁白+字幕淡入+角色道具入场)、决策动作卡(替代文字选项列表)、分支演出(选择后动画过渡)、结局演出(庆祝/鼓励动画),决策树数据模型零改动。
+
+**Architecture:** 纯前端呈现层升级。新增 `theater.js`(互动形态判定 + 演出数据提取纯函数)、`ActionCard.vue`(动作卡)、`SceneTheater.vue`(开场演出覆盖层);改造 `play.vue`(开场集成 + 动作卡 + 分支演出)与 `result.vue`(结局演出)。触控互动(PropPick 等 5 种)仅用于已有 config 互动节点;普通决策节点一律用动作卡呈现(**计划级修正**,见下)。全部 CSS 动画,无新依赖。
+
+**Tech Stack:** uni-app (Vue 3) H5 先行、现有 RubyText/SpeakButton/speech.js/visual.js/sound.js、CSS keyframes。
+
+**对规格的修正(重要)**:spec 中"按选项内容特征自动判定互动形态 a-e"与现有交互协议冲突——触控互动组件只有 success/fail 双出口(提交 options[0]/options[1]),而普通决策节点的 2-4 个选项各自指向独立分支,前端无法静态判定"最佳选项"。修正:普通决策节点(interaction_type=1)一律渲染动作卡(多分支语义完整保留),触控互动仅用于 config 非空的互动节点。全 36 关文字选项列表消灭的目标不变(动作卡兜底所有普通节点)。
+
+---
+
+### Task 1: `ui-src/src/utils/theater.js`(互动判定 + 演出数据提取)
+
+**Files:**
+- Create: `ui-src/src/utils/theater.js`
+
+- [ ] **Step 1: 写文件**
+
+```js
+// 剧场化工具:互动形态判定 + 开场演出数据提取(决策树模型零改动)
+
+const INTERACTION_MAP = { 2: 'PropPick', 3: 'StepSort', 5: 'DragPlace', 7: 'FindSpot', 8: 'LinkMatch' }
+
+// 互动形态判定:config 互动节点 → 对应触控组件;普通决策节点 → 动作卡
+// (触控组件只有 success/fail 双出口,普通节点多分支选项语义由 ActionCard 完整保留)
+export function pickInteraction(node) {
+ if (node && node.config && INTERACTION_MAP[node.interaction_type]) {
+ return INTERACTION_MAP[node.interaction_type]
+ }
+ return 'ActionCard'
+}
+
+// 开场演出道具:入口节点选项的道具名去重,最多 4 个
+export function entryProps(entry) {
+ const names = []
+ for (const o of (entry && entry.options) || []) {
+ if (o.prop && o.prop.name && !names.includes(o.prop.name)) {
+ names.push(o.prop.name)
+ if (names.length >= 4) break
+ }
+ }
+ return names
+}
+
+// 开场演出角色:入口节点人物(可能为空)
+export function entryCharacter(entry) {
+ return entry && entry.character ? entry.character : null
+}
+```
+
+- [ ] **Step 2: H5 编译检查**
+
+Run: `curl -s -o /dev/null -w "%{http_code}" http://localhost:5173/src/utils/theater.js` 返回 200。
+
+- [ ] **Step 3: 提交**
+
+```bash
+git add ui-src/src/utils/theater.js
+git commit -m "feat: 剧场化工具 theater.js(互动形态判定 + 开场演出数据提取)"
+```
+
+---
+
+### Task 2: `ui-src/src/components/ActionCard.vue`(动作卡组件)
+
+**Files:**
+- Create: `ui-src/src/components/ActionCard.vue`
+
+动作卡 = 现有选项列表的升级呈现:每选项一张卡(序号徽章 + 道具图标/emoji + 短语拼音注音 + 听一听 + 按压弹跳 + c1-c4 四色边框)。
+
+- [ ] **Step 1: 写组件**
+
+```vue
+
+
+
+ {{ ['A', 'B', 'C', 'D'][idx] }}
+
+
+ {{ propEmoji(o.prop.name) }}
+
+
+
+
+ 🔊
+
+
+
+
+
+
+
+```
+
+- [ ] **Step 2: H5 编译检查**
+
+Run: `curl -s -o /dev/null -w "%{http_code}" http://localhost:5173/src/components/ActionCard.vue` 返回 200。
+
+- [ ] **Step 3: 提交**
+
+```bash
+git add ui-src/src/components/ActionCard.vue
+git commit -m "feat: 动作卡组件 ActionCard(选项图标/拼音/听读/按压动画/四色边框)"
+```
+
+---
+
+### Task 3: `ui-src/src/components/SceneTheater.vue`(开场演出覆盖层)
+
+**Files:**
+- Create: `ui-src/src/components/SceneTheater.vue`
+
+开场演出:场景横幅 + 角色滑入 + 道具飞入 + 旁白自动朗读 + 字幕逐字淡入 + 跳过按钮。演出播完(或点跳过)后 emit done,父组件隐藏本层。
+
+- [ ] **Step 1: 写组件**
+
+```vue
+
+
+
+ 跳过 ›
+
+
+ {{ sceneEmoji }}
+ {{ sceneName }}
+
+
+
+
+ {{ propEmoji(p) }}
+
+
+
+
+
+ {{ character.name.slice(0, 1) }}
+ 🤔
+
+
+
+
+
+ 📖 情境
+ {{ speaking ? '正在朗读…' : '' }}
+
+
+
+ {{ ch.p }}
+ {{ ch.c }}
+
+
+
+
+
+ 开始 ›
+
+
+
+
+
+
+
+```
+
+- [ ] **Step 2: H5 编译检查**
+
+Run: `curl -s -o /dev/null -w "%{http_code}" http://localhost:5173/src/components/SceneTheater.vue` 返回 200。
+
+- [ ] **Step 3: 提交**
+
+```bash
+git add ui-src/src/components/SceneTheater.vue
+git commit -m "feat: 开场演出组件 SceneTheater(旁白朗读+字幕逐字淡入+角色入场+道具飞入+跳过)"
+```
+
+---
+
+### Task 4: `play.vue` 集成(开场演出 + 动作卡 + 分支演出)
+
+**Files:**
+- Modify: `ui-src/src/pages/play/play.vue`
+
+- [ ] **Step 1: script 部分改造**
+
+`
+```
+
+- [ ] **Step 2: template 部分改造**
+
+在 `` 之前插入开场演出覆盖层,并把选项列表块替换为 ActionCard:
+
+开场覆盖层(插在 ``(topbar 结束)之后、`` 之前):
+
+```html
+
+
+```
+
+场景卡片加演出状态类(`.scene-card` 增加 `:class="{ 'fx-shake': sceneFx }"`):
+
+```html
+
+```
+
+互动分发整块替换(原「互动组件(触控 5 种)」v-if 链 + 「选项选择(type 1)」v-else-if 的 `class="options"` 列表 + 「soon 兜底」三段,替换为 activeInteraction 驱动):
+
+```html
+
+
+
+
+
+
+
+
+
+ 该互动玩法(类型 {{ curNode.interaction_type }})敬请期待
+```
+
+- [ ] **Step 3: style 部分追加**
+
+在 `