Archify 语义相机Semantic Camera让读者语义意图拥有取景框的 viewer-only 视口引擎【免费下载链接】archifyAgent skill for beautiful, verifiable architecture, workflow, sequence,>项目地址: https://gitcode.com/GitHub_Trending/arch/archify导读本文深入解析 ArchifyAgent skill用于生成自包含 HTML 的架构/工作流/时序/数据流/生命周期图在视觉演化第十二轮引入的Semantic Camera语义相机一个只存在于 viewer 运行时、不进入图数据模型的语义取景机制。它把读者想看的语义对象被聚焦的节点、被选中的关系、被播放的引导视图映射为精确的视口平移与缩放让意图获得真正的取景框。读完本文你将理解它的边界设定、getBBoxviewBox几何映射原理、one-hop 冻结种子集、手动交互让位协议、移动端 contained scroll 模型以及它如何通过一份契约测试同时覆盖五类渲染器。读者问题语义意图没有取景框在引入语义相机之前Archify 已经能够选中节点、为关系命名、播放引导视图guided views但桌面端reveal()返回后视口纹丝不动。在 Presentation Stage 下高而密的图会一直停留在 overview 缩放下居中显示——哪怕读者真正关心的只有四个节点。文档给出的诊断很直接The system knew the readers semantic intent but did not give that intent the frame.系统知道读者的语义意图却没有把取景框给到这份意图。这正是本轮演化的出发点语义选中 ≠ 视觉可见二者之间缺少一座桥。借鉴自成熟图可视化库的模式在动手之前团队考察了四个主流图可视化方案的视口操控设计作为模式参考均记载于 docs/research-visual-evolution-round-12.md参考来源借鉴点G6focusElement以一个或多个语义元素 ID 为中心支持有边界的视口动画G6 FocusElement 行为聚焦与拖拽、缩放行为分离可配置时长与缓动React FlowFitViewOptions把选中节点、padding、最小/最大缩放、时长、缓动、插值打包成一个显式的相机契约Cytoscape.js 视口操控将fit、center、pan/zoom、动画视口操作分离而不是去改动模型的坐标这些是值得借鉴的模式而非照搬的实现——下一节的边界设定说明了 Archify 如何只取所需。Archify 边界viewer-only 的语义相机文档明确划定了本轮的交付边界新增一个语义的、仅存在于 viewer 的相机——不做自动布局auto-layout、不移动节点、不引入图运行时graph runtime。相机是解释语义选择的编译产物内行为绝不成为图数据的来源真相source of truth。边界内的九条核心规则如下几何唯一来源是作者产出的 SVG已编译 SVG 的getBBox()值是唯一的几何数据源语义相机把它们并集union经过当前viewBox与preserveAspectRatioletterboxing 映射到视口。节点聚焦取景的是冻结的 one-hop 种子集绝不是不断扩张传递闭包的连通分量。关系遍历与 Finder 选择取景新节点的一跳邻域one-hop neighborhood。引导视图精确取景其作者节点48px 基础 padding、2.15× 放大上限、480ms ease-out 过渡。Relationship Lens 保留左侧安全区选中的节点不会落到面板下方。重置控件仅在语义取景真的放大超过 100% 时才显示AUTO。手动缩放或拖拽会停掉相机并暂停引导播放Show all 与 Escape 恢复完整 100% overview。720px 及以下变换归一化到 100%宽图保留既有的 contained 水平滚动模型用户在程序化滚动稳定后的滑动会暂停播放。prefers-reduced-motion去掉过渡Presentation Stage 在自身布局变化后重新取景。此外相机模式只活在 HTML 容器上SVG 导出时剥离 transform 与data-view-scale任何相机状态与坐标都不进入 artifact。实现上要求一份实现 一份契约测试同时覆盖 architecture、workflow、sequence、data-flow、lifecycle 五类渲染器。实现解剖从语义种子到取景框相机实现在 viewer 运行时模板 archify/assets/template.html 的视口模块中核心函数链为reveal()→frameDesktop()/ 移动端分支 →semanticIds()→boxesFor()→cameraReceipt()事务动画。下面按数据流逐层拆解。5.1 几何的唯一来源getBBox viewBox 映射文档规则第 1 条在源码中有直接对应。frameDesktop开头template.html#L11617-L11635先计算 SVG 内容在容器里的实际布局var contentScale Math.min(svgWidth / viewBox.width, svgHeight / viewBox.height); var contentOffsetX (svgWidth - viewBox.width * contentScale) / 2; var contentOffsetY (svgHeight - viewBox.height * contentScale) / 2;contentScale正是preserveAspectRatioletterboxing 下的等比缩放因子contentOffsetX/Y是居中留白偏移。随后每个目标节点的getBBox()逻辑坐标乘以contentScale、加上偏移就得到屏幕坐标下的语义包围盒并集bounds。契约测试 archify/test/semantic-camera.test.mjs#L41 显式断言了这段公式的存在确保仅从作者 SVG 几何出发这一约束不会被后续改动破坏。5.2 冻结 one-hop 种子集semanticIds规则第 2、3 条的落点。semanticIds(ids, includeNeighbors)template.html#L11595-L11607用一个局部seeds对象先冻结传入的种子 ID再只做一轮边遍历(ids || []).forEach(function (id) { seeds[id] true; wanted[id] true; }); if (includeNeighbors) { Array.prototype.forEach.call(svg.querySelectorAll([data-edge-from][data-edge-to]), function (edge) { var from edge.getAttribute(data-edge-from); var to edge.getAttribute(data-edge-to); if (seeds[from] || seeds[to]) { wanted[from] true; wanted[to] true; } }); }关键在只检查seeds[from] || seeds[to]而不是wanted[from] || wanted[to]。这保证邻域集合是以原始种子为中心的冻结一跳绝不会像第一版那样沿边不断扩张成整个连通分量详见第 6 节缺陷 1。boxesFortemplate.html#L11608-L11616再据此过滤[data-node-id]节点并取getBBox()。5.3 frameDesktop从包围盒到目标取景frameDesktop(ids, options)template.html#L11617-L11716是桌面端核心参数契约如下与文档规则 4、5 一一对应参数/常量值说明源码出处padding默认48取景安全边距底部额外保留Math.max(padding, 72)maxScale2.15含邻居时1.9放大上限template.html#L11661缩放系数* 0.9留出取景余量下限阈值 1.08时归1近乎 1× 的取景直接回落到 100%duration默认420夹取[180, 520]动画时长ms缓动eased 1 - Math.pow(1 - fraction, 3)三次方 ease-out取景前还要处理两处避让一是Relationship Lens 左侧安全区——当#focus-chip可见时左边界被推至Math.max(left, Math.min(svgWidth * 0.42, lensEnd))template.html#L11648-L11652即选中节点不会藏到语义透镜面板之下二是可见视口感知——通过container.getBoundingClientRect()计算visibleTop/visibleBottom当可见高度 ≥ 240px 时把取景范围收束到当前可见区域内template.html#L11641-L11647这正是文档所说Presentation Stage 重新取景的地基布局变化后 resize 监听触发syncSemantic()template.html#L11806-L11813。动画由cameraReceipt()事务对象驱动template.html#L11480-L11510带单调递增id、finishedPromise、可cancel(reason, commitTarget)运行中在容器上打is-camera-moving/data-camera-transaction标记。instant分支options.instant、reducedMotion()、document.hidden任一为真直接落位并立即结算事务template.html#L11677-L11683。5.4 移动端contained scroll 而非叠加缩放reveal(ids, options)template.html#L11717-L11752按window.innerWidth 720分派桌面走frameDesktop≤720px 一律先把scale/x/y归一化为 1、mode: semantic规则 8。非宽图直接结算一个{scale:1,x:0,y:0}语义事务宽图data-wide-diagram则取目标包围盒中心换算成scrollLeft用container.scrollTo({left, behavior: instant ? auto : smooth})水平滚动template.html#L11732-L11751。程序化滚动有保护窗口autoScrollUntil Date.now() (instant ? 50 : 470)。onScrolltemplate.html#L11765-L11771只有同时满足≤720px 宽图 Date.now() autoScrollUntil才调用interruptCamera()——即只有用户自己滑动才会中断相机并暂停播放程序化滚动不会误伤。契约测试 semantic-camera.test.mjs#L70-L78 逐条断言了这套归一化与滚动时序。5.5 手动交互的让位协议规则 7 的实现是interruptCamera(reason)template.html#L11524-L11540取消进行中的相机事务、采样当前渲染状态转mode: manual、Archify.guidedViews.pause()、暂停 Route Journey。它由三类入口触发缩放/重置zoom()与reset()在options.manual ! false时先interruptCamera()template.html#L11541-L11562缩放被夹在1…3、步进 0.25。拖拽容器pointerdown监听template.html#L11787-L11793在state.scale 1、左键且未命中交互浮层时接管相机开始拖拽平移diagram-nav、focus-chip、node-finder、diagram-guide、overview-map、route-probe、semantic-lens等浮层命中会被显式排除避免与面板内交互冲突。路由等后续功能Route Probe、Radar、Story 等模块的reveal调用统一走Archify.view.reveal(...)例如 template.html#L12281-L12282、template.html#L12663-L12664保证最新语义意图赢、手动操作随时接管。reset()Show all / Escape把状态恢复为{scale:1, x:0, y:0, mode:overview}当它是被相机器自动调用时走stopCameraMotion(reset, false)而非中断template.html#L11556-L11562避免播放流程自身重置视口时互相打断。5.6 控件与语义指示AUTO只在真的放大时出现规则 6 落在renderControls()template.html#L11376-L11403var semantic state.mode semantic state.scale 1.01;仅当语义取景实际放大超过 100%1.01时重置标签才显示AUTOi18n 文案viewer.nav.level.auto并把data-camera-indicatortrue打到容器上否则回退到 map/read/full 的常规 detail 标签。data-camera-mode与data-camera-indicator两个容器属性同时服务于样式与契约测试断言semantic-camera.test.mjs#L45-L46。细节密度detailLevel()也与相机联动语义取景时直接视为fulltemplate.html#L11370-L11375。视觉上取景时还叠加clipToViewport的inset()clip-pathtemplate.html#L11404-L11420防止放大时边缘内容溢出容器。5.7 reduced motion 与 Presentation Stage 重取景规则 9 的两条都在源码中有直接对应reducedMotion()用matchMedia((prefers-reduced-motion: reduce))检测template.html#L7138-L7140frameDesktop里instant分支因此直接落位并跳过动画template.html#L11677-L11683CSS 侧media (prefers-reduced-motion: reduce)强制svg [data-node-id] ... { transition: none !important; }该选择器由测试 semantic-camera.test.mjs#L77 断言。而 Presentation Stage 在布局变化后重取景依靠的是 resize 监听里if (state.mode semantic) syncSemantic();的分支template.html#L11806-L11813——相机处于语义模式时布局变化自动按当前语义焦点重新取景。5.8 导出洁净相机状态永不进入 artifact规则的最后一条同样可验证。apply()每次更新都会svg.setAttribute(data-view-scale, String(state.scale))并写入style.transformtemplate.html#L11437-L11450但导出路径canonical SVG/raster会显式剥离clone.style.removeProperty(transform)、clone.removeAttribute(data-view-scale)template.html#L5854-L5856。契约测试第 4 条semantic-camera.test.mjs#L80-L86用doesNotMatch断言导出的svg中不存在transform、data-view-scale、data-camera-mode。CHANGELOG 里同样强调embed/print/canonical SVG 导出保持干净无 schema、IR、布局或依赖变更CHANGELOG.md#L123。浏览器实测驱动的三项修正文档专门用一节记录静态契约测不出来的三个缺陷它们全部来自真实浏览器运行是语义相机最有价值的经验沉淀可变邻居集把 one-hop 扩张成整个连通分量。第一版用可变的wanted集合做邻域扩散一跳聚焦最终把整张图都框了进去冻结原始种子 ID5.2 节的seeds才恢复语义对等。桌面 Show all 被非用户的容器滚动事件误标为manual。修复后手动滚动接管被限制在窄屏宽图这一唯一表面即 5.4 节的autoScrollUntil保护窗口。桌面 transform 在桌面→移动resize 后残留。窄屏reveal现在会先归一化 scale 与 translation再做水平定位5.4 节的移动端分支保证 resize 后不出现缩放与滚动叠加的脏状态。这三条修正也被固化为契约测试断言semantic-camera.test.mjs#L54-L78例如断言semanticIds的种子冻结逻辑、reset({ automatic: true })、autoScrollUntil Date.now() (instant ? 50 : 470)等精确表达式。一个实现五类渲染器共用一份契约测试文档规则最后一条一份实现 一份契约测试覆盖全部五种图类型在测试中有完整落地。archify/test/semantic-camera.test.mjs 的CASES把五种模式映射到各自示例渲染器示例输入architectureweb-app.architecture.jsonworkflowagent-tool-call.workflow.jsonsequencecache-miss-request.sequence.jsondataflowproduct-analytics.dataflow.jsonlifecycleagent-run.lifecycle.json测试用execFileSync依次调用 renderers/architecture/render-architecture.mjs、renderers/workflow/render-workflow.mjs、renderers/sequence/render-sequence.mjs、renderers/dataflow/render-dataflow.mjs、renderers/lifecycle/render-lifecycle.mjs 渲染真实示例再对产物 HTML 做正则断言——例如frameDesktop、semanticIds、data-camera-mode、is-camera-moving、ease-out 的cubic-bezier(0.22, 1, 0.36, 1)必须同时出现在五份产物里而导出的svg中不得出现任何相机痕迹semantic-camera.test.mjs#L35-L52。这正是跨渲染器几何中立的同一份语义相机的机器可验证保证。刻意不借鉴的部分文档最后一节明确列出边界Archify不引入滚轮缩放wheel zoom、惯性物理inertial physics、小地图minimap、可编辑节点位置editable node positions也不把相机模型持久化进 JSON。相机只在编译产物内解释语义选择永远不会成为图的来源真相。这套少即是多的取舍让语义相机能作为 viewer-only 引擎长期服务于后续迭代——后续的 Story Follow Camera、Chapter Handoff、Route Journey 等能力都以Archify.view.reveal(...)为统一取景入口见 CHANGELOG.md#L106-L131 与后续轮次 docs/research-visual-evolution-round-30.md。如何在仓库中验证与体验直接查看渲染产物五种类型的渲染结果已提交在 archify/examples 下如 web-app-rendered.html、workflow-agent-tool-call-rendered.html、sequence-cache-miss-request.html、dataflow-product-analytics.html、lifecycle-agent-run.html用浏览器打开即可体验节点聚焦、关系遍历与引导播放的取景动画。运行契约测试在archify/目录执行node --test test/semantic-camera.test.mjs四组测试会真实渲染五类示例并校验相机行为与导出洁净性。阅读实现全部相机逻辑集中在 archify/assets/template.html 视口模块约 L11350-L11829是后续所有取景类能力的公共地基本轮完整决策记录见 docs/research-visual-evolution-round-12.md。【免费下载链接】archifyAgent skill for beautiful, verifiable architecture, workflow, sequence,>项目地址: https://gitcode.com/GitHub_Trending/arch/archify创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
