# Local G2 Interactive Visualization Redesign Implementation Plan

> **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:** 将两份 Local G2 HTML 报告附录从流程卡片重做为可逐步查看路径变化、并能对照错误与正确预期的离线交互式可视化。

**Architecture:** 两页均继续为独立 HTML 文件。算法页使用一个固定坐标系的 SVG 和六个可切换状态，曲线由内嵌 JavaScript 的五次 Hermite 基函数计算并绘制；问题页使用三个可切换的 SVG 场景，每个场景同时呈现“实际发生 / 正确应有 / 差异原因”。所有教学几何固定标为典型示例，真实测试结论只以已知状态与原始文本呈现。

**Tech Stack:** HTML5、CSS、内嵌 SVG、原生 JavaScript、PowerShell 静态验证。

## Global Constraints

- 仅在 `dailywork_report/pathsmoothing_rep/` 下两个指定 HTML 路径重建内容；它们在本任务基线提交中尚未跟踪，因此 Git 可将首次纳入版本控制的重建页面显示为新增文件。不修改路径平滑算法、测试、地图、粗路径或两份 Markdown 报告的事实内容。
- 不使用任何外部资源：不使用 CDN、网络请求、外部图片、外部字体、第三方库或构建步骤。
- 算法页必须具备六个可访问步骤：粗路径、局部窗口、五次 Hermite、局部替换、曲率—弧长、安全与质量门。
- 问题页必须具备三个可访问问题场景；每个场景同时可见“实际发生”“正确应有”“差异原因”。
- 所有典型坐标、曲率图形和车辆示意均必须明确标注为机制解释，不得暗示为项目运行时实测结果。
- `RectangleDetour` 只陈述已复现的 `Success → InvalidInput`；失败点仍标记“待定位”，不得画出伪造的具体坏样本或根因。
- 用户已授权整体删除并从头重建两份旧 HTML；工作区存在无关改动，每个任务的提交只能包含其对应的一份 HTML，不得带入其他文件。

## File Structure

| 文件 | 职责 |
|---|---|
| `dailywork_report/pathsmoothing_rep/01-local-g2-quintic-hermite-algorithm-visualization.html` | 六步 Local G2 路径几何演示、Hermite 曲线生成、键盘/按钮步骤导航与安全质量门示意。 |
| `dailywork_report/pathsmoothing_rep/02-local-g2-issues-and-next-actions-visualization.html` | 三个问题的实际/正确对照、场景切换与证据边界标注。 |

---

### Task 1: 重做算法页为六步路径几何演示

**Files:**
- Modify: `dailywork_report/pathsmoothing_rep/01-local-g2-quintic-hermite-algorithm-visualization.html`

**Interfaces:**
- Consumes: 无运行时数据；仅使用固定、标为典型示例的二维点和已确认的 G2 术语/门限。
- Produces: `setStep(index)`、`buildQuinticPath()`、`stepButtons`、`#algorithm-diagram`、`#step-title`、`#step-description`、`#step-status`、`#prev-step` 与 `#next-step`，供 HTML 初次渲染、按钮和左右方向键共用。

- [ ] **Step 1: 先运行会失败的结构验证**

Run:

```powershell
$file = 'dailywork_report\pathsmoothing_rep\01-local-g2-quintic-hermite-algorithm-visualization.html'
$html = Get-Content -Raw -Encoding UTF8 $file
$required = @('id="algorithm-diagram"', 'data-step="0"', 'data-step="5"', 'id="prev-step"', 'id="next-step"', 'function buildQuinticPath', 'function setStep')
$missing = @($required | Where-Object { -not $html.Contains($_) })
if ($missing.Count -gt 0) { throw "Algorithm visual contract missing: $($missing -join ', ')" }
```

Expected: FAIL because the current static flow page has no interactive step contract.

- [ ] **Step 2: 整体删除旧卡片页面并从头重建，让主 SVG 成为视觉中心**

Use `apply_patch` to整体删除当前文件内容并添加一个响应式新文档，结构如下：

```html
<main id="local-g2-algorithm-demo" data-step="0">
  <header>…候选层已实现、正式发布流水线尚未接入…</header>
  <p class="evidence-note">典型示例：用于解释机制，不代表某次测试的精确坐标。</p>
  <nav class="stepper" aria-label="Local G2 平滑步骤">
    <button type="button" class="step-button" data-step="0" aria-pressed="true">0 粗路径</button>
    <button type="button" class="step-button" data-step="1" aria-pressed="false">1 局部窗口</button>
    <button type="button" class="step-button" data-step="2" aria-pressed="false">2 Hermite 约束</button>
    <button type="button" class="step-button" data-step="3" aria-pressed="false">3 局部替换</button>
    <button type="button" class="step-button" data-step="4" aria-pressed="false">4 连续性效果</button>
    <button type="button" class="step-button" data-step="5" aria-pressed="false">5 安全质量门</button>
  </nav>
  <section class="diagram-shell" aria-live="polite">
    <div class="step-copy"><span id="step-status"></span><h2 id="step-title"></h2><p id="step-description"></p></div>
    <svg id="algorithm-diagram" viewBox="0 0 1200 720" role="img" aria-labelledby="algorithm-svg-title algorithm-svg-desc">
      <title id="algorithm-svg-title">Local G2 五次 Hermite 局部路径平滑步骤</title>
      <desc id="algorithm-svg-desc">典型粗路径在局部曲率跳变处被五次 Hermite 曲线安全替换的六步示意。</desc>
      <!-- 始终可见的坐标、粗路径和步骤图层 -->
    </svg>
  </section>
  <div class="step-controls"><button id="prev-step" type="button">上一步</button><button id="next-step" type="button">下一步</button></div>
</main>
```

CSS requirements:

- `svg { width: 100%; height: auto; }`，不再使用 `min-width` 和横向滚动容器；窄屏按 `viewBox` 等比缩放。
- 用同一组语义颜色稳定表达：灰色原始粗路径、蓝色窗口/约束、绿色已接受候选、琥珀色发布边界、红色拒绝或阻断；同时配合实线/虚线、文字和符号。
- `.scene-layer` 默认淡出，`[data-step="N"] .scene-N` 显示；`prefers-reduced-motion: reduce` 时禁用转场。
- 不设置固定视口高度、不设置内部滚动，并保证按钮触摸目标和焦点状态清晰。

- [ ] **Step 3: 用真实五次 Hermite 基函数绘制典型候选曲线**

In the page script, define the fixed example endpoints and use the six quintic Hermite basis functions—not an SVG cubic Bézier substitute—to sample the visual candidate:

```javascript
const hermite = {
  p0: { x: 290, y: 462 }, p1: { x: 690, y: 258 },
  d0: { x: 180, y: 0 }, d1: { x: 210, y: -135 },
  a0: { x: 0, y: -18 }, a1: { x: 22, y: -12 }
};

function quinticBasis(t) {
  const t2 = t * t, t3 = t2 * t, t4 = t3 * t, t5 = t4 * t;
  return [
    1 - 10 * t3 + 15 * t4 - 6 * t5,
    t - 6 * t3 + 8 * t4 - 3 * t5,
    0.5 * (t2 - 3 * t3 + 3 * t4 - t5),
    10 * t3 - 15 * t4 + 6 * t5,
    -4 * t3 + 7 * t4 - 3 * t5,
    0.5 * (t3 - 2 * t4 + t5)
  ];
}

function buildQuinticPath() {
  const points = [];
  for (let i = 0; i <= 48; i += 1) {
    const [h00, h10, h20, h01, h11, h21] = quinticBasis(i / 48);
    points.push({
      x: h00 * hermite.p0.x + h10 * hermite.d0.x + h20 * hermite.a0.x + h01 * hermite.p1.x + h11 * hermite.d1.x + h21 * hermite.a1.x,
      y: h00 * hermite.p0.y + h10 * hermite.d0.y + h20 * hermite.a0.y + h01 * hermite.p1.y + h11 * hermite.d1.y + h21 * hermite.a1.y
    });
  }
  return points.map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x.toFixed(1)} ${point.y.toFixed(1)}`).join(' ');
}
```

Set the generated string on `#quintic-candidate`. Draw a separate raw polyline that shares the same window endpoints but has a visible heading/curvature break in its interior. Add persistent labels for start, end, direction, window boundary and `κ` jump; do not attach real-world units or claim these fixed coordinates are measured data.

- [ ] **Step 4: 实现六个可读状态的 SVG 图层**

Create six SVG groups, each carrying both `scene-layer` and `scene-0` through `scene-5` as appropriate. They must communicate these exact visual effects:

```text
scene-0: 原始离散点、方向箭头、突变点，候选曲线隐藏。
scene-1: 左右窗口边界和淡蓝色局部带高亮，其余粗路径降低不透明度。
scene-2: 两端切向箭头、二阶趋势弧线、虚线 quintic-candidate 可见。
scene-3: 灰色原折线与绿色候选曲线叠加，接缝用“替换开始/结束”标记。
scene-4: 上方替换后路径；下方 κ—s 趋势示意显示原始跳变与候选连续过渡，并标“趋势示意，非实测数据”。
scene-5: 三个车辆轮廓沿候选曲线放置；净空带、通过标记和“碰撞 / 净空 / 曲率 / 偏移”四个质量门可见。
```

Use `<path>`, `<circle>`, `<line>`, `<text>`, `<marker>` and simple `<g transform>` vehicle rectangles; do not use raster images. Put the existing “正式发布流水线尚未接入”的事实边界 below the visual, outside the six state layers.

- [ ] **Step 5: 接入状态更新与键盘操作**

Use one state function and no inline event handlers:

```javascript
const steps = [
  ['0 / 5', '原始 Hybrid A* 粗路径', '可行离散路径在局部接口处仍可能有曲率跳变。'],
  ['1 / 5', '检测并框定局部窗口', '只处理跳变附近，不重新搜索整条路径。'],
  ['2 / 5', '由端点约束构造五次 Hermite 候选', '位置、切向和曲率趋势共同确定局部曲线。'],
  ['3 / 5', '替换窗口内部的原始几何', '窗口外路径保持不变，接缝需要连续。'],
  ['4 / 5', '观察曲率—弧长连续性', '目标是消除接口处的趋势跳变，而不是只让外形更圆。'],
  ['5 / 5', '经安全与质量门决定接受或回退', '候选必须同时满足车体安全、净空、曲率和偏移约束。']
];

function setStep(index) {
  const next = Math.max(0, Math.min(steps.length - 1, index));
  const [status, title, description] = steps[next];
  document.getElementById('local-g2-algorithm-demo').dataset.step = String(next);
  document.getElementById('step-status').textContent = `步骤 ${status}`;
  document.getElementById('step-title').textContent = title;
  document.getElementById('step-description').textContent = description;
  stepButtons.forEach((button) => button.setAttribute('aria-pressed', String(Number(button.dataset.step) === next)));
  document.getElementById('prev-step').disabled = next === 0;
  document.getElementById('next-step').disabled = next === steps.length - 1;
}
```

Declare `stepButtons` before `setStep`, register each button, register `#prev-step`/`#next-step`, handle only unmodified `ArrowLeft` and `ArrowRight` key presses, then call `setStep(0)`. Do not override keyboard interaction when the event target is a form control.

- [ ] **Step 6: 重新运行算法页验证，确认由失败转为通过**

Run the Step 1 command again, then run:

```powershell
$file = 'dailywork_report\pathsmoothing_rep\01-local-g2-quintic-hermite-algorithm-visualization.html'
$html = Get-Content -Raw -Encoding UTF8 $file
$terms = @('典型示例：用于解释机制', '曲率—弧长', '趋势示意，非实测数据', '完整车体安全', '正式发布流水线尚未接入')
$missing = @($terms | Where-Object { -not $html.Contains($_) })
if ($missing.Count -gt 0) { throw "Algorithm visual content missing: $($missing -join ', ')" }
Write-Output 'Algorithm interactive visualization checks passed.'
```

Expected: `Algorithm interactive visualization checks passed.`

---

### Task 2: 重做问题页为错误与正确预期的几何对照

**Files:**
- Modify: `dailywork_report/pathsmoothing_rep/02-local-g2-issues-and-next-actions-visualization.html`

**Interfaces:**
- Consumes: 已确认的三类证据、`RectangleDetour` 端到端输出、窗口约束数值和弧长陈旧风险的事实边界。
- Produces: `selectIssue(issueId)`、`issueButtons`、`#issue-visual`、`#issue-evidence`、`#issue-title`、`#issue-actual`、`#issue-expected`、`#issue-cause`、`#issue-action`、`#prev-issue` 与 `#next-issue`。

- [ ] **Step 1: 先运行会失败的结构验证**

Run:

```powershell
$file = 'dailywork_report\pathsmoothing_rep\02-local-g2-issues-and-next-actions-visualization.html'
$html = Get-Content -Raw -Encoding UTF8 $file
$required = @('id="issue-visual"', 'data-issue="baseline"', 'data-issue="window"', 'data-issue="arclength"', 'function selectIssue', 'id="issue-actual"', 'id="issue-expected"', 'id="issue-cause"')
$missing = @($required | Where-Object { -not $html.Contains($_) })
if ($missing.Count -gt 0) { throw "Issue visual contract missing: $($missing -join ', ')" }
```

Expected: FAIL because the current page has only static issue cards and one causal flow diagram.

- [ ] **Step 2: 整体删除旧问题卡片页面并构建共享选择器与三栏事实说明**

Use `apply_patch` to整体删除当前文件内容并添加一个新文档，结构如下：

```html
<main id="local-g2-issue-demo" data-issue="baseline">
  <header>…三种证据等级…</header>
  <nav class="issue-selector" aria-label="选择要查看的 Local G2 问题">
    <button type="button" class="issue-button" data-issue="baseline" aria-pressed="true">问题一：基线失败</button>
    <button type="button" class="issue-button" data-issue="window" aria-pressed="false">问题二：窗口约束</button>
    <button type="button" class="issue-button" data-issue="arclength" aria-pressed="false">问题三：弧长错位</button>
  </nav>
  <section class="issue-stage" aria-live="polite">
    <div class="issue-copy"><span id="issue-evidence"></span><h2 id="issue-title"></h2></div>
    <svg id="issue-visual" viewBox="0 0 1200 700" role="img" aria-labelledby="issue-svg-title issue-svg-desc">…</svg>
    <div class="compare-copy">
      <article><h3>实际发生</h3><p id="issue-actual"></p></article>
      <article><h3>正确应有</h3><p id="issue-expected"></p></article>
      <article><h3>差异原因</h3><p id="issue-cause"></p></article>
    </div>
    <p class="next-action"><strong>下一步：</strong><span id="issue-action"></span></p>
  </section>
  <div class="issue-controls"><button id="prev-issue" type="button">上一个问题</button><button id="next-issue" type="button">下一个问题</button></div>
</main>
```

Use a single shared scale and distinct, labelled SVG lanes rather than three textual cards. Keep the priority/action order in a compact section below the interactive visual, not above it.

- [ ] **Step 3: 画出三个“实际 / 正确”对照场景，并保持证据边界**

Create `.issue-scene` SVG groups and make the selected group visible using `[data-issue="…"]` CSS. Each scene must implement these marks:

```text
baseline:
  - 上方：概念性 RectangleDetour 绕障路径、障碍物、灰色原始路径；红色问号标“首次失败样本待定位”。
  - 中间：实际链路 Hybrid A* Success → 原始基线复验 InvalidInput ⛔ → G2 候选未开始。
  - 下方：正确链路 Hybrid A* Success → 原始基线复验 Success → G2 候选评价。
  - 固定脚注：概念性几何，不代表尚未定位的实际坏样本。

window:
  - 上方：同一条典型路径上的事件 A/B 和弧长标尺，中心距离直接标为 1.0 m。
  - 中间左侧“实际”：两个 ±0.8 m 影响范围重叠后合并，合并总区间标“> 0.8 m”，红色叉号和“无候选”。
  - 中间右侧“正确”：可行的拆分窗口或一致的长度策略，绿色窗口 A/B 和“可评价候选”。
  - 下方：明确标“静态分析确认的逻辑缺口”。

arclength:
  - 上方：替换前路径的 A、B 两个局部窗口和原始弧长标尺。
  - 下方左侧“实际风险”：A 替换后路径长度改变，B-old 仍按旧弧长落在偏早位置；用虚线箭头表达旧映射。
  - 下方右侧“正确”：重算/稳定锚点后 B-new 落在预期局部；用实线箭头表达新映射。
  - 固定脚注：待正式多区域流水线接入后通过回归测试验证。
```

Do not draw a red collision marker or concrete bad curvature sample in `baseline`; only the question marker is allowed there. Pair every colored status with text (`实际`, `正确`, `待定位`, `无候选`, `重定位`) and a different line style or marker.

- [ ] **Step 4: 接入问题状态数据、导航和可访问性**

In the page script, use immutable descriptive data and one update function:

```javascript
const issues = {
  baseline: {
    evidence: '已复现故障 · RectangleDetour',
    title: '原始基线在 Local G2 开始前被拒绝',
    actual: 'Hybrid A* 粗路径规划成功，但原始基线统一复验返回 InvalidInput；候选生成没有开始。',
    expected: '同一条成功规划的粗路径应先作为可行基线通过统一复验，再进入候选评价。',
    cause: '首次非法数值或超限曲率样本尚未定位；不能把该失败归因于 G2 候选。',
    action: '记录首次异常的方向段、样本、曲率、净空和验证结果，在不放松安全门的前提下定位源头。'
  },
  window: {
    evidence: '静态分析确认的逻辑缺口',
    title: '合并范围比可用候选窗口更宽',
    actual: '相距 1.0 m 的事件被 ±0.8 m 范围合并，但候选总长度不能超过 0.8 m，结果没有候选。',
    expected: '窗口合并和最大总长度应采用一致语义，或在不满足时拆分为可行局部窗口。',
    cause: '影响范围的合并规则与候选总长度约束没有共同的可行性判断。',
    action: '加入 1.0 m 间距回归，统一窗口长度语义并验证候选仍可生成。'
  },
  arclength: {
    evidence: '待验证集成风险',
    title: '区域 A 替换后，区域 B 的弧长坐标可能陈旧',
    actual: 'A 拼接并重算弧长后，B 若仍使用替换前坐标，可能指向错误局部。',
    expected: '处理 B 前应按当前路径重定位，或由稳定锚点映射恢复其原始语义位置。',
    cause: '候选记录的原始弧长与每次拼接后重新计算的当前弧长处于不同坐标系。',
    action: '构造 A 改变长度、B 仍准确定位的双区域回归，再接入正式流水线。'
  }
};

function selectIssue(issueId) {
  const issue = issues[issueId];
  if (!issue) return;
  document.getElementById('local-g2-issue-demo').dataset.issue = issueId;
  document.getElementById('issue-evidence').textContent = issue.evidence;
  document.getElementById('issue-title').textContent = issue.title;
  document.getElementById('issue-actual').textContent = issue.actual;
  document.getElementById('issue-expected').textContent = issue.expected;
  document.getElementById('issue-cause').textContent = issue.cause;
  document.getElementById('issue-action').textContent = issue.action;
  issueButtons.forEach((button) => button.setAttribute('aria-pressed', String(button.dataset.issue === issueId)));
}
```

Declare an ordered `issueIds = ['baseline', 'window', 'arclength']`, implement previous/next by index, register button clicks, then call `selectIssue('baseline')`. Make the initial baseline state useful without JavaScript by placing its copy in the HTML before the script runs, then allow JavaScript to overwrite it with the same factually equivalent text.

- [ ] **Step 5: 重新运行问题页验证，确认由失败转为通过**

Run the Step 1 command again, then run:

```powershell
$file = 'dailywork_report\pathsmoothing_rep\02-local-g2-issues-and-next-actions-visualization.html'
$html = Get-Content -Raw -Encoding UTF8 $file
$terms = @('Success → InvalidInput', '首次失败样本待定位', '1.0 m', '±0.8 m', '> 0.8 m', '弧长重算', '实际发生', '正确应有', '差异原因')
$missing = @($terms | Where-Object { -not $html.Contains($_) })
if ($missing.Count -gt 0) { throw "Issue visual content missing: $($missing -join ', ')" }
Write-Output 'Issue interactive visualization checks passed.'
```

Expected: `Issue interactive visualization checks passed.`

---

### Task 3: 离线完整性、交互契约和可视化验收

**Files:**
- Verify: `dailywork_report/pathsmoothing_rep/01-local-g2-quintic-hermite-algorithm-visualization.html`
- Verify: `dailywork_report/pathsmoothing_rep/02-local-g2-issues-and-next-actions-visualization.html`

**Interfaces:**
- Consumes: 两页已实现的 DOM id、数据属性、函数名和离线资源限制。
- Produces: 可复查的 PowerShell 验证输出，以及在浏览器可用时的人工交互验收结论。

- [ ] **Step 1: 验证离线性、文件结构和静态交互契约**

Run:

```powershell
$files = @(
  'dailywork_report\pathsmoothing_rep\01-local-g2-quintic-hermite-algorithm-visualization.html',
  'dailywork_report\pathsmoothing_rep\02-local-g2-issues-and-next-actions-visualization.html'
)
$contracts = @{
  $files[0] = @('<!doctype html>', '<svg', '<script>', 'function buildQuinticPath', 'function setStep', 'id="algorithm-diagram"', 'data-step="5"')
  $files[1] = @('<!doctype html>', '<svg', '<script>', 'function selectIssue', 'id="issue-visual"', 'data-issue="arclength"', 'id="issue-cause"')
}
foreach ($file in $files) {
  $html = Get-Content -Raw -Encoding UTF8 $file
  $missing = @($contracts[$file] | Where-Object { -not $html.Contains($_) })
  if ($missing.Count -gt 0) { throw "$file missing: $($missing -join ', ')" }
  if ($html -match 'https?://|<script[^>]+\bsrc\s*=|<img[^>]+\bsrc\s*=') { throw "$file must not depend on external resources." }
  if (($html -split '<svg').Count -lt 2) { throw "$file must contain a main SVG." }
}
Write-Output 'Offline HTML and interaction contracts passed.'
```

Expected: `Offline HTML and interaction contracts passed.`

- [ ] **Step 2: 验证 JavaScript 所查询的 DOM 节点均存在**

Run:

```powershell
$checks = @{
  'dailywork_report\pathsmoothing_rep\01-local-g2-quintic-hermite-algorithm-visualization.html' = @('local-g2-algorithm-demo','step-status','step-title','step-description','prev-step','next-step','quintic-candidate')
  'dailywork_report\pathsmoothing_rep\02-local-g2-issues-and-next-actions-visualization.html' = @('local-g2-issue-demo','issue-evidence','issue-title','issue-actual','issue-expected','issue-cause','issue-action','prev-issue','next-issue')
}
foreach ($entry in $checks.GetEnumerator()) {
  $html = Get-Content -Raw -Encoding UTF8 $entry.Key
  $missing = @($entry.Value | Where-Object { -not $html.Contains("id=`"$_`"") })
  if ($missing.Count -gt 0) { throw "$($entry.Key) queried ids missing: $($missing -join ', ')" }
}
Write-Output 'DOM query targets passed.'
```

Expected: `DOM query targets passed.`

- [ ] **Step 3: 进行浏览器交互和窄屏人工验收，或如实记录不可用状态**

When an in-app browser is available, open each local HTML and verify:

```text
算法页：初始第 0 步可见；连续点六个步骤均可切换；上/下一步禁用状态正确；左右键切换；窄宽度下标签、曲线和按钮不重叠。
问题页：三个问题均可切换；每个场景同时可看到实际发生、正确应有、差异原因；问题一没有伪造坏样本；窄宽度下文本可读。
```

If no browser is available, do not substitute unapproved browser tooling or claim visual QA passed. Record that offline/static checks pass but browser-based visual inspection remains unavailable.

- [ ] **Step 4: 检查改动范围与空白字符**

Run:

```powershell
git diff --check -- dailywork_report/pathsmoothing_rep/01-local-g2-quintic-hermite-algorithm-visualization.html dailywork_report/pathsmoothing_rep/02-local-g2-issues-and-next-actions-visualization.html
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
git status --short -- dailywork_report/pathsmoothing_rep/
```

Expected: no whitespace errors; each任务提交仅包含其对应 HTML 文件，工作区状态不出现由本次工作带入的其他文件。
