Archify 语义化 Story 载体(Semantic Story Carrier)设计与实现解析:让五类语义流 Token 沿精确关系流动
【免费下载链接】archifyAgent skill for beautiful, verifiable architecture, workflow, sequence,>项目地址: https://gitcode.com/GitHub_Trending/arch/archify
本篇技术文章围绕 Archify 项目可视化研究第 49 轮(Round 49)的决策文档 research-visual-evolution-round-49.md 展开:它记录了如何将第 48 轮(Round 48)引入的五类Semantic Flow Token(call / data / event / security / state)接入既有的 Story Beat 播放体系,形成"语义化 Story 载体"。读者读完本文后,将掌握 Archify 中关系身份去重的实现原理、Token 分类与几何构建的完整逻辑、?embed=1&play=1分享播放契约的边界,以及该方案在 template.html 中的真实落地点与对应测试。
一、决策背景:为什么要做"语义化 Story 载体"
Round 48 为 Archify 的Relationship Preview(关系预览)引入了五类语义流 Token:调用(call)、数据(data)、事件(event)、安全(security)、状态(state)。这些 Token 能沿着一条精确的关系路径(path、line或polyline)流动,直观表达"这条连线上流动的是什么语义载荷"。
但当时这五类 Token 只存在于直接关系检查的路径中,并未出现在项目的正式 Story 播放、README 证明面与 Gallery 分享面上。Round 49 的决策是:当一次有意的 Story 播放跨越一条精确的、由作者撰写的(authored)关系时,恰好一个匹配的 call/data/event/security/state Token 应沿这条精确关系流动一次,而 source route、marker、label、nodes、camera target、beat caption 与 Story Trail 全部保持不变。
决策文档明确把这一轮定位为比"再做一个 viewer 面板、minimap、风格预设、环境循环动画或新的 motion 持有者"更强的切片:它让项目的主要呈现面和 README 证明面,与直接关系检查讲的是同一种语义故事,同时先修复一个具体的身份(identity)缺陷。
二、现状与缺口:部件齐全但彼此不连通
决策文档指出,共享 viewer 中已经有正确的零件,但尚未汇合:
| 现有能力 | 位置(archify/assets/template.html) | 当前职责 |
|---|---|---|
relationshipTokenKind() | 第 7954 行起 | 将一条精确关系分类为 call/data/event/security/state,并给出确定性优先级 |
relationshipTokenGeometry() | 第 7995 行起 | 在 author 出的path/line/polyline几何上放置紧凑 Token |
storyStep()与pulseStoryStep() | 第 9702 行、第 9917 行起 | 构建有序 Story Beat 并驱动通用的 Story Trail 流动动画 |
storyMotionAllowed() | 第 9885 行起 | 拒绝一切 embed 中的 Story 运动,即使 URL 显式带?embed=1&play=1 |
followStoryStep() | 第 9998 行起 | 正确允许 embed 仅在data-share-playback="true"时推进相机与字幕 |
也就是说,运动权限的闸门两侧标准不一致:followStoryStep()已经支持显式分享播放,而storyMotionAllowed()却把 embed 全部拒绝;与此同时,Story 载体(carrier)本身尚不存在。
三、先修的身份缺陷:带标签关系被计为两条边
在考虑任何运动之前,还存在一个精确身份(exact identity)缺陷。源码中storyStep()会遍历每一个带边语义的 DOM 元素并逐个入列(template.html)。问题在于:带标签的关系既会作为可绘制的 route 被渲染,又会作为 context label group 被渲染,两者拥有相同的data-edge-key。
在当前的 Agent Tool Call Gallery 产物中,11 个关系键里有 5 个出现两次(1、3、5、9、10)。例如happy-path故事包含chat → planner,其作者关系键为1;于是这条关系的 route 与 label group 被计数为两条"边",被分类为multiple,进而被既有的step.edges.length === 1脉冲闸门排除。而源 JSON 明确证明这是一条关系(ID 为plan-request),并非两条平行关系。
权威本地证据:
- Agent Tool Call story 源文件
- 编译后的 Agent Tool Call 产物
- 共享 Story Beat 实现
因此决策文档给出的第一个实现动作必须是:在判定forward、reverse或multiple之前,先按data-edge-key对语义边记录去重,而不是用放宽成>= 1的运动条件来掩盖 bug。这一点在 story-carrier.test.mjs 第 47-55 行有专门测试,断言模板中存在uniqueStoryEdges(forward)、uniqueStoryEdges(reverse)以及edges.length === 1 && forward.length === 1 ? 'forward'的精确逻辑。
四、主源对比:三条可借鉴的外部实现路径
决策文档对照了三个公开实现,明确"借什么、怎么改、跳过什么":
1. Fireworks Tech Graph:载体属于路线且故障时关闭(fail closed)
其官方运动契约在节点、标签、容器、marker、几何与相机全部固定的前提下,让连接器运动遵循语义顺序。场景使用可识别的、路线所属的载体(Blueprint 注册珠、Notion 记忆卡),均派生自源路径;重复的语义角色通过精确的(role, stage, order)身份独立寻址;剥离运动元数据后还原出相同的静态几何。
Borrow:一个有意义载体运行在精确且不可变的源路线上;路线身份不明确时故障关闭。Adapt:Archify 已有更稳定的data-edge-key/可选关系 ID 与五种跨渲染器 Token,直接复用,而非引入 Fireworks 的场景元数据矩阵。Skip:5.75 秒无限循环 GIF 操作、按风格的时间表、新媒体格式、环境载体流与复制的签名几何。
2. React Flow(xyflow):运动对象与可见边共享同一条计算路径
其一等公民 Animating Edges 示例渲染普通BaseEdge,并把同一条edgePath传给 SVG<animateMotion>载体。路径是唯一事实来源,运动只是相邻的视觉层,而不是第二条路线计算。
Borrow:把载体绑定到已编译的精确路径上。Adapt:复用既有有限 Token 词表,放进 Story 既有的 780 ms 精确边脉冲,而不是示例里无限循环的通用圆。Skip:React 运行时、可编辑节点状态、重复路径计算、无限重复、整节点沿边移动。
3. AntV G6:载体可以是边拥有的子形状,但生命周期必须明确
其 fly-marker 示例把 marker 建为精确边的子形状,并把该边的 key shape 作为offsetPath;其 path-in 示例则展示一个有界路径揭示动画,显式 500 ms 时长并保留结束状态。
Borrow:让移动标记归精确关系几何所有,并显式声明生命周期。Adapt:每个被选中的 Story Beat 至多一个载体,配 Archify 既有的清理逻辑与运动治理器(motion governor)。Skip:图运行时、自定义边注册表、无限迭代与持久 ant-line/fly-marker 装饰。
五、Borrow / Adapt / Skip 决策总表
| 决策 | Round 49 边界 |
|---|---|
| Borrow | 一个可识别的载体沿一条精确不可变路线行进;载体与可见关系使用同一条路径与作者方向。 |
| Adapt | 复用 Round 48 的五类 Token 种类与几何,放进当前 Story 持有者;允许出现在普通产物中,且只允许出现在已显式的data-share-playback=trueembed 契约中。 |
| Adapt | 在判定方向或多重性之前,先把 Story Beat 的边归一化为每个稳定data-edge-key一条语义记录。 |
| Adapt | 对 group/no-edge 与真正的平行边 Beat 保留通用静态 Story Trail 与字幕;运动必须故障关闭,而不是任意选择。 |
| Skip | 新增 schema 字段、场景角色、Token 选择器、工具栏控件、依赖、布局 pass、渲染器专属播放代码或独立 timer/owner。 |
| Skip | 被动 embed 中的运动、无play=1的页面加载运动、精确时刻链接、Still/减弱运动/隐藏/打印/导出状态、移动端专属行为。 |
| Skip | 无限循环、多边同步载体、随机路径选择、标签文本推断、相机/背景/节点运动、canonical SVG 残留。 |
六、提议契约:九条边界,逐条落地到源码
决策文档提出 9 条契约,当前 template.html 中大部分已可直接对应到实现:
共享辅助函数:把 Token 分类与几何抽成一个共享运行时 helper。Relationship Preview 与 Story 播放调用同一个 helper,不复制五个 Token 分支。→ 源码中的
relationshipTokenKind()/relationshipTokenGeometry()与Archify.flowTokens导出(第 8042-8046 行)正是这条契约的实现。每个
data-edge-key一条语义记录:保留第一条真实可绘制 route 及其作者方向、wrapper transform、可选关系 ID、标签与类型证据;context label group 只是该记录的注解,不是额外关系。→ 实现为uniqueStoryEdges()(第 9686-9700 行):它用storyEdgeKey()建立去重表,且当已有记录没有可绘制几何、而新元素有几何时,用新元素替换(!storyGeometry(unique[index]).length && storyGeometry(edge).length)。Story Beat 只有去重结果恰好包含一条 forward 或一条 reverse 作者关系时才可携带载体。→
pulseStoryStep()第一行闸门:step.relation !== 'forward' && step.relation !== 'reverse' || step.edges.length !== 1时直接返回 false(第 9919 行)。Token 永远沿关系的作者 source→target 方向行进;故事顺序若反向访问端点,仍使用 reverse-caption 契约,但不得在视觉上反转作者流量。→ 方向分类在
storyStep()中按data-edge-from/data-edge-to判定,caption 方向文案另有storyCaptionRouteCopy()。启动一个合格 Beat 至多添加一个位于节点与标签之下的 story-only 载体,使用既有 780 ms 有限脉冲与当前 owner generation,不创建独立 claim/interval/无限动画。→
pulseStoryStep()调用Archify.flowTokens.create(edge, shapes[0], { className: 'story-flow-token', duration: '0.78s' }),并把animateMotion的dur设为 0.78s(relationshipTokenGeometry第 8023 行);载体包在data-story-carrier-overlay分组中,插入到首个[data-node-id]之前,即节点/标签之下。普通完整产物在 Live 下允许载体;embed 仅在
data-embed=true且data-share-playback=true(即显式?embed=1&play=1契约)时允许;被动 embed 与精确时刻链接保持静态。→storyMotionAllowed()(第 9885-9892 行)逐条实现:data-motion !== 'live'拒绝、data-embed === 'true'且无data-share-playback拒绝、打印态拒绝、motion governor 暂停拒绝。Beat 替换、暂停、Stop/Still、减弱运动、文档隐藏、手动导航、打印、导出、章节切换、播放完成都要同步移除载体;过期的
animationend回调不能清掉或释放更新的 Story owner。→clearStoryPulse()通过storyPulseGeneration代际计数 +storyPulseOwnerTokenowner token 实现(第 9901-9915 行),animationend回调只在本代pulseGeneration === storyPulseGeneration时才清理(第 9954-9956 行)。静态含义永不依赖 Token:Story Trail、beat caption、活动节点、路线方向文案与 settled 边强调在无运动时保持完整。→ 所有 caption 生成(
storyBeatCopy/storyBeatAria/storyCaptionRouteCopy)与载体解耦,可独立运行。不新增移动端专属产品工作:窄布局只继承同一套静态回退;桌面呈现与文档 embed 是目标面。
七、风险与缓解:把"想当然"逐条堵死
| 风险 | 缓解 |
|---|---|
| 标签组被计为第二条关系 | 按稳定data-edge-key去重;在五种渲染器上测试带标签与不带标签的边。 |
| 两条真实平行边共享端点 | 保留不同 key 并把 Beat 分类为multiple;不展示任意载体。 |
| 反向故事顺序歪曲数据方向 | 只沿作者 source→target 几何动画,并保留显式反向文案。 |
| 载体比 Beat 活得更久、或清掉更新的 Beat | 把 overlay 清理绑定到 Story generation/owner token,并拒绝过期回调。 |
| README embed 变成环境动画 | 只允许既有的显式play=1请求;被动 embed、时刻链接、Still、减弱运动保持静态。 |
| Token 与通用 trail 视觉竞争 | 只一个 Token、780 ms、位于节点/标签之下;不增加虚线流或辉光族。 |
| 运行时装饰泄漏进导出 | 在 canonical SVG/位图序列化与打印前,同步剥离 story-carrier overlay 与运行时属性。 |
八、验收标准:可验证的十一项
决策文档给出 11 条验收标准,其中若干条已由 story-carrier.test.mjs 直接验证(第 36-45 行测试确认五种渲染器都继承同一份 viewer-only carrier、产物 canonical SVG 中无story-flow-token/story-carrier-token/semantic-flow-token残留):
- 五种类型化渲染器通过共享模板继承同一套 Story Carrier 实现,无渲染器私增播放分支;
- 含一条带标签关系的 fixture 产生两个语义 DOM 片段,但解析为一个 Story 关系键、一个 forward/reverse Beat、至多一个 Token;
- 两条真正不同的平行关系键保持
multiple且不产生载体; - call/data/event/security/state Beat 使用与 Relationship Preview 完全相同的确定性分类优先级与 SVG 形状;
- 覆盖
path/line/polyline路线、wrapper transform、弯曲路线、垂直路线与作者反向; - Token 只在 Beat 有意推进或作为显式播放的一部分被激活时才开始;hover、focus、URL 恢复、钉住的时刻都不重启它;
- 单个 Token 有限(780 ms)、位于节点/标签之下,并在动画结束、暂停、替换、章节切换、完成、文档隐藏、Still、减弱运动、打印、导出后消失;
?embed=1&play=1可见地推进 Story Carrier;?embed=1与#view=...&beat=...保持静态;分享播放中切到 Still 移除 Token 且不改变真实的活动 Beat;- canonical SVG 与位图/导出快照不含载体元素、
animateMotion、Story owner 残留、运行时 Token kind 或运行时 edge key; - 浏览器验证至少覆盖:Workflow Signal Flow 深色(带标签的 call/security Beat)、Architecture 或 Data Flow(弯曲/垂直路线上的 data/event 载体)、Lifecycle(state 载体)、Blueprint 浅色(无辉光锐利 Token)、显式 README/Gallery 分享 embed 与被动 embed 及 Still 切换、零 console 错误与每次有限 pass 后零运行时 overlay;
- 聚焦的 Story/relationship/motion/export 测试、全部 11 个 Gallery 产物、composition 检查、完整
npm test与git diff --check保持绿色。
九、为什么这不是重复范围
决策文档专门澄清了与历史轮次的关系:
- Round 13 添加了Story Trail:用通用路线 overlay 解释有序拓扑,并不分类 Beat 上流动的载荷;
- Rounds 16、37、38、39、41 添加了 beat 顺序、相机跟随、导演文案、未来上下文与 settled 交接,都不复用关系类型载体;
- Round 48 的Semantic Flow Tokens 只存在于直接 Relationship Preview,其自身 embed 防护阻止它们进入主要 story/share 证明路径;
- Round 49 不新增任何作者事实、阅读模式、控件、面板、相机规则或 motion owner,它修复关系身份,并让两个已上线的系统共享同一套精确语义视觉词表。
十、结论与推荐
以Semantic Story Carrier作为 Round 49 推进:先通过把 DOM 片段去重为稳定关系键,让 Story Beat 边身份回归真实;再复用(而非克隆)Round 48 的 Token 构建器放进既有有限 Story owner;仅在完整桌面产物与已显式的?embed=1&play=1分享契约中允许载体。这是一个实现面很小、产品效果超比例的切片——图表的形式化 Story、README 证明与直接探索终于讲同一种视觉语言。读者可在 template.html 的relationshipTokenKind、uniqueStoryEdges、pulseStoryStep、storyMotionAllowed四处对照本文的契约逐条验证,并以 story-carrier.test.mjs 为入口运行聚焦测试复现全部断言。
【免费下载链接】archifyAgent skill for beautiful, verifiable architecture, workflow, sequence,>项目地址: https://gitcode.com/GitHub_Trending/arch/archify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考