Skip to content

Latest commit

 

History

History
443 lines (319 loc) · 25.8 KB

File metadata and controls

443 lines (319 loc) · 25.8 KB
doc-id 21-floating-workbench-island
title 浮动工作台与灵动岛交互方案
status active
version 0.2.0
last-updated 2026-08-29
implementation-status implemented; browser-visual-validation-pending
source-range Runtime 浮动入口、可拖拽工作台、视口定位、会话位置恢复、动效、响应式、无障碍与专项验收
参考文献/依赖
05-runtime-lifecycle
09-local-protocol-security
11-coding-standards
12-testing-acceptance
20-local-development-acceptance

浮动工作台与灵动岛交互方案

2026-09-09 文档配图

灵动岛规范概念示意

本图按实现职责重绘,不是实际运行截图,也不更新本页 implementation-status 中的待验收项。README 的 GIF 是预设演示状态,不能代替真实事件驱动、拖拽、触摸、缩放或性能验收。英文配图在同目录 en-US 下;素材来源见 事实核对记录

1. 文档目的与状态

本文定义 SpotPatch Runtime 浮动入口和上下文工作台的下一阶段交互。已经确认的产品方向是:入口默认位于右下角,入口和展开后的工作台均可由用户拖拽改变位置;选中元素后,工作台保持用户位置,不再以选中元素为定位锚点。页面元素只保留候选高亮和持久编号高亮。

截至 2026-08-29,本文的 Runtime 实现已落地:floating-surface-position.ts 提供纯位置计算,floating-surface-controller.ts 管理 Pointer Events、边缘吸附、视口协调和释放,floating-surface-session.ts 负责按 sessionId 隔离的恢复;runtime-view.ts 已移除目标锚点和旧 placement 算法。专项单元、类型和 lint 校验已覆盖并通过。

这不替代浏览器视觉验收:本次环境未提供可用的受控浏览器,因此真实 Chromium 下的拖拽、窄视口、缩放、触摸与截图验收仍是发布前 required Gate,不能因此被描述为已通过。

通用品牌、目标编辑、Agent、双语、诊断和无障碍规则仍由 (见 doc-id:10-ui-diagnostics) 负责;本文只拥有浮动位置、拖拽、展开方向和对应动效的规范事实,避免两个文档重复维护同一算法。

2. 实仓事实与问题校准

2.1 当前代码事实

当前 Runtime 的相关实现分布在 packages/runtime/src/ui/runtime-view.tspackages/runtime/src/ui/floating-surface-{position,controller}.tspackages/runtime/src/state/floating-surface-session.ts

  • Trigger 和工作台共享归一化锚点;默认锚点解析为右下安全区域,用户拖拽后按 session 恢复;
  • 工作台只读取自身尺寸和安全视口,showHighlight()showSelectionHighlights() 不再参与面板定位;
  • 位置控制器使用 Pointer Events、pointer capture、单帧布局协调、边缘吸附和取消恢复;
  • dialog-placement.ts、视觉箭头、placement dataset 和目标矩形定位状态已删除;
  • Runtime 现有业务状态只有 idle | inspecting | selected | previewing,足以驱动入口和工作台展示,不需要为视觉动画复制一套业务状态机;
  • 当前实现常量为最大宽度 460px、最大高度 620px,旧版 UI 规范中的 560px × 720px 与代码存在漂移。

2.2 当前问题

  1. 工作台已经承载目标说明、数据链路、Agent、诊断和底部操作,不再是适合依附单个元素的小型气泡;活动目标变化会造成主操作区位置跳动。
  2. 滚动期间,目标高亮更新与工作台尺寸测量耦合,存在不必要的同步布局读取。
  3. 多目标分散在页面时,“活动目标决定工作台位置”会让用户已经建立的空间记忆失效。
  4. 真实 Chromium 的视觉、触摸、缩放和窄视口验收仍未在本次受控环境完成,不能把单元测试替代为视觉证据。

3. 目标与非目标

3.1 目标

  1. 首次加载时,灵动岛入口稳定出现在右下角安全区域。
  2. 用户可以拖拽灵动岛,也可以通过工作台标题栏拖拽展开后的工作台。
  3. 点击与拖拽有确定边界;拖动不能误触发选择,点击不能产生位置漂移。
  4. 工作台从当前浮动位置向可用空间展开,始终被限制在可见视口内。
  5. 选择、滚动和目标尺寸变化只更新高亮,不改变浮动工作台位置。
  6. 当前开发 Session 内刷新页面后恢复位置;无效或不可用存储安全退回默认位置。
  7. 桌面、窄视口、触摸输入、浏览器缩放和动态视口均有确定降级。
  8. 动效使用现有 Runtime 状态投影,不引入第三方动画依赖或并行业务状态。
  9. 删除被替代的目标定位算法、视觉锚点、测试和无意义回调,不保留兼容死分支。

3.2 非目标

  • 不让 SpotPatch 修改宿主页面布局、为业务页面增加右侧 padding,或推动业务内容避让工作台;
  • 不在首版增加可配置公共 API、拖拽网格、多个浮窗、面板尺寸调整或跨设备同步;
  • 不使用 HTML Drag and Drop;它不适合同时承担按钮点击、触摸拖动和表单交互;
  • 不把用户位置写入项目文件、服务端配置、URL、Cookie 或长期 localStorage
  • 不复制 Apple Dynamic Island 的外观和行为;“灵动岛”只表示紧凑胶囊入口、状态反馈和连续展开体验;
  • 不因动画尚未完成而阻塞核心选择、说明编辑、Preview 或 Agent 操作。

4. 产品交互契约

4.1 状态投影

Runtime 状态 浮动表面 页面高亮 主要行为
idle 且无保留目标 紧凑灵动岛,显示“选择元素” 点击进入选择;拖动改变位置
idle 且有保留目标 紧凑灵动岛,显示可恢复语义 按现有导航规则决定是否可见 点击恢复工作台;拖动改变位置
inspecting 灵动岛显示明确的选择中状态 hover 候选高亮;已有目标高亮保留 点击页面候选;Escape 取消;仍可拖动入口
selected 当前锚点处展开工作台 全部目标编号高亮 编辑、追加、发送、预览;标题栏可拖动
previewing 工作台位置与尺寸边界不重置,只切换内容 保留目标高亮 复制或返回;标题栏仍可拖动

浮动表面只消费 Runtime 状态和现有目标数量,不拥有选择、Preview 或 Agent 的领域转换。动画结束事件不得触发业务状态变化。

4.2 拖拽区域

  • 灵动岛:胶囊主体是点击与拖拽共用区域;键盘激活仍按标准按钮语义执行点击。
  • 工作台:只允许标题栏中的非交互空白区域或显式拖拽手柄开始拖动。
  • GitHub、语言切换、关闭按钮、输入框、选择器、折叠区、滚动区和底部操作不得启动拖动。
  • 拖动区域使用 Pointer Events,设置 touch-action: none;表单和正文区域保持浏览器原生选择、滚动和触控行为。
  • 只接受 primary pointer;非主鼠标键、多指后续 pointer 和合成事件不能改变位置。

4.3 点击与拖动判定

Pointer down 时只记录候选手势,不立即改变业务状态。移动距离超过集中定义的激活阈值后才进入 dragging;进入后通过 setPointerCapture() 持续接收当前 pointer,并抑制本次 click。未超过阈值的 pointer up 保持普通点击。

必须处理 pointeruppointercancel、丢失 pointer capture、窗口失焦和 dispose。Escape 在拖动期间优先取消本次拖动并恢复上一个已提交位置;没有拖动时继续执行 Runtime 已有的 Escape 规则。不得用固定延时区分点击和拖动。

阈值属于交互策略,只能在浮动表面模块的单一常量所有者中定义。测试引用导出行为或通过输入输出断言,不复制数值字面量。

4.4 自由位置与边缘吸附

本方案采用“自由拖动 + 有界边缘吸附”:

  1. 拖动过程中表面跟随 pointer,并实时钳制在安全视口内;
  2. 释放时,只有进入集中定义的吸附范围才靠近最近边缘,否则保留自由位置;
  3. 四角同时满足两个边缘时形成角落停靠;
  4. 吸附只改变最终位置,不改变 Runtime 状态;
  5. 窄视口下工作台采用底部工作台布局,禁止保持会遮断主要操作的任意自由位置;灵动岛仍可在安全范围内移动。

吸附是位置算法的确定性输出,不通过 CSS 猜测,也不使用多段 timeout 制造磁吸效果。

4.5 展开与收起

灵动岛和工作台共享一个持久化浮动锚点。展开方向由锚点、当前安全视口和工作台实测尺寸计算:

  • 靠右时优先向左展开,靠左时优先向右展开;
  • 靠下时优先向上展开,靠上时优先向下展开;
  • 自由位置按可用面积选择稳定方向,并使用上一次对齐方向避免中心线附近抖动;
  • 最终矩形必须再次钳制到安全视口;
  • 收起后灵动岛回到同一锚点,不回到默认右下角。

工作台展开后,目标变化不能重新计算浮动锚点。只有用户拖动、视口变化、工作台自身尺寸变化、位置恢复或重置位置可以触发表面布局协调。

5. 位置模型与算法边界

5.1 内部模型

位置模型是 Runtime 私有类型,不进入 @spotpatch/shared、公共配置或浏览器/服务端协议。建议的最小模型为:

type SurfaceAlignment = "start" | "end";

interface FloatingSurfacePosition {
  readonly xRatio: number;
  readonly yRatio: number;
  readonly horizontal: SurfaceAlignment;
  readonly vertical: SurfaceAlignment;
}

xRatio/yRatio 表示安全视口内的归一化锚点,不保存原始屏幕像素。horizontal/vertical 表示浮动表面的哪一侧附着到锚点;它们用于保持中心线附近的稳定展开方向,不是可从单次尺寸可靠推导的重复字段。

模型不得包含以下派生状态:

  • 当前 left/top/right/bottom 像素;
  • 工作台宽高;
  • 是否正在选择、是否展开;
  • 目标矩形或目标 ID;
  • 动画进度;
  • 是否移动端。

上述信息必须从当前视口、DOM 实测尺寸、Runtime 状态和媒体条件即时派生,避免双向同步。

5.2 纯函数职责

新的位置模块只接收不可变输入并返回不可变结果,至少包含:

  • 默认锚点解析;
  • pointer 位移到候选锚点的转换;
  • 安全视口钳制;
  • 边缘吸附;
  • 对齐方向选择与稳定保持;
  • 紧凑岛体和展开工作台矩形解析;
  • 视口变化后的归一化恢复。

纯函数不读取 DOM、Storage、媒体查询或全局 Window。DOM 尺寸读取和样式写入由控制器边界负责,便于对四边、四角、中心、极窄视口和异常输入做确定性单元测试。

5.3 安全视口

控制器优先使用 window.visualViewport 的偏移和尺寸,缺失时回退 innerWidth/innerHeight。安全边距和移动端边距由 Shadow Root 的布局令牌定义;JavaScript 应读取实际边界容器矩形或解析后的单一令牌结果,不能在 TS 和 CSS 中各维护一份相同数值。

软键盘、浏览器缩放或窗口 resize 后,应调度一次布局协调并钳制当前位置。不得在每个 pointermove 同步重复读取多个布局属性。

6. 状态所有权与项目组织

6.1 模块边界

建议在现有 packages/runtime 内完成,不新增 workspace package 或公共 export:

packages/runtime/src/
├── state/
│   ├── floating-surface-session.ts
│   └── floating-surface-session.test.ts
└── ui/
    ├── floating-surface-position.ts
    ├── floating-surface-position.test.ts
    ├── floating-surface-controller.ts
    ├── floating-surface-controller.test.ts
    ├── runtime-view.ts
    └── runtime-view.test.ts

职责如下:

  • floating-surface-position.ts:纯位置计算和私有类型;取代 dialog-placement.ts
  • floating-surface-controller.ts:Pointer Events、pointer capture、帧合并、DOM 读写和生命周期释放;不处理选择业务;
  • floating-surface-session.ts:版本化 Session Storage 解析与 best-effort 保存;不读取目标草稿;
  • runtime-view.ts:创建 DOM、投影 Runtime 状态、接入控制器和样式,不内联拖拽算法;
  • runtime-controller.ts:继续拥有选择和目标生命周期,不接管浮动位置。

若实施时控制器非常小且只有一个消费者,可以与位置模块合并;只有在职责和测试边界真实独立时才保留三个模块。不得为了匹配本文树形示意制造空包装器、单行转发器或仅重导出的 barrel。

6.2 单一状态来源

状态 唯一所有者
idle/inspecting/selected/previewing 现有 Runtime 状态机
目标集合、活动目标和说明 现有 Runtime Controller/Selection Session
committed 浮动位置 Floating Surface Controller + Floating Surface Session
当前 pointer 手势 Floating Surface Controller 内存状态
展开方向和像素矩形 Position 纯函数派生
视觉过渡 CSS data-* 状态投影

禁止把 dragging 加入 Runtime 领域状态机;它是短生命周期的视图手势。禁止让 CSS class、Storage 和 Controller 分别保存三份“当前是否展开”。

7. 位置恢复与隐私

位置恢复沿用现有 Selection Session 的容错模式,但使用独立 key 和独立快照:

  • 存储介质:当前 Window 的 sessionStorage
  • 隔离范围:带 sessionId 的 SpotPatch 命名空间;
  • 快照内容:版本、归一化锚点和两轴对齐;
  • 明确不保存:页面 URL、路径、组件名、目标、说明、Prompt、Agent 状态或用户输入;
  • 读取规则:从 unknown 开始验证对象形状、版本、有限数、[0, 1] 比例和允许枚举;额外字段不进入领域状态,未知版本、比例越界或 JSON 异常时忽略整份快照;
  • 写入规则:只在一次拖动成功提交或重置位置后写入,不在每个 pointermove 写 Storage;
  • 失败规则:访问受限、配额不足或序列化失败不影响当前内存位置和核心 picker;
  • 生命周期:清除目标不能清除 UI 位置;新的开发 Session 默认回到右下角。

首版不使用 localStorage,因此不承诺关闭浏览器或重新启动 dev server 后长期保留。若未来需要跨 Session 保存,必须先定义项目隔离键、迁移和显式重置策略,不能直接替换存储介质。

8. 视觉与动效

8.1 灵动岛状态

  • 空闲:品牌状态点、可读动作文字和快捷键 tooltip;
  • 选择中:状态点使用克制呼吸/扫描反馈,文字明确表示正在选择;
  • 有保留目标:显示可恢复语义,不把再次点击误导成重新清空选择;
  • 拖动中:阴影和缩放提供抓取反馈,暂停 hover 位移;
  • 展开:岛体淡出,工作台以共享锚点为 transform origin 进入;
  • 收起:执行相反过渡,焦点按现有规则恢复。

Agent 的连接、执行和结果状态继续在工作台内由现有面板表达。首版不把全部 Agent 状态复制到岛体,避免第二套状态文案和颜色映射。

8.2 动效约束

  • 颜色、边框、轻微位移和状态点使用集中 CSS motion token;
  • 岛体尺寸变化和工作台进入可使用不同 token,但所有值只在 :host 设计令牌中定义;
  • 不使用 JS interval、逐帧 setTimeout 或动画结束后修改业务状态;
  • 不对工作台正文做整体大比例缩放,避免文字模糊和焦点元素视觉漂移;
  • prefers-reduced-motion: reduce 下移除位移、缩放、呼吸和磁吸过渡,只保留即时状态切换;
  • 动画期间的可点击区域必须与最终几何一致,不能出现视觉位置与 hit area 分离。

当前 460px × 620px 只作为首轮视觉验证基线。最终宽高、边距、吸附距离、手势阈值和 motion 时长必须分别归入布局、手势和 CSS 令牌的单一所有者,并在 playground 实测后确定;不得把同一数值复制到测试和多个模块。命名设计令牌不是业务硬编码,散落且相互依赖的裸字面量才是本方案禁止的硬编码。

9. 响应式与边界行为

9.1 桌面

  • 默认右下角;工作台最大宽度以现有 460px 为视觉验证基线;
  • 工作台正文独立滚动,标题栏、关闭入口和底部主操作保持可见;
  • 用户拖到任意自由位置后,展开矩形仍必须完全位于安全视口;
  • 工作台不能因为目标位于另一侧而移动。

9.2 窄视口

  • 灵动岛在可见安全范围内移动;
  • 展开后的工作台切换为底部受限布局,左右使用紧凑安全边距;
  • 自由桌面位置只作为锚点参考,不强行维持可能越界的像素位置;
  • 关闭后灵动岛恢复到经过钳制的最近有效位置;
  • 使用动态视口高度并考虑 safe area,不能仅依赖旧式 100vh

9.3 内容变化

数据链路、诊断、Agent 设置和结果折叠会改变内容高度。现有扩展提供的 onViewChange 仍有实际消费者,但其用途从“重新跟随目标”收敛为“合并调度一次浮动表面边界协调”。如果实施后 CSS 最大高度和滚动容器已能在全部状态保证边界,则应删除该回调及全部调用;不能保留空函数兼容层。

10. 性能与生命周期

  • pointermove 只更新内存中的最新坐标,每个 animation frame 最多执行一次 DOM 写入;
  • 拖动开始时读取必要矩形,拖动帧中不反复测量不变尺寸;
  • 工作台内容、视口或对齐变化时才重新测量展开表面;
  • 目标 scroll/ResizeObserver 继续更新高亮,但不得调用浮动表面测量;
  • 布局协调使用单一调度器合并同一帧内的数据链路、Agent 和诊断更新;
  • dispose 必须释放 pointer、lost capture、blur、resize、visualViewport 和 media query 监听,取消待执行 animation frame;
  • HMR 后旧控制器不得继续持有 DOM、Window 或 pointer 状态;
  • 不新增第三方动画、手势或状态管理依赖。

目标是移除当前滚动期间因工作台跟随目标产生的尺寸读取,而不是用更频繁的拖拽布局计算替代它。性能门禁仍以 (见 doc-id:12-testing-acceptance) 为准。

11. 无障碍与键盘

  1. 灵动岛继续是带可读名称和 aria-pressed 的按钮;拖拽是附加能力,不能成为使用 SpotPatch 的必要条件。
  2. 工作台继续使用 role="dialog" 和标题关联;展开、收起和焦点恢复遵循现有规范。
  3. 标题栏拖拽手柄必须有明确名称;如果使用纯装饰空白区拖拽,仍需提供可聚焦的“重置位置”控制。
  4. 重置位置必须可由键盘执行,并通过 polite live region 宣告结果。
  5. 拖动时不连续向读屏播报像素;只在提交、取消或重置后播报一次结果。
  6. Escape 在拖动时先取消拖动;非拖动状态保持现有确定行为。
  7. 高对比度、减少动画、页面缩放到 200% 和触控目标均需真实 Chromium 验证。

首版不要求键盘逐像素移动浮层,因为默认位置下所有核心能力完整可用;若后续增加键盘移动,必须通过有限步进和可撤销操作实现,不能复用不透明的 pointer 模拟。

12. 错误与降级

情况 必须行为
Storage 不可访问或损坏 使用内存默认位置,不显示阻断错误
visualViewport 不可用 回退布局视口并保持边界钳制
Pointer Capture 不可用或丢失 安全结束/取消当前拖动,不改变业务状态
工作台大于可用视口 启用窄视口/底部布局和内部滚动
恢复位置在视口外 归一化并钳制,不写入 NaN/Infinity
动画不支持或减少动画 即时切换,核心功能保持一致
内容在拖动中改变尺寸 完成当前帧后统一协调,不跳回目标附近

所有降级都保持选择、目标说明和 Preview 可用。位置恢复失败不是协议错误,不进入 Agent 错误码或服务端日志。

13. 删除与迁移清单

实施必须在同一变更中处理以下旧实现:

  • 删除 packages/runtime/src/ui/dialog-placement.ts
  • 删除 packages/runtime/src/ui/dialog-placement.test.ts
  • 删除 runtime-view.ts 中仅为目标定位存在的 currentRectactiveSelectionRect、anchor DOM、placement dataset 和相关 CSS;
  • 删除 showHighlight()hideHighlight()showSelectionHighlights()hideSelectionHighlights() 中对工作台定位的调用;
  • 将仍有消费者的尺寸变化回调接入统一边界协调器;确认无消费者后连同契约参数和调用点一起删除;
  • 更新当前断言“元素内居中/元素旁停靠”的 Runtime View 与 E2E;不得同时保留新旧两套位置测试;
  • 清理被新 motion token 取代的重复 transition 字面量;只提取语义相同且多处消费的值;
  • 不保留 feature flag、旧定位回退或“双算法临时兼容”,因为该行为没有公共 API 兼容承诺。

删除前必须用 rg 证明无剩余生产引用;删除后执行 TypeScript、ESLint、单元测试、E2E、生产零残留和包验证。

14. 测试与验收矩阵

14.1 纯函数单元测试

  • 默认右下角锚点;
  • 自由位置、四边和四角吸附;
  • 不同表面尺寸共享锚点并选择稳定展开方向;
  • 极窄/极矮视口钳制;
  • viewport offset、缩放和 resize;
  • 非有限数、越界比例和异常尺寸拒绝或规范化;
  • 输入对象不被修改,输出不可变。

14.2 手势与生命周期单元测试

  • 未超过阈值是 click,超过阈值只提交 drag;
  • primary pointer、pointer capture、cancel、lost capture 和 blur;
  • 交互子元素不启动拖动;
  • 同一帧多次 pointermove 只写一次位置;
  • Escape 回滚未提交拖动;
  • dispose 后监听和 animation frame 为零;
  • 动画状态不改变 Runtime 状态。

14.3 Session 单元测试

  • 合法快照恢复;
  • 版本、枚举、有限数和范围校验;
  • 畸形 JSON、超限文本、Storage getter/setter 异常;
  • 不同 sessionId 隔离;
  • 拖动提交后写一次,pointermove 不写;
  • 清除 Selection Session 不清除位置。

14.4 Playwright E2E

  • 默认右下角截图和可访问名称;
  • 灵动岛 click 与 drag 分离;
  • 右下、左上、边缘和自由位置分别展开;
  • 选中屏幕四角元素、滚动和切换活动目标后工作台位置不变,高亮正确移动;
  • 展开面板通过标题栏拖动,表单输入和正文选择不触发拖动;
  • 刷新恢复、重启新 Session 回默认、重置位置;
  • 桌面、窄视口、触摸仿真、200% 缩放和动态视口;
  • prefers-reduced-motion 下无非必要位移/缩放;
  • 中文、英文、长组件名、长路径、Agent 长错误和折叠区展开后均不越界;
  • HMR 后只有一个控制器和一个 SpotPatch Root。

视觉截图只覆盖稳定关键状态,不为每个动画帧生成像素快照。动效通过最终几何、data 状态、计算样式和减少动画模式断言;禁止固定 sleep。

15. 实施顺序与阻断 Gate

P0:规范与基线

  • 收敛 UI 总规范、本文和 E2E 目标;
  • 记录当前桌面/窄屏截图、现有包体和相关测试;
  • 确认 runtime-view.ts、扩展回调和选择事件的实际依赖。

Gate:文档无冲突;现有质量门禁保持通过;不修改业务代码。

P1:纯位置与 Session

  • 实现位置纯函数和版本化位置存储;
  • 完成异常输入、边缘、四角、缩放和存储失败单测;
  • 暂不接入视觉动画。

Gate:纯模块无 DOM/业务依赖,测试覆盖所有边界。

P2:浮动控制器与旧代码替换

  • 接入 Pointer Events、标题栏手柄、帧合并和边界协调;
  • 工作台与目标几何解耦;
  • 删除旧 placement、anchor 和测试;
  • 完成桌面/窄视口功能 E2E。

Gate:拖动、选择、滚动和恢复全部确定;生产代码不存在旧目标定位分支。

P3:灵动岛视觉与动效

  • 建立状态投影、统一 motion token、展开/收起和拖动反馈;
  • 完成 reduced motion、焦点和双语;
  • 在完整 playground 进行人工视觉校准。

Gate:动画不驱动业务状态,不造成 hit area 偏移或焦点丢失。

P4:全量验收与文档收口

  • 运行 format、lint、typecheck、unit、compatibility、performance、E2E、production leakage、build 和 package validate;
  • 对新增 Runtime gzip 体积做现有门禁比较;
  • 更新本文 implementation-status、UI 总规范和当前实现证据;
  • rg、依赖检查和 coverage 审核未使用导出、CSS token、监听器及旧选择器。

Gate:全部 required checks 通过;没有未解释 skip、无消费者代码、重复状态或散落策略值。

16. 决策摘要

决策 结论 理由
默认位置 右下角 与当前入口一致,稳定且不改变宿主布局
用户位置 自由拖动并在边缘范围内吸附 兼顾自由度和常用停靠整齐度
工作台与目标 完全解耦 避免跳动和滚动布局测量;高亮继续表达关联
手势技术 Pointer Events + pointer capture 统一鼠标、触控笔和触摸输入
位置持久化 按 sessionId 隔离的 sessionStorage 与当前开发会话边界一致,不长期污染宿主
业务状态 复用现有 Runtime 状态机 不复制展开/选择状态
动画 CSS 状态投影,无第三方依赖 体积小、可降级、易支持 reduced motion
公共 API 首版不新增 位置是本地 UI 偏好,不需要进入协议或配置
旧目标定位 同变更删除 不保留无公共兼容承诺的双算法和死代码

当前仍需通过 playground 视觉验收确定的是具体尺寸、边距、吸附距离、手势阈值和动效曲线。这些属于集中令牌的校准,不影响位置模型、模块边界和测试策略;在真实浏览器验证前不得把建议值描述为最终视觉事实。