@ray-js/robot-map-sdk 0.0.14-beta.2 → 0.0.14-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/bin/mcp-server.js +1 -1
  2. package/dist/constant/methods.js +1 -1
  3. package/dist/index.d.ts +225 -207
  4. package/dist/index.rjs.js +1 -1
  5. package/dist-app/assets/{index-BdM8mVW2.js → index-DKS25OWM.js} +1 -1
  6. package/dist-app/index.html +1 -1
  7. package/dist-docs/404.html +2 -2
  8. package/dist-docs/assets/{app.B-cJvUCw.js → app.DkbwKXWW.js} +1 -1
  9. package/dist-docs/assets/chunks/@localSearchIndexroot.Bl2MTYXJ.js +1 -0
  10. package/dist-docs/assets/chunks/{BitmapFont.CqQVBHFj.js → BitmapFont.Ksg_-Wh2.js} +1 -1
  11. package/dist-docs/assets/chunks/{BufferResource.B2VSGaWU.js → BufferResource.B5f5z3Gf.js} +1 -1
  12. package/dist-docs/assets/chunks/{CanvasRenderer.CZO0PMWy.js → CanvasRenderer.RJyTOkK-.js} +1 -1
  13. package/dist-docs/assets/chunks/{RenderTargetSystem.p9lXtNJj.js → RenderTargetSystem.CzrROK4J.js} +1 -1
  14. package/dist-docs/assets/chunks/{VPLocalSearchBox.D1PfgbSt.js → VPLocalSearchBox.BaVzW47p.js} +1 -1
  15. package/dist-docs/assets/chunks/{WebGLRenderer.0K1DT-Es.js → WebGLRenderer.BH_y7OeB.js} +1 -1
  16. package/dist-docs/assets/chunks/{WebGPURenderer.COUGZ4Th.js → WebGPURenderer.gl7aEJfn.js} +1 -1
  17. package/dist-docs/assets/chunks/{browserAll.C5bQpkD7.js → browserAll.DPzB7yA8.js} +1 -1
  18. package/dist-docs/assets/chunks/{index.C-AiaySA.js → index.DSHMgZlq.js} +5 -5
  19. package/dist-docs/assets/chunks/{theme.C-O3vTBh.js → theme.KfweDRuA.js} +3 -3
  20. package/dist-docs/assets/chunks/{webworkerAll.EzKpjJ2M.js → webworkerAll.CFniL2R0.js} +1 -1
  21. package/dist-docs/assets/{guide_getting-started.md._t5bADoD.js → guide_getting-started.md.BoT_seGX.js} +2 -2
  22. package/dist-docs/assets/guide_getting-started.md.BoT_seGX.lean.js +1 -0
  23. package/dist-docs/assets/plans_2026-03-10-testing-rollout-next-steps-plan.md.CGR6uZic.js +17 -0
  24. package/dist-docs/assets/plans_2026-03-10-testing-rollout-next-steps-plan.md.CGR6uZic.lean.js +1 -0
  25. package/dist-docs/assets/records_plans_2026-03-05-testing-infrastructure-design.md.DLHGz5Ez.js +77 -0
  26. package/dist-docs/assets/records_plans_2026-03-05-testing-infrastructure-design.md.DLHGz5Ez.lean.js +1 -0
  27. package/dist-docs/assets/{reference_callbacks.md.BIwuGR3s.js → reference_callbacks.md.DdQU431C.js} +2 -2
  28. package/dist-docs/assets/{reference_callbacks.md.BIwuGR3s.lean.js → reference_callbacks.md.DdQU431C.lean.js} +1 -1
  29. package/dist-docs/guide/advanced-usage.html +3 -3
  30. package/dist-docs/guide/concepts.html +3 -3
  31. package/dist-docs/guide/getting-started.html +5 -5
  32. package/dist-docs/guide/mcp.html +3 -3
  33. package/dist-docs/hashmap.json +1 -1
  34. package/dist-docs/index.html +3 -3
  35. package/dist-docs/plans/2026-03-04-detected-objects-visibility-design.html +3 -3
  36. package/dist-docs/plans/2026-03-04-show-detected-objects-implementation-plan.html +3 -3
  37. package/dist-docs/plans/2026-03-10-simulator-debug-design.html +3 -3
  38. package/dist-docs/plans/2026-03-10-simulator-events-console-design.html +3 -3
  39. package/dist-docs/plans/2026-03-10-simulator-events-console-implementation-plan.html +3 -3
  40. package/dist-docs/plans/2026-03-10-simulator-runtime-controls-design.html +3 -3
  41. package/dist-docs/plans/2026-03-10-simulator-runtime-controls-implementation-plan.html +3 -3
  42. package/dist-docs/plans/2026-03-10-testing-rollout-next-steps-plan.html +41 -0
  43. package/dist-docs/plans/2026-03-11-simulator-logger-dump-implementation-plan.html +3 -3
  44. package/dist-docs/records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.html +3 -3
  45. package/dist-docs/records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.html +3 -3
  46. package/dist-docs/records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.html +3 -3
  47. package/dist-docs/records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.html +3 -3
  48. package/dist-docs/records/bugs/2026-03-11-docs-server-bin-clean-bugfix.html +3 -3
  49. package/dist-docs/records/bugs/2026-03-11-render-result-runtime-sync-bugfix.html +3 -3
  50. package/dist-docs/records/plans/2026-03-02-furniture-feature-plan.html +3 -3
  51. package/dist-docs/records/plans/2026-03-05-testing-infrastructure-design.html +101 -0
  52. package/dist-docs/records/plans/2026-03-10-simulator-events-console-plan.html +3 -3
  53. package/dist-docs/records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.html +3 -3
  54. package/dist-docs/records/plans/2026-03-10-simulator-map-parsed-view-plan.html +3 -3
  55. package/dist-docs/records/plans/2026-03-10-simulator-map-playground-refactor-plan.html +3 -3
  56. package/dist-docs/records/plans/2026-03-10-simulator-playground-plan.html +3 -3
  57. package/dist-docs/records/plans/2026-03-10-simulator-runtime-controls-plan.html +3 -3
  58. package/dist-docs/records/plans/2026-03-11-docs-cli-ui-polish-plan.html +3 -3
  59. package/dist-docs/records/plans/2026-03-11-simulator-logger-dump-plan.html +3 -3
  60. package/dist-docs/records/plans/2026-03-11-simulator-src-migration-implementation.html +3 -3
  61. package/dist-docs/records/plans/2026-03-11-simulator-src-migration-plan.html +3 -3
  62. package/dist-docs/records/plans/2026-03-11-simulator-style-tokenization-plan.html +3 -3
  63. package/dist-docs/reference/callbacks.html +5 -5
  64. package/dist-docs/reference/config.html +3 -3
  65. package/dist-docs/reference/data.html +3 -3
  66. package/dist-docs/reference/methods.html +3 -3
  67. package/dist-docs/reference/runtime.html +3 -3
  68. package/dist-docs/reference/types.html +3 -3
  69. package/dist-docs/reference/utils.html +3 -3
  70. package/dist-docs/simulator/index.html +3 -3
  71. package/package.json +8 -3
  72. package/dist-docs/assets/chunks/@localSearchIndexroot.CrYZjrrp.js +0 -1
  73. package/dist-docs/assets/guide_getting-started.md._t5bADoD.lean.js +0 -1
@@ -9,9 +9,9 @@
9
9
  <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
10
  <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/assets/app.B-cJvUCw.js"></script>
12
+ <script type="module" src="/assets/app.DkbwKXWW.js"></script>
13
13
  <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/assets/chunks/theme.C-O3vTBh.js">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.KfweDRuA.js">
15
15
  <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
16
  <link rel="modulepreload" href="/assets/plans_2026-03-10-simulator-events-console-design.md.BVmEzCbR.lean.js">
17
17
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
@@ -26,7 +26,7 @@
26
26
  <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> payload</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> unknown</span></span>
27
27
  <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> summary</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
28
28
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="field-purpose" tabindex="-1">Field purpose <a class="header-anchor" href="#field-purpose" aria-label="Permalink to &quot;Field purpose&quot;">​</a></h3><ul><li><code>id</code>: stable render key.</li><li><code>name</code>: the exact callback name shown to developers.</li><li><code>timestamp</code>: raw sort and copy value.</li><li><code>timeLabel</code>: readable time for the list.</li><li><code>payload</code>: full callback payload used for JSON expansion and copy.</li><li><code>summary</code>: concise text for the collapsed row.</li></ul><h2 id="event-source-strategy" tabindex="-1">Event source strategy <a class="header-anchor" href="#event-source-strategy" aria-label="Permalink to &quot;Event source strategy&quot;">​</a></h2><p>The simulator must not infer events from UI state. It should record only what <code>MapApplication</code> actually emits.</p><p>Use wrapped SDK callbacks when creating or updating the map instance:</p><ul><li>inject a recorder-backed <code>events</code> object into the SDK config</li><li>let the SDK invoke callbacks normally</li><li>append a record to the event store inside each callback wrapper</li></ul><p>This guarantees the console reflects the real public API surface rather than a simulator-specific approximation.</p><h2 id="events-panel-behavior" tabindex="-1">Events panel behavior <a class="header-anchor" href="#events-panel-behavior" aria-label="Permalink to &quot;Events panel behavior&quot;">​</a></h2><p>The <code>Events</code> panel is a compact developer console.</p><h3 id="toolbar" tabindex="-1">Toolbar <a class="header-anchor" href="#toolbar" aria-label="Permalink to &quot;Toolbar&quot;">​</a></h3><p>The header includes:</p><ul><li>callback filter</li><li><code>Pause</code></li><li><code>Clear</code></li><li><code>Copy JSON</code></li></ul><h3 id="list-rows" tabindex="-1">List rows <a class="header-anchor" href="#list-rows" aria-label="Permalink to &quot;List rows&quot;">​</a></h3><p>Each row shows:</p><ul><li>callback name</li><li>event time</li><li>summary line</li><li>expand or collapse control for payload JSON</li></ul><h3 id="empty-state" tabindex="-1">Empty state <a class="header-anchor" href="#empty-state" aria-label="Permalink to &quot;Empty state&quot;">​</a></h3><p>Show a single neutral message:</p><ul><li><code>No SDK callbacks yet</code></li></ul><h3 id="capacity" tabindex="-1">Capacity <a class="header-anchor" href="#capacity" aria-label="Permalink to &quot;Capacity&quot;">​</a></h3><p>Keep only the most recent <code>100</code> records. Drop the oldest record first when the limit is exceeded.</p><h2 id="summary-rules" tabindex="-1">Summary rules <a class="header-anchor" href="#summary-rules" aria-label="Permalink to &quot;Summary rules&quot;">​</a></h2><p>Collapsed rows need short summaries that are useful at a glance.</p><p>Examples:</p><ul><li><code>onClickRoom</code> -&gt; <code>roomId=8, name=阳台8</code></li><li><code>onClickRoomProperties</code> -&gt; <code>roomId=8, property clicked</code></li></ul><p>Summary generation stays in a dedicated helper so more callbacks can be added later without bloating the panel component.</p><h2 id="ui-primitive-strategy" tabindex="-1">UI primitive strategy <a class="header-anchor" href="#ui-primitive-strategy" aria-label="Permalink to &quot;UI primitive strategy&quot;">​</a></h2><p>The simulator is starting to depend on recurring interaction patterns:</p><ul><li>tooltip</li><li>popover</li><li>dropdown menu</li><li>collapsible content</li><li>custom select behavior</li></ul><p>A full UI framework would add unnecessary visual and structural weight. This iteration introduces <code>reka-ui</code> as a headless primitive layer instead.</p><h3 id="why-reka-ui" tabindex="-1">Why <code>reka-ui</code> <a class="header-anchor" href="#why-reka-ui" aria-label="Permalink to &quot;Why `reka-ui`&quot;">​</a></h3><ul><li>It fits Vue 3 well.</li><li>It supplies behavior and accessibility without imposing a visual system.</li><li>It matches the simulator&#39;s existing design direction better than a full UI framework.</li><li>It creates a path to standardize future overlays and menus without forcing a full component rewrite now.</li></ul><h3 id="v1-usage-boundary" tabindex="-1">V1 usage boundary <a class="header-anchor" href="#v1-usage-boundary" aria-label="Permalink to &quot;V1 usage boundary&quot;">​</a></h3><p>Only use <code>reka-ui</code> where it solves an actual problem in this iteration:</p><ul><li>event filter menu or select</li><li>event row collapsible payload</li><li>tooltip or popover where the simulator already needs one</li></ul><p>Do not use this iteration to replace every custom simulator control.</p><h2 id="component-structure" tabindex="-1">Component structure <a class="header-anchor" href="#component-structure" aria-label="Permalink to &quot;Component structure&quot;">​</a></h2><p>Recommended additions:</p><ul><li><code>useSimulatorEvents.ts</code></li><li><code>eventSummaries.ts</code></li><li><code>SimulatorEventsPanel.vue</code></li><li><code>SimulatorEventItem.vue</code></li></ul><p>Expected integration points:</p><ul><li><code>useMapCanvas.ts</code> or <code>usePlaygroundRender.ts</code> for callback injection</li><li><code>useMapPlayground.ts</code> for page-level state wiring</li><li><code>MapPlayground.vue</code> for layout placement</li></ul><h2 id="data-flow" tabindex="-1">Data flow <a class="header-anchor" href="#data-flow" aria-label="Permalink to &quot;Data flow&quot;">​</a></h2><ol><li>The simulator creates the map instance with recorder-backed SDK callbacks.</li><li>The SDK fires a public callback.</li><li>The wrapper creates a <code>SimulatorEventRecord</code>.</li><li><code>useSimulatorEvents()</code> appends the record.</li><li><code>SimulatorEventsPanel.vue</code> reacts and renders the update.</li></ol><p>The source of truth is the event store, not the UI.</p><h2 id="error-handling" tabindex="-1">Error handling <a class="header-anchor" href="#error-handling" aria-label="Permalink to &quot;Error handling&quot;">​</a></h2><p>Event recording should fail soft.</p><ul><li>If summary generation fails, store the event with a fallback summary such as <code>payload recorded</code>.</li><li>If JSON copy fails, show a lightweight UI failure state but keep the list.</li><li>If the event filter or payload viewer fails, do not affect the map or runtime controls.</li></ul><h2 id="verification-strategy" tabindex="-1">Verification strategy <a class="header-anchor" href="#verification-strategy" aria-label="Permalink to &quot;Verification strategy&quot;">​</a></h2><ul><li>Click a room and confirm <code>onClickRoom</code> appears with the correct payload.</li><li>Click a room property label and confirm <code>onClickRoomProperties</code> appears.</li><li>Pause the console and confirm new callbacks stop appending.</li><li>Clear the console and confirm only event state resets.</li><li>Copy the event log and confirm the output is a valid JSON array.</li><li>Confirm the docs build still passes and the map preview remains visually stable.</li></ul></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-03-10T10:32:53.000Z" data-v-e98dd255></time></p></div></div><!----></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
29
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"_t5bADoD\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"BIwuGR3s\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
29
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"BoT_seGX\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-05-testing-infrastructure-design.md\":\"DLHGz5Ez\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"DdQU431C\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
30
30
 
31
31
  </body>
32
32
  </html>
@@ -9,9 +9,9 @@
9
9
  <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
10
  <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/assets/app.B-cJvUCw.js"></script>
12
+ <script type="module" src="/assets/app.DkbwKXWW.js"></script>
13
13
  <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/assets/chunks/theme.C-O3vTBh.js">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.KfweDRuA.js">
15
15
  <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
16
  <link rel="modulepreload" href="/assets/plans_2026-03-10-simulator-events-console-implementation-plan.md.S2f1zs9-.lean.js">
17
17
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
@@ -19,7 +19,7 @@
19
19
  </head>
20
20
  <body>
21
21
  <div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0b0ada53></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0b0ada53>Skip to content</a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar" data-v-ae24b3ad data-v-6aa21345><div class="wrapper" data-v-6aa21345><div class="container" data-v-6aa21345><div class="title" data-v-6aa21345><div class="VPNavBarTitle" data-v-6aa21345 data-v-1168a8e4><a class="title" href="/" data-v-1168a8e4><!--[--><!--]--><!----><span data-v-1168a8e4>Tuya Robot Map</span><!--[--><!--]--></a></div></div><div class="content" data-v-6aa21345><div class="content-body" data-v-6aa21345><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6aa21345><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6aa21345 data-v-dc692963><span id="main-nav-aria-label" class="visually-hidden" data-v-dc692963> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/guide/concepts.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/reference/data.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>参考</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/simulator/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>模拟调试</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6aa21345 data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6aa21345 data-v-bb2aa2f0 data-v-cf11d7a2><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-cf11d7a2><span class="vpi-more-horizontal icon" data-v-cf11d7a2></span></button><div class="menu" data-v-cf11d7a2><div class="VPMenu" data-v-cf11d7a2 data-v-b98bc113><!----><!--[--><!--[--><!----><div class="group" data-v-bb2aa2f0><div class="item appearance" data-v-bb2aa2f0><p class="label" data-v-bb2aa2f0>Appearance</p><div class="appearance-action" data-v-bb2aa2f0><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-bb2aa2f0 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6aa21345 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-6aa21345><div class="divider-line" data-v-6aa21345></div></div></div><!----></header><div class="VPLocalNav empty fixed" data-v-5d98c3a5 data-v-a6f0e41e><div class="container" data-v-a6f0e41e><!----><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a6f0e41e data-v-8a42e2b4><button data-v-8a42e2b4>Return to top</button><!----></div></div></div><!----><div class="VPContent" id="VPContent" data-v-5d98c3a5 data-v-1428d186><div class="VPDoc has-aside" data-v-1428d186 data-v-39a288b8><!--[--><!--]--><div class="container" data-v-39a288b8><div class="aside" data-v-39a288b8><div class="aside-curtain" data-v-39a288b8></div><div class="aside-container" data-v-39a288b8><div class="aside-content" data-v-39a288b8><div class="VPDocAside" data-v-39a288b8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-a5bbad30><div class="content" data-v-a5bbad30><div class="outline-marker" data-v-a5bbad30></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-a5bbad30>页面导航</div><ul class="VPDocOutlineItem root" data-v-a5bbad30 data-v-b933a997><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-39a288b8><div class="content-container" data-v-39a288b8><!--[--><!--]--><main class="main" data-v-39a288b8><div style="position:relative;" class="vp-doc _plans_2026-03-10-simulator-events-console-implementation-plan" data-v-39a288b8><div><h1 id="simulator-events-console-implementation-plan" tabindex="-1">Simulator events console Implementation Plan <a class="header-anchor" href="#simulator-events-console-implementation-plan" aria-label="Permalink to &quot;Simulator events console Implementation Plan&quot;">​</a></h1><blockquote><p><strong>For Claude:</strong> REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.</p></blockquote><p><strong>Goal:</strong> Add a developer-facing <code>Events</code> console to the simulator that records public SDK callbacks and exposes them as a live, filterable event stream.</p><p><strong>Architecture:</strong> Keep event recording separate from source-data rendering and runtime patching. Inject recorder-backed <code>MapCallbacks</code> into the live map instance, store bounded event records in a focused composable, and render them in a dedicated panel near the map preview. Introduce <code>reka-ui</code> only for the new collapsible and menu primitives required by this console.</p><p><strong>Tech Stack:</strong> Vue 3 Composition API, VitePress, TypeScript, existing simulator composables, SDK <code>MapCallbacks</code>, <code>reka-ui</code></p><hr><h3 id="task-1-add-event-facing-simulator-types-and-helpers" tabindex="-1">Task 1: Add event-facing simulator types and helpers <a class="header-anchor" href="#task-1-add-event-facing-simulator-types-and-helpers" aria-label="Permalink to &quot;Task 1: Add event-facing simulator types and helpers&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/.vitepress/theme/components/simulator/types.ts</code></li><li>Create: <code>docs/.vitepress/theme/components/simulator/eventSummaries.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Add event record and filter types</strong></p><p>Define types for:</p><ul><li><code>SimulatorEventRecord</code></li><li>supported callback names in V1</li><li>event filter values</li><li>event panel action payloads if needed</li></ul><p><strong>Step 2: Add summary helpers</strong></p><p>Create a helper that maps supported callbacks to concise summaries and falls back to a safe default when payload parsing fails.</p><p><strong>Step 3: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-2-build-the-event-store-composable" tabindex="-1">Task 2: Build the event store composable <a class="header-anchor" href="#task-2-build-the-event-store-composable" aria-label="Permalink to &quot;Task 2: Build the event store composable&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Create: <code>docs/.vitepress/theme/components/simulator/useSimulatorEvents.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Create bounded event state</strong></p><p>Implement state for:</p><ul><li>full event list</li><li>paused state</li><li>active callback filter</li><li>derived filtered list</li></ul><p>Limit the stored list to the latest <code>100</code> entries.</p><p><strong>Step 2: Add event actions</strong></p><p>Implement:</p><ul><li><code>pushEvent()</code></li><li><code>clearEvents()</code></li><li><code>toggleEventsPaused()</code></li><li><code>setEventFilter()</code></li><li><code>copyEventsJson()</code></li></ul><p><strong>Step 3: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-3-add-recorder-backed-sdk-callbacks" tabindex="-1">Task 3: Add recorder-backed SDK callbacks <a class="header-anchor" href="#task-3-add-recorder-backed-sdk-callbacks" aria-label="Permalink to &quot;Task 3: Add recorder-backed SDK callbacks&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapCanvas.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/usePlaygroundRender.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapPlayground.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Define callback wrappers</strong></p><p>Create a recorder-backed <code>events</code> object that wraps supported <code>MapCallbacks</code> and forwards payloads into <code>pushEvent()</code>.</p><p><strong>Step 2: Attach wrappers to the map lifecycle</strong></p><p>Ensure the live map instance always receives the wrapped callbacks after render and after source-data reinitialization.</p><p><strong>Step 3: Keep runtime and event paths separate</strong></p><p>Do not route event recording through runtime patch logic or source-data cache logic.</p><p><strong>Step 4: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-4-install-and-integrate-reka-ui-primitives" tabindex="-1">Task 4: Install and integrate <code>reka-ui</code> primitives <a class="header-anchor" href="#task-4-install-and-integrate-reka-ui-primitives" aria-label="Permalink to &quot;Task 4: Install and integrate `reka-ui` primitives&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>package.json</code></li><li>Modify: lockfile</li><li>Test: <code>npm install</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Add the dependency</strong></p><p>Install <code>reka-ui</code> and update the lockfile.</p><p><strong>Step 2: Verify the docs bundle resolves the package</strong></p><p>Confirm imports compile cleanly in the docs app.</p><p><strong>Step 3: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-5-build-the-events-ui-components" tabindex="-1">Task 5: Build the events UI components <a class="header-anchor" href="#task-5-build-the-events-ui-components" aria-label="Permalink to &quot;Task 5: Build the events UI components&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorEventsPanel.vue</code></li><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorEventItem.vue</code></li><li>Test: <code>npm run lint</code></li></ul><p><strong>Step 1: Build the panel shell</strong></p><p>Render:</p><ul><li>title</li><li>filter control</li><li>pause button</li><li>clear button</li><li>copy button</li><li>empty state</li><li>scrollable event list</li></ul><p><strong>Step 2: Build event rows</strong></p><p>Each row must show:</p><ul><li>callback name</li><li>timestamp label</li><li>summary</li><li>collapsible JSON payload</li></ul><p>Use <code>reka-ui</code> primitives for the collapsible payload and filter control if they materially improve structure and accessibility.</p><p><strong>Step 3: Run lint</strong></p><p>Run: <code>npm run lint</code> Expected: PASS</p><h3 id="task-6-integrate-the-events-panel-into-the-simulator-layout" tabindex="-1">Task 6: Integrate the events panel into the simulator layout <a class="header-anchor" href="#task-6-integrate-the-events-panel-into-the-simulator-layout" aria-label="Permalink to &quot;Task 6: Integrate the events panel into the simulator layout&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/.vitepress/theme/components/MapPlayground.vue</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/SimulatorPreviewPanel.vue</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapPlayground.ts</code></li><li>Test: <code>npm run docs:build</code></li></ul><p><strong>Step 1: Add the events panel below the map preview</strong></p><p>Keep the map large and ensure the event console does not collapse the preview area unreasonably.</p><p><strong>Step 2: Pass event state through the page-level composable</strong></p><p>Expose filtered events and event actions cleanly from <code>useMapPlayground()</code>.</p><p><strong>Step 3: Run docs build</strong></p><p>Run: <code>npm run docs:build</code> Expected: PASS</p><h3 id="task-7-verify-the-full-event-flow-and-update-traceability" tabindex="-1">Task 7: Verify the full event flow and update traceability <a class="header-anchor" href="#task-7-verify-the-full-event-flow-and-update-traceability" aria-label="Permalink to &quot;Task 7: Verify the full event flow and update traceability&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/records/plans/2026-03-10-simulator-events-console-plan.md</code></li><li>Test: <code>npm run lint</code></li><li>Test: <code>npx tsc --noEmit</code></li><li>Test: <code>npm run docs:build</code></li></ul><p><strong>Step 1: Update verification checklist</strong></p><p>Mark completed verification items and note any deferred event types.</p><p><strong>Step 2: Run the full validation suite</strong></p><p>Run: <code>npm run lint</code> Expected: PASS</p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><p>Run: <code>npm run docs:build</code> Expected: PASS</p><p><strong>Step 3: Prepare for implementation handoff</strong></p><p>Ensure the plan remains aligned with the approved design and current simulator structure.</p></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-03-10T10:32:53.000Z" data-v-e98dd255></time></p></div></div><!----></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
22
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"_t5bADoD\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"BIwuGR3s\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
22
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"BoT_seGX\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-05-testing-infrastructure-design.md\":\"DLHGz5Ez\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"DdQU431C\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
23
23
 
24
24
  </body>
25
25
  </html>
@@ -9,9 +9,9 @@
9
9
  <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
10
  <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/assets/app.B-cJvUCw.js"></script>
12
+ <script type="module" src="/assets/app.DkbwKXWW.js"></script>
13
13
  <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/assets/chunks/theme.C-O3vTBh.js">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.KfweDRuA.js">
15
15
  <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
16
  <link rel="modulepreload" href="/assets/plans_2026-03-10-simulator-runtime-controls-design.md.mqeNaYgg.lean.js">
17
17
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
@@ -19,7 +19,7 @@
19
19
  </head>
20
20
  <body>
21
21
  <div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0b0ada53></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0b0ada53>Skip to content</a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar" data-v-ae24b3ad data-v-6aa21345><div class="wrapper" data-v-6aa21345><div class="container" data-v-6aa21345><div class="title" data-v-6aa21345><div class="VPNavBarTitle" data-v-6aa21345 data-v-1168a8e4><a class="title" href="/" data-v-1168a8e4><!--[--><!--]--><!----><span data-v-1168a8e4>Tuya Robot Map</span><!--[--><!--]--></a></div></div><div class="content" data-v-6aa21345><div class="content-body" data-v-6aa21345><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6aa21345><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6aa21345 data-v-dc692963><span id="main-nav-aria-label" class="visually-hidden" data-v-dc692963> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/guide/concepts.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/reference/data.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>参考</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/simulator/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>模拟调试</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6aa21345 data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6aa21345 data-v-bb2aa2f0 data-v-cf11d7a2><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-cf11d7a2><span class="vpi-more-horizontal icon" data-v-cf11d7a2></span></button><div class="menu" data-v-cf11d7a2><div class="VPMenu" data-v-cf11d7a2 data-v-b98bc113><!----><!--[--><!--[--><!----><div class="group" data-v-bb2aa2f0><div class="item appearance" data-v-bb2aa2f0><p class="label" data-v-bb2aa2f0>Appearance</p><div class="appearance-action" data-v-bb2aa2f0><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-bb2aa2f0 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6aa21345 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-6aa21345><div class="divider-line" data-v-6aa21345></div></div></div><!----></header><div class="VPLocalNav empty fixed" data-v-5d98c3a5 data-v-a6f0e41e><div class="container" data-v-a6f0e41e><!----><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a6f0e41e data-v-8a42e2b4><button data-v-8a42e2b4>Return to top</button><!----></div></div></div><!----><div class="VPContent" id="VPContent" data-v-5d98c3a5 data-v-1428d186><div class="VPDoc has-aside" data-v-1428d186 data-v-39a288b8><!--[--><!--]--><div class="container" data-v-39a288b8><div class="aside" data-v-39a288b8><div class="aside-curtain" data-v-39a288b8></div><div class="aside-container" data-v-39a288b8><div class="aside-content" data-v-39a288b8><div class="VPDocAside" data-v-39a288b8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-a5bbad30><div class="content" data-v-a5bbad30><div class="outline-marker" data-v-a5bbad30></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-a5bbad30>页面导航</div><ul class="VPDocOutlineItem root" data-v-a5bbad30 data-v-b933a997><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-39a288b8><div class="content-container" data-v-39a288b8><!--[--><!--]--><main class="main" data-v-39a288b8><div style="position:relative;" class="vp-doc _plans_2026-03-10-simulator-runtime-controls-design" data-v-39a288b8><div><h1 id="simulator-runtime-controls-design" tabindex="-1">Simulator runtime controls design <a class="header-anchor" href="#simulator-runtime-controls-design" aria-label="Permalink to &quot;Simulator runtime controls design&quot;">​</a></h1><h2 id="context" tabindex="-1">Context <a class="header-anchor" href="#context" aria-label="Permalink to &quot;Context&quot;">​</a></h2><p>The simulator page currently lets developers paste <code>mapHex</code>, <code>pathHex</code>, and <code>roomProperties</code> and preview the rendered map. It does not expose the SDK <code>runtime</code> layer, so developers cannot validate visibility toggles, room selection, interaction flags, or measurement settings without editing code.</p><p>This design adds a dedicated runtime control experience to the simulator while keeping the map preview large and the UI maintainable.</p><h2 id="goals" tabindex="-1">Goals <a class="header-anchor" href="#goals" aria-label="Permalink to &quot;Goals&quot;">​</a></h2><ul><li>Cover every field in <code>RuntimeConfig</code>.</li><li>Make runtime changes apply in real time through <code>mapApi.updateRuntime()</code>.</li><li>Represent field dependencies explicitly instead of exposing a flat form.</li><li>Prefer direct manipulation when the map already provides the right affordance.</li><li>Keep unsupported runtime fields visible but clearly disabled.</li></ul><h2 id="non-goals" tabindex="-1">Non-goals <a class="header-anchor" href="#non-goals" aria-label="Permalink to &quot;Non-goals&quot;">​</a></h2><ul><li>Do not add full editing workflows for forbidden zones, carpets, furniture, waypoints, or spots in this iteration.</li><li>Do not add a raw JSON editor as the primary runtime editing surface.</li><li>Do not persist runtime state across page reloads in this iteration.</li></ul><h2 id="recommended-approach" tabindex="-1">Recommended approach <a class="header-anchor" href="#recommended-approach" aria-label="Permalink to &quot;Recommended approach&quot;">​</a></h2><h3 id="option-1-flat-runtime-form" tabindex="-1">Option 1: flat runtime form <a class="header-anchor" href="#option-1-flat-runtime-form" aria-label="Permalink to &quot;Option 1: flat runtime form&quot;">​</a></h3><p>Render every runtime field in a single long form with basic controls.</p><ul><li>Pros: fastest to build.</li><li>Cons: poor dependency handling, weak discoverability, scales badly.</li></ul><h3 id="option-2-runtime-as-a-separate-tab" tabindex="-1">Option 2: runtime as a separate tab <a class="header-anchor" href="#option-2-runtime-as-a-separate-tab" aria-label="Permalink to &quot;Option 2: runtime as a separate tab&quot;">​</a></h3><p>Add a <code>Runtime</code> tab next to <code>Map</code>, <code>Path</code>, and <code>Room</code>.</p><ul><li>Pros: clear separation from source data.</li><li>Cons: weak link between runtime controls and live map interaction.</li></ul><h3 id="option-3-recommended-dedicated-runtime-console" tabindex="-1">Option 3: recommended, dedicated runtime console <a class="header-anchor" href="#option-3-recommended-dedicated-runtime-console" aria-label="Permalink to &quot;Option 3: recommended, dedicated runtime console&quot;">​</a></h3><p>Keep source data input and runtime controls separate. Add a dedicated <code>Runtime</code> panel in the left control column, and keep the right column focused on the large map preview.</p><ul><li>Pros: clear mental model, strong map-control linkage, scales well as more runtime fields and future config panels are added.</li><li>Cons: more initial design and state management work.</li></ul><p>This design uses option 3.</p><h2 id="page-information-architecture" tabindex="-1">Page information architecture <a class="header-anchor" href="#page-information-architecture" aria-label="Permalink to &quot;Page information architecture&quot;">​</a></h2><p>The simulator stays in a two-column layout.</p><ul><li>Left column: <ul><li><code>Data</code> panel for <code>Map</code>, <code>Path</code>, and <code>Room</code></li><li><code>Runtime</code> panel for all runtime controls</li><li><code>Inspector</code> panel for runtime snapshot and live state</li></ul></li><li>Right column: <ul><li>large map preview</li><li>light runtime summary overlay</li></ul></li></ul><p>The runtime panel is not merged into the existing source-data tabs. Source data answers &quot;what is rendered&quot;; runtime answers &quot;how it behaves right now.&quot;</p><h2 id="runtime-group-design" tabindex="-1">Runtime group design <a class="header-anchor" href="#runtime-group-design" aria-label="Permalink to &quot;Runtime group design&quot;">​</a></h2><p>Group runtime fields by behavior instead of by raw type.</p><h3 id="visibility" tabindex="-1">Visibility <a class="header-anchor" href="#visibility" aria-label="Permalink to &quot;Visibility&quot;">​</a></h3><p>This group contains direct visibility toggles and uses a compact switch matrix.</p><ul><li><code>showPath</code></li><li><code>showRobot</code></li><li><code>showChargingStation</code></li><li><code>showRoomName</code></li><li><code>showRoomType</code></li><li><code>showRoomProperty</code></li><li><code>showRoomOrder</code></li><li><code>showRoomFloorType</code></li><li><code>showCarpet</code></li><li><code>showDetectedObjects</code></li><li><code>showChargingStationRing</code></li><li><code>showRobotRing</code></li><li><code>showRobotSleepAnimation</code></li><li><code>showRobotPulseCircle</code></li></ul><h3 id="room-selection" tabindex="-1">Room selection <a class="header-anchor" href="#room-selection" aria-label="Permalink to &quot;Room selection&quot;">​</a></h3><p>This is the highest-value interaction group and gets a dedicated sub-panel.</p><ul><li><code>enableRoomSelection</code></li><li><code>roomSelectionMode</code></li><li><code>selectRoomIds</code></li><li><code>roomPropertyFoldIds</code></li><li><code>dividingRoomId</code></li></ul><p>Key behavior:</p><ul><li>When <code>enableRoomSelection</code> is <code>false</code>, dependent controls remain visible but disabled with a clear reason.</li><li><code>selectRoomIds</code> supports two synchronized input channels: <ul><li>room checklist in the panel</li><li>direct room clicking on the map</li></ul></li><li>In <code>checkmark</code> mode, the panel uses a checkbox list.</li><li>In <code>order</code> mode, the panel shows ordered selected rooms and preserves order in <code>selectRoomIds</code>.</li><li><code>dividingRoomId</code> uses a room dropdown, not a free number field.</li><li><code>roomPropertyFoldIds</code> uses room multi-select, not raw array input.</li></ul><h3 id="interaction" tabindex="-1">Interaction <a class="header-anchor" href="#interaction" aria-label="Permalink to &quot;Interaction&quot;">​</a></h3><ul><li><code>enableInteraction</code></li><li><code>enableMapClickCapture</code></li></ul><p>Key behavior:</p><ul><li><code>enableInteraction</code> is the parent switch.</li><li>When <code>enableInteraction</code> is <code>false</code>, <code>enableMapClickCapture</code> is disabled and automatically normalized to <code>false</code>.</li><li>Captured click coordinates appear in the inspector as a read-only result.</li></ul><h3 id="geometry-and-measurement" tabindex="-1">Geometry and measurement <a class="header-anchor" href="#geometry-and-measurement" aria-label="Permalink to &quot;Geometry and measurement&quot;">​</a></h3><ul><li><code>mapRotation</code></li><li><code>unit</code></li><li><code>unitLabel</code></li></ul><p>Key behavior:</p><ul><li><code>mapRotation</code> uses a slider plus numeric input.</li><li><code>unit</code> uses a segmented control or select.</li><li><code>unitLabel</code> follows the default unit mapping until the user customizes it.</li></ul><h3 id="editing-state" tabindex="-1">Editing state <a class="header-anchor" href="#editing-state" aria-label="Permalink to &quot;Editing state&quot;">​</a></h3><ul><li><code>editingForbiddenSweepZoneIds</code></li><li><code>editingForbiddenMopZoneIds</code></li><li><code>editingCleanZoneIds</code></li><li><code>editingVirtualWallIds</code></li><li><code>editingSpotIds</code></li><li><code>editingWayPointIds</code></li><li><code>editingCarpetIds</code></li><li><code>editingFurnitureIds</code></li><li><code>selectedCarpetIds</code></li></ul><p>This group is visible but collapsed by default. Fields are disabled when the simulator lacks the supporting dataset or editing workflow.</p><h2 id="human-friendly-behaviors" tabindex="-1">Human-friendly behaviors <a class="header-anchor" href="#human-friendly-behaviors" aria-label="Permalink to &quot;Human-friendly behaviors&quot;">​</a></h2><p>The runtime console needs a few usability features so it feels like a real debug surface rather than a schema viewer.</p><ul><li>Keep a light &quot;modified&quot; indicator when runtime differs from defaults.</li><li>Provide safe presets such as <code>Default</code>, <code>Selection Debug</code>, <code>Minimal</code>, and <code>Labels Off</code>.</li><li>Show the current runtime snapshot as formatted JSON for copy-and-compare workflows.</li><li>Show why a control is disabled, not only that it is disabled.</li><li>Derive room labels from parsed map rooms and prefer <code>roomProperties</code> names when available.</li></ul><h2 id="state-model" tabindex="-1">State model <a class="header-anchor" href="#state-model" aria-label="Permalink to &quot;State model&quot;">​</a></h2><p>Split state into three layers.</p><h3 id="source-data-state" tabindex="-1">Source data state <a class="header-anchor" href="#source-data-state" aria-label="Permalink to &quot;Source data state&quot;">​</a></h3><p>Mutable source inputs:</p><ul><li><code>mapHex</code></li><li><code>pathHex</code></li><li><code>roomProperties</code></li></ul><p>This layer keeps its current render-and-cache flow.</p><h3 id="derived-map-state" tabindex="-1">Derived map state <a class="header-anchor" href="#derived-map-state" aria-label="Permalink to &quot;Derived map state&quot;">​</a></h3><p>Read-only values produced from parsed data and current map support:</p><ul><li><code>availableRooms</code></li><li><code>parsedMapData</code></li><li><code>parsedPathData</code></li><li><code>mapType</code></li><li><code>runtimeSupportMatrix</code></li><li><code>capturedMapClick</code></li></ul><h3 id="runtime-state" tabindex="-1">Runtime state <a class="header-anchor" href="#runtime-state" aria-label="Permalink to &quot;Runtime state&quot;">​</a></h3><p>Mutable runtime state managed separately from source data:</p><ul><li><code>runtimeDraft</code></li><li>optional <code>runtimeApplied</code> snapshot for diagnostics</li></ul><p>Runtime changes call <code>updateRuntime(partial)</code> and do not re-run map decoding.</p><h2 id="normalization-rules" tabindex="-1">Normalization rules <a class="header-anchor" href="#normalization-rules" aria-label="Permalink to &quot;Normalization rules&quot;">​</a></h2><p>Runtime state must stay valid as source data changes.</p><ul><li>Keep <code>selectRoomIds</code> when <code>enableRoomSelection</code> is off, but disable the UI.</li><li>Force <code>enableMapClickCapture</code> to <code>false</code> when <code>enableInteraction</code> is <code>false</code>.</li><li>Reset <code>dividingRoomId</code> to <code>-1</code> if the room no longer exists.</li><li>Filter invalid room IDs from <code>selectRoomIds</code> and <code>roomPropertyFoldIds</code>.</li><li>Preserve selection order in <code>order</code> mode.</li><li>Keep custom <code>unitLabel</code> if the user has overridden it.</li></ul><h2 id="error-handling" tabindex="-1">Error handling <a class="header-anchor" href="#error-handling" aria-label="Permalink to &quot;Error handling&quot;">​</a></h2><p>Runtime updates use light feedback instead of full render errors.</p><ul><li>If <code>updateRuntime()</code> fails, show a runtime-level error status and keep the last applied state.</li><li>If normalization removes invalid values, show a small informational status describing the change.</li><li>Unsupported fields stay visible and disabled rather than hidden.</li></ul><h2 id="component-boundaries" tabindex="-1">Component boundaries <a class="header-anchor" href="#component-boundaries" aria-label="Permalink to &quot;Component boundaries&quot;">​</a></h2><p>Add runtime support without re-centralizing the simulator into one file.</p><ul><li><code>MapPlayground.vue</code>: layout orchestration only</li><li><code>useMapPlayground.ts</code>: page-level state aggregation</li><li><code>useRuntimePlayground.ts</code>: runtime draft, dependencies, presets, snapshot</li><li><code>useRuntimeBindings.ts</code>: bridge between UI actions, map callbacks, and <code>mapApi.updateRuntime()</code></li><li><code>SimulatorRuntimePanel.vue</code>: runtime console shell</li><li><code>SimulatorRoomSelectionPanel.vue</code>: dedicated room-selection UI</li><li><code>SimulatorInspectorPanel.vue</code>: runtime JSON, selected rooms, click capture</li></ul><h2 id="verification" tabindex="-1">Verification <a class="header-anchor" href="#verification" aria-label="Permalink to &quot;Verification&quot;">​</a></h2><p>Validate the design with the following outcomes.</p><ul><li>Every <code>RuntimeConfig</code> field appears in the runtime console.</li><li>Runtime changes update the map through <code>updateRuntime()</code> without full redraw.</li><li>Room selection stays synchronized between panel and map.</li><li>Invalid room-linked values are normalized after source data changes.</li><li>Unsupported fields are visible, disabled, and labeled with the reason.</li><li>The map preview remains visually dominant on desktop and mobile layouts.</li></ul><h2 id="next-steps" tabindex="-1">Next steps <a class="header-anchor" href="#next-steps" aria-label="Permalink to &quot;Next steps&quot;">​</a></h2><p>Write an implementation plan that phases the runtime console into composables and components without destabilizing the existing simulator page.</p></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-03-10T12:21:24.000Z" data-v-e98dd255></time></p></div></div><!----></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
22
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"_t5bADoD\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"BIwuGR3s\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
22
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"BoT_seGX\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-05-testing-infrastructure-design.md\":\"DLHGz5Ez\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"DdQU431C\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
23
23
 
24
24
  </body>
25
25
  </html>
@@ -9,9 +9,9 @@
9
9
  <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
10
  <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/assets/app.B-cJvUCw.js"></script>
12
+ <script type="module" src="/assets/app.DkbwKXWW.js"></script>
13
13
  <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/assets/chunks/theme.C-O3vTBh.js">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.KfweDRuA.js">
15
15
  <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
16
  <link rel="modulepreload" href="/assets/plans_2026-03-10-simulator-runtime-controls-implementation-plan.md.BXG1UWFt.lean.js">
17
17
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
@@ -19,7 +19,7 @@
19
19
  </head>
20
20
  <body>
21
21
  <div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0b0ada53></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0b0ada53>Skip to content</a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar" data-v-ae24b3ad data-v-6aa21345><div class="wrapper" data-v-6aa21345><div class="container" data-v-6aa21345><div class="title" data-v-6aa21345><div class="VPNavBarTitle" data-v-6aa21345 data-v-1168a8e4><a class="title" href="/" data-v-1168a8e4><!--[--><!--]--><!----><span data-v-1168a8e4>Tuya Robot Map</span><!--[--><!--]--></a></div></div><div class="content" data-v-6aa21345><div class="content-body" data-v-6aa21345><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6aa21345><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6aa21345 data-v-dc692963><span id="main-nav-aria-label" class="visually-hidden" data-v-dc692963> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/guide/concepts.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/reference/data.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>参考</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/simulator/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>模拟调试</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6aa21345 data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6aa21345 data-v-bb2aa2f0 data-v-cf11d7a2><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-cf11d7a2><span class="vpi-more-horizontal icon" data-v-cf11d7a2></span></button><div class="menu" data-v-cf11d7a2><div class="VPMenu" data-v-cf11d7a2 data-v-b98bc113><!----><!--[--><!--[--><!----><div class="group" data-v-bb2aa2f0><div class="item appearance" data-v-bb2aa2f0><p class="label" data-v-bb2aa2f0>Appearance</p><div class="appearance-action" data-v-bb2aa2f0><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-bb2aa2f0 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6aa21345 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-6aa21345><div class="divider-line" data-v-6aa21345></div></div></div><!----></header><div class="VPLocalNav empty fixed" data-v-5d98c3a5 data-v-a6f0e41e><div class="container" data-v-a6f0e41e><!----><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a6f0e41e data-v-8a42e2b4><button data-v-8a42e2b4>Return to top</button><!----></div></div></div><!----><div class="VPContent" id="VPContent" data-v-5d98c3a5 data-v-1428d186><div class="VPDoc has-aside" data-v-1428d186 data-v-39a288b8><!--[--><!--]--><div class="container" data-v-39a288b8><div class="aside" data-v-39a288b8><div class="aside-curtain" data-v-39a288b8></div><div class="aside-container" data-v-39a288b8><div class="aside-content" data-v-39a288b8><div class="VPDocAside" data-v-39a288b8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-a5bbad30><div class="content" data-v-a5bbad30><div class="outline-marker" data-v-a5bbad30></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-a5bbad30>页面导航</div><ul class="VPDocOutlineItem root" data-v-a5bbad30 data-v-b933a997><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-39a288b8><div class="content-container" data-v-39a288b8><!--[--><!--]--><main class="main" data-v-39a288b8><div style="position:relative;" class="vp-doc _plans_2026-03-10-simulator-runtime-controls-implementation-plan" data-v-39a288b8><div><h1 id="simulator-runtime-controls-implementation-plan" tabindex="-1">Simulator runtime controls Implementation Plan <a class="header-anchor" href="#simulator-runtime-controls-implementation-plan" aria-label="Permalink to &quot;Simulator runtime controls Implementation Plan&quot;">​</a></h1><blockquote><p><strong>For Claude:</strong> REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.</p></blockquote><p><strong>Goal:</strong> Add a runtime control console to the simulator page so developers can inspect and update all <code>RuntimeConfig</code> fields from the docs UI.</p><p><strong>Architecture:</strong> Keep source data rendering and runtime updates on separate paths. Source inputs continue to use the existing full render pipeline, while runtime controls update a dedicated runtime draft and call <code>mapApi.updateRuntime()</code> incrementally. Build the new UI as focused simulator components and composables so the page stays maintainable.</p><p><strong>Tech Stack:</strong> Vue 3 Composition API, VitePress, TypeScript, existing simulator composables, <code>MapApplication.updateRuntime()</code></p><hr><h3 id="task-1-define-runtime-facing-simulator-types-and-defaults" tabindex="-1">Task 1: Define runtime-facing simulator types and defaults <a class="header-anchor" href="#task-1-define-runtime-facing-simulator-types-and-defaults" aria-label="Permalink to &quot;Task 1: Define runtime-facing simulator types and defaults&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/.vitepress/theme/components/simulator/types.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/constants.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Add runtime UI metadata types</strong></p><p>Add types for:</p><ul><li>runtime field groups</li><li>disabled-state reasons</li><li>room option descriptors</li><li>runtime preset descriptors</li><li>runtime support matrix</li></ul><p><strong>Step 2: Add simulator runtime defaults and labels</strong></p><p>Define:</p><ul><li>the default runtime draft</li><li>unit-to-label defaults</li><li>field-group metadata</li><li>safe preset definitions</li></ul><p><strong>Step 3: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-2-build-runtime-state-composable" tabindex="-1">Task 2: Build runtime state composable <a class="header-anchor" href="#task-2-build-runtime-state-composable" aria-label="Permalink to &quot;Task 2: Build runtime state composable&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Create: <code>docs/.vitepress/theme/components/simulator/useRuntimePlayground.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapPlayground.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Create <code>useRuntimePlayground()</code></strong></p><p>Implement a composable that manages:</p><ul><li><code>runtimeDraft</code></li><li><code>runtimeModified</code></li><li>preset application</li><li>normalization helpers</li><li>runtime JSON snapshot</li><li>room-derived option lists</li></ul><p><strong>Step 2: Encode normalization rules</strong></p><p>Add helpers to:</p><ul><li>filter invalid room IDs</li><li>reset <code>dividingRoomId</code> to <code>-1</code> when needed</li><li>force <code>enableMapClickCapture</code> off when interaction is disabled</li><li>keep custom <code>unitLabel</code> once it has diverged from the default</li></ul><p><strong>Step 3: Integrate the composable into <code>useMapPlayground.ts</code></strong></p><p>Expose runtime state and actions from the page-level composable without mixing them into source-input logic.</p><p><strong>Step 4: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-3-expose-map-instance-and-room-derived-support-data" tabindex="-1">Task 3: Expose map instance and room-derived support data <a class="header-anchor" href="#task-3-expose-map-instance-and-room-derived-support-data" aria-label="Permalink to &quot;Task 3: Expose map instance and room-derived support data&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapCanvas.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/usePlaygroundRender.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/summaries.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Expose the active map instance</strong></p><p>Update <code>useMapCanvas.ts</code> so callers can access the live map instance and call <code>updateRuntime()</code> after the initial render succeeds.</p><p><strong>Step 2: Extract room-level derived data after render</strong></p><p>Update <code>usePlaygroundRender.ts</code> to publish:</p><ul><li>parsed room list</li><li>room labels derived from map and <code>roomProperties</code></li><li>runtime support signals based on parsed content</li></ul><p><strong>Step 3: Avoid full redraw on runtime-only changes</strong></p><p>Keep <code>renderMap()</code> responsible for source data changes only. Do not route runtime updates back into this function.</p><p><strong>Step 4: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-4-build-the-runtime-to-map-binding-layer" tabindex="-1">Task 4: Build the runtime-to-map binding layer <a class="header-anchor" href="#task-4-build-the-runtime-to-map-binding-layer" aria-label="Permalink to &quot;Task 4: Build the runtime-to-map binding layer&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Create: <code>docs/.vitepress/theme/components/simulator/useRuntimeBindings.ts</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapPlayground.ts</code></li><li>Test: <code>npx tsc --noEmit</code></li></ul><p><strong>Step 1: Create <code>useRuntimeBindings()</code></strong></p><p>Implement bindings that:</p><ul><li>accept partial runtime changes from the UI</li><li>call <code>mapApi.updateRuntime(partial)</code></li><li>keep a last-applied snapshot</li><li>surface lightweight runtime errors</li></ul><p><strong>Step 2: Add room-click synchronization</strong></p><p>Wire map room-click callbacks so:</p><ul><li>clicking a room updates <code>selectRoomIds</code></li><li><code>checkmark</code> mode toggles selection</li><li><code>order</code> mode appends or removes while preserving order</li></ul><p><strong>Step 3: Add normalization after source re-render</strong></p><p>When map data changes, re-validate runtime draft against the new room list and re-apply the normalized runtime if needed.</p><p><strong>Step 4: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><h3 id="task-5-build-runtime-panel-ui-components" tabindex="-1">Task 5: Build runtime panel UI components <a class="header-anchor" href="#task-5-build-runtime-panel-ui-components" aria-label="Permalink to &quot;Task 5: Build runtime panel UI components&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorRuntimePanel.vue</code></li><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorRuntimeGroup.vue</code></li><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorRuntimeField.vue</code></li><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorRoomSelectionPanel.vue</code></li><li>Create: <code>docs/.vitepress/theme/components/simulator/SimulatorInspectorPanel.vue</code></li><li>Test: <code>npm run lint</code></li></ul><p><strong>Step 1: Build generic runtime group and field components</strong></p><p>Support the control types needed in V1:</p><ul><li>switch</li><li>select</li><li>segmented choice</li><li>range plus number</li><li>room checklist</li><li>room chips</li><li>disabled readonly lists</li></ul><p><strong>Step 2: Build the room-selection sub-panel</strong></p><p>Include:</p><ul><li>enable switch</li><li>selection mode switch</li><li>room checklist</li><li>selected-room chips</li><li>clear selection action</li><li>disabled-state hints</li></ul><p><strong>Step 3: Build the inspector panel</strong></p><p>Show:</p><ul><li>runtime snapshot JSON</li><li>selected room IDs</li><li>captured map click</li><li>lightweight dependency summary</li></ul><p><strong>Step 4: Run lint</strong></p><p>Run: <code>npm run lint</code> Expected: PASS</p><h3 id="task-6-integrate-runtime-console-into-page-layout" tabindex="-1">Task 6: Integrate runtime console into page layout <a class="header-anchor" href="#task-6-integrate-runtime-console-into-page-layout" aria-label="Permalink to &quot;Task 6: Integrate runtime console into page layout&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/.vitepress/theme/components/MapPlayground.vue</code></li><li>Modify: <code>docs/.vitepress/theme/components/simulator/useMapPlayground.ts</code></li><li>Test: <code>npm run docs:build</code></li></ul><p><strong>Step 1: Add the runtime and inspector panels to the left column</strong></p><p>Keep the existing source-data panel intact and add the runtime console beneath it without shrinking the map preview more than necessary.</p><p><strong>Step 2: Add preview-side runtime summary</strong></p><p>Show a lightweight summary overlay for key states such as:</p><ul><li>selection enabled</li><li>selected room count</li><li>map rotation</li></ul><p><strong>Step 3: Verify responsive behavior</strong></p><p>Ensure the layout remains usable on mobile and on medium desktop widths.</p><p><strong>Step 4: Run docs build</strong></p><p>Run: <code>npm run docs:build</code> Expected: PASS</p><h3 id="task-7-verify-the-full-simulator-flow" tabindex="-1">Task 7: Verify the full simulator flow <a class="header-anchor" href="#task-7-verify-the-full-simulator-flow" aria-label="Permalink to &quot;Task 7: Verify the full simulator flow&quot;">​</a></h3><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/records/plans/2026-03-10-simulator-runtime-controls-plan.md</code></li><li>Test: <code>npm run lint</code></li><li>Test: <code>npx tsc --noEmit</code></li><li>Test: <code>npm run docs:build</code></li></ul><p><strong>Step 1: Run lint</strong></p><p>Run: <code>npm run lint</code> Expected: PASS</p><p><strong>Step 2: Run type-check</strong></p><p>Run: <code>npx tsc --noEmit</code> Expected: PASS</p><p><strong>Step 3: Run docs build</strong></p><p>Run: <code>npm run docs:build</code> Expected: PASS</p><p><strong>Step 4: Update the verification checklist</strong></p><p>Mark the record checklist with actual results and note any scoped follow-up work that was intentionally deferred.</p></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-03-10T12:21:24.000Z" data-v-e98dd255></time></p></div></div><!----></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
22
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"_t5bADoD\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"BIwuGR3s\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
22
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"BoT_seGX\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-05-testing-infrastructure-design.md\":\"DLHGz5Ez\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"DdQU431C\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
23
23
 
24
24
  </body>
25
25
  </html>
@@ -0,0 +1,41 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US" dir="ltr">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Testing rollout next steps implementation plan | Tuya Robot Map</title>
7
+ <meta name="description" content="涂鸦扫地机地图组件">
8
+ <meta name="generator" content="VitePress v1.6.4">
9
+ <link rel="preload stylesheet" href="/assets/style.hiWmcVfN.css" as="style">
10
+ <link rel="preload stylesheet" href="/vp-icons.css" as="style">
11
+
12
+ <script type="module" src="/assets/app.DkbwKXWW.js"></script>
13
+ <link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
+ <link rel="modulepreload" href="/assets/chunks/theme.KfweDRuA.js">
15
+ <link rel="modulepreload" href="/assets/chunks/framework.CBLqO2Q1.js">
16
+ <link rel="modulepreload" href="/assets/plans_2026-03-10-testing-rollout-next-steps-plan.md.CGR6uZic.lean.js">
17
+ <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
18
+ <script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
19
+ </head>
20
+ <body>
21
+ <div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0b0ada53></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0b0ada53>Skip to content</a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar" data-v-ae24b3ad data-v-6aa21345><div class="wrapper" data-v-6aa21345><div class="container" data-v-6aa21345><div class="title" data-v-6aa21345><div class="VPNavBarTitle" data-v-6aa21345 data-v-1168a8e4><a class="title" href="/" data-v-1168a8e4><!--[--><!--]--><!----><span data-v-1168a8e4>Tuya Robot Map</span><!--[--><!--]--></a></div></div><div class="content" data-v-6aa21345><div class="content-body" data-v-6aa21345><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6aa21345><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6aa21345 data-v-dc692963><span id="main-nav-aria-label" class="visually-hidden" data-v-dc692963> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/guide/concepts.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/reference/data.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>参考</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/simulator/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>模拟调试</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6aa21345 data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-6aa21345 data-v-bb2aa2f0 data-v-cf11d7a2><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-cf11d7a2><span class="vpi-more-horizontal icon" data-v-cf11d7a2></span></button><div class="menu" data-v-cf11d7a2><div class="VPMenu" data-v-cf11d7a2 data-v-b98bc113><!----><!--[--><!--[--><!----><div class="group" data-v-bb2aa2f0><div class="item appearance" data-v-bb2aa2f0><p class="label" data-v-bb2aa2f0>Appearance</p><div class="appearance-action" data-v-bb2aa2f0><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-bb2aa2f0 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6aa21345 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-6aa21345><div class="divider-line" data-v-6aa21345></div></div></div><!----></header><div class="VPLocalNav empty fixed" data-v-5d98c3a5 data-v-a6f0e41e><div class="container" data-v-a6f0e41e><!----><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a6f0e41e data-v-8a42e2b4><button data-v-8a42e2b4>Return to top</button><!----></div></div></div><!----><div class="VPContent" id="VPContent" data-v-5d98c3a5 data-v-1428d186><div class="VPDoc has-aside" data-v-1428d186 data-v-39a288b8><!--[--><!--]--><div class="container" data-v-39a288b8><div class="aside" data-v-39a288b8><div class="aside-curtain" data-v-39a288b8></div><div class="aside-container" data-v-39a288b8><div class="aside-content" data-v-39a288b8><div class="VPDocAside" data-v-39a288b8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-a5bbad30><div class="content" data-v-a5bbad30><div class="outline-marker" data-v-a5bbad30></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-a5bbad30>页面导航</div><ul class="VPDocOutlineItem root" data-v-a5bbad30 data-v-b933a997><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-39a288b8><div class="content-container" data-v-39a288b8><!--[--><!--]--><main class="main" data-v-39a288b8><div style="position:relative;" class="vp-doc _plans_2026-03-10-testing-rollout-next-steps-plan" data-v-39a288b8><div><h1 id="testing-rollout-next-steps-implementation-plan" tabindex="-1">Testing rollout next steps implementation plan <a class="header-anchor" href="#testing-rollout-next-steps-implementation-plan" aria-label="Permalink to &quot;Testing rollout next steps implementation plan&quot;">​</a></h1><blockquote><p><strong>For Claude:</strong> REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.</p></blockquote><p><strong>Goal:</strong> Finish the remaining high-value SDK test coverage work from the current worktree state, then harden the test system with enforceable coverage and verification gates.</p><p><strong>Architecture:</strong> Keep the existing Vitest and layered PIXI mock foundation, then expand coverage in ROI order: missing manager logic, missing component logic, browser-specific utilities, and finally coverage ratcheting and CI readiness. Prefer small test files that mirror one source module or one focused behavior area.</p><p><strong>Tech Stack:</strong> TypeScript, Vitest 4, V8 coverage, PIXI.js 8 mocks, Valtio, ESLint, Vite.</p><hr><h2 id="current-state-summary" tabindex="-1">Current state summary <a class="header-anchor" href="#current-state-summary" aria-label="Permalink to &quot;Current state summary&quot;">​</a></h2><p>This plan starts from the actual repository state on March 10, 2026, not from the earlier design baseline.</p><ul><li>Test infrastructure is already present in <code>vitest.config.ts</code>, <code>test/setup.ts</code>, <code>test/mocks/*</code>, and <code>test/factories/*</code>.</li><li>The worktree already has 25 test files and 650 passing tests.</li><li><code>AppService</code>, <code>Interaction</code>, <code>MapApplication</code>, <code>PathManager</code>, <code>ControlsManager</code>, <code>Robot</code>, <code>ChargingStation</code>, and utility algorithms already have meaningful test coverage.</li><li>The largest remaining gaps are <code>MapManager</code>, <code>RoomManager</code>, many untested components, <code>browser.ts</code>, and hardening tasks such as non-zero coverage thresholds.</li></ul><h2 id="constraints-and-execution-rules" tabindex="-1">Constraints and execution rules <a class="header-anchor" href="#constraints-and-execution-rules" aria-label="Permalink to &quot;Constraints and execution rules&quot;">​</a></h2><p>This plan follows the current repository rules and the current worktree state.</p><ul><li>Preserve existing user changes in the dirty worktree.</li><li>Keep tests in <code>test/</code> mirroring <code>src/core/</code> paths.</li><li>Prefer splitting oversized test files by behavior area when it improves maintainability.</li><li>After each implementation slice, run <code>npm test</code>, <code>npx tsc --noEmit</code>, and <code>npm run lint</code>.</li><li>Before claiming hardening is complete, also run <code>npm run test:coverage</code>.</li><li>Do not introduce browser or E2E frameworks in this plan.</li></ul><h2 id="task-1-stabilize-the-in-progress-test-file-split" tabindex="-1">Task 1: Stabilize the in-progress test file split <a class="header-anchor" href="#task-1-stabilize-the-in-progress-test-file-split" aria-label="Permalink to &quot;Task 1: Stabilize the in-progress test file split&quot;">​</a></h2><p>This task closes the current dirty-worktree refactor before adding more surface area.</p><p><strong>Files:</strong></p><ul><li>Modify: <code>test/core/application/Interaction.test.ts</code></li><li>Modify: <code>test/core/components/Robot.test.ts</code></li><li>Modify: <code>test/core/managers/PathManager.test.ts</code></li><li>Modify: <code>test/core/utils/algorithm-geometry.test.ts</code></li><li>Modify: <code>test/core/utils/algorithm-outline.test.ts</code></li><li>Modify: <code>test/core/utils/algorithm-room.test.ts</code></li><li>Modify: <code>test/core/utils/algorithm-vector.test.ts</code></li><li>Delete: <code>test/core/utils/index.test.ts</code></li><li>Create: <code>test/core/application/Interaction-pointer.test.ts</code></li><li>Create: <code>test/core/application/Interaction-gesture.test.ts</code></li><li>Create: <code>test/core/application/Interaction-panzoom.test.ts</code></li><li>Create: <code>test/core/application/Interaction-detect.test.ts</code></li><li>Create: <code>test/core/application/interaction-test-setup.ts</code></li><li>Create: <code>test/core/components/Robot-draw.test.ts</code></li><li>Create: <code>test/core/components/Robot-movement.test.ts</code></li><li>Create: <code>test/core/managers/PathManager-draw.test.ts</code></li><li>Create: <code>test/core/managers/PathManager-operations.test.ts</code></li><li>Create: <code>test/core/utils/utils-easing.test.ts</code></li><li>Create: <code>test/core/utils/utils-precision.test.ts</code></li><li>Create: <code>test/core/utils/utils-room.test.ts</code></li></ul><p><strong>Step 1: Review the split for duplication and ownership</strong></p><p>Check that each new file owns one behavior cluster and that no assertions are duplicated across old and new files.</p><p><strong>Step 2: Keep helper setup local and reusable</strong></p><p>Move repeated Interaction setup into <code>test/core/application/interaction-test-setup.ts</code> only when it reduces noise.</p><p><strong>Step 3: Remove the obsolete aggregate utility test file</strong></p><p>Finish the migration away from <code>test/core/utils/index.test.ts</code> after its coverage has been preserved by the new focused utility test files.</p><p><strong>Step 4: Run verification</strong></p><p>Run:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span></span>
22
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> tsc</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --noEmit</span></span>
23
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span></code></pre></div><p>Expected: all commands pass with no regression from the split.</p><h2 id="task-2-add-missing-manager-coverage-for-roommanager" tabindex="-1">Task 2: Add missing manager coverage for RoomManager <a class="header-anchor" href="#task-2-add-missing-manager-coverage-for-roommanager" aria-label="Permalink to &quot;Task 2: Add missing manager coverage for RoomManager&quot;">​</a></h2><p>This task fills one of the two explicit manager gaps from the original phase plan.</p><p><strong>Files:</strong></p><ul><li>Modify: <code>src/core/managers/RoomManager.ts</code></li><li>Create: <code>test/core/managers/RoomManager.test.ts</code></li></ul><p><strong>Step 1: Write failing tests for subscription-driven visibility behavior</strong></p><p>Cover runtime reactions such as room visibility toggles, label visibility, and cleanup of subscriptions in <code>destroy()</code>.</p><p><strong>Step 2: Write failing tests for room data synchronization</strong></p><p>Cover room collection updates, state-driven redraw decisions, and basic idempotency when repeated room updates arrive.</p><p><strong>Step 3: Reuse existing factories and PIXI mocks</strong></p><p>Build test fixtures from <code>test/factories/map-data.ts</code>, <code>test/factories/config.ts</code>, and <code>test/factories/runtime.ts</code> before creating new helpers.</p><p><strong>Step 4: Implement only minimal test-support changes</strong></p><p>If testability gaps exist, keep production edits small and avoid behavior changes beyond exposing stable seams.</p><p><strong>Step 5: Run verification</strong></p><p>Run:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> RoomManager</span></span>
24
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span></span>
25
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> tsc</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --noEmit</span></span>
26
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span></code></pre></div><p>Expected: new <code>RoomManager</code> tests pass, and the full suite still passes.</p><h2 id="task-3-add-missing-manager-coverage-for-mapmanager" tabindex="-1">Task 3: Add missing manager coverage for MapManager <a class="header-anchor" href="#task-3-add-missing-manager-coverage-for-mapmanager" aria-label="Permalink to &quot;Task 3: Add missing manager coverage for MapManager&quot;">​</a></h2><p>This is the largest remaining high-value gap and the best next ROI item after <code>RoomManager</code>.</p><p><strong>Files:</strong></p><ul><li>Modify: <code>src/core/managers/MapManager.ts</code></li><li>Create: <code>test/core/managers/MapManager.test.ts</code></li></ul><p><strong>Step 1: Identify a narrow first slice</strong></p><p>Start with room detection flow, raster versus structured handling, and caching decisions. Do not try to cover every branch in the first pass.</p><p><strong>Step 2: Mock robot-protocol decode boundaries deliberately</strong></p><p>Use <code>test/mocks/robot-protocol.ts</code> and fixture builders so tests focus on manager orchestration rather than protocol internals.</p><p><strong>Step 3: Add tests for cache reuse and redraw triggers</strong></p><p>Cover cases where identical inputs skip unnecessary work and changed inputs cause the expected processing path.</p><p><strong>Step 4: Add tests for structured versus raster dispatch</strong></p><p>Verify that <code>MapManager</code> selects the correct pipeline and populates downstream data consistently.</p><p><strong>Step 5: Run verification</strong></p><p>Run:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> MapManager</span></span>
27
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span></span>
28
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> tsc</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --noEmit</span></span>
29
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span></code></pre></div><p>Expected: the first focused <code>MapManager</code> slice lands without destabilizing the existing suite.</p><h2 id="task-4-expand-component-coverage-by-priority" tabindex="-1">Task 4: Expand component coverage by priority <a class="header-anchor" href="#task-4-expand-component-coverage-by-priority" aria-label="Permalink to &quot;Task 4: Expand component coverage by priority&quot;">​</a></h2><p>This task broadens Phase 4, but only for components with meaningful state or geometry logic.</p><p><strong>Files:</strong></p><ul><li>Create: <code>test/core/components/Path.test.ts</code></li><li>Create: <code>test/core/components/RoomInfo.test.ts</code></li><li>Create: <code>test/core/components/RoomLabel.test.ts</code></li><li>Create: <code>test/core/components/VirtualWall.test.ts</code></li><li>Create: <code>test/core/components/Carpet.test.ts</code></li><li>Optional create: additional focused component test files that map to the selected source modules</li></ul><p><strong>Step 1: Prioritize data-rich components</strong></p><p>Implement coverage in this order: <code>Path</code> first, then room presentation components, then interactive control visuals.</p><p><strong>Step 2: Test construction, updates, and destroy cleanup</strong></p><p>Focus on input-to-render-state behavior, not PIXI internals.</p><p><strong>Step 3: Avoid broad snapshot-style assertions</strong></p><p>Use direct assertions on points, visibility, labels, transforms, and child management so failures stay easy to diagnose.</p><p><strong>Step 4: Run verification</strong></p><p>Run:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span></span>
30
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> tsc</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --noEmit</span></span>
31
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span></code></pre></div><p>Expected: component coverage grows without requiring heavier PIXI mocks.</p><h2 id="task-5-add-browser-utility-coverage" tabindex="-1">Task 5: Add browser utility coverage <a class="header-anchor" href="#task-5-add-browser-utility-coverage" aria-label="Permalink to &quot;Task 5: Add browser utility coverage&quot;">​</a></h2><p>This task closes the small but explicit browser-specific risk called out in the design record.</p><p><strong>Files:</strong></p><ul><li>Create: <code>test/core/utils/browser.test.ts</code></li><li>Modify: <code>src/core/utils/browser.ts</code> only if a small test seam is required</li></ul><p><strong>Step 1: Stub <code>navigator</code> inputs explicitly</strong></p><p>Cover <code>userAgent</code> and <code>deviceMemory</code> branches with <code>vi.stubGlobal()</code> based tests.</p><p><strong>Step 2: Verify environment assumptions</strong></p><p>Make sure tests reset globals between cases so forked execution is not the only thing protecting isolation.</p><p><strong>Step 3: Run verification</strong></p><p>Run:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> browser</span></span>
32
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span></span>
33
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> tsc</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --noEmit</span></span>
34
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span></code></pre></div><p>Expected: <code>browser.ts</code> no longer remains at zero coverage.</p><h2 id="task-6-harden-the-test-system-gates" tabindex="-1">Task 6: Harden the test system gates <a class="header-anchor" href="#task-6-harden-the-test-system-gates" aria-label="Permalink to &quot;Task 6: Harden the test system gates&quot;">​</a></h2><p>This task converts the current test suite from permissive to enforceable.</p><p><strong>Files:</strong></p><ul><li>Modify: <code>vitest.config.ts</code></li><li>Modify: <code>package.json</code></li><li>Modify: <code>eslint.config.js</code></li></ul><p><strong>Step 1: Set non-zero coverage thresholds</strong></p><p>After Tasks 2 through 5 are complete, run <code>npm run test:coverage</code> and set thresholds in <code>vitest.config.ts</code> using the ratchet rule from the design doc.</p><p><strong>Step 2: Extend lint coverage to test code</strong></p><p>Update lint configuration so test files are included in normal verification. The current <code>lint</code> script only checks <code>src</code>.</p><p><strong>Step 3: Keep thresholds realistic</strong></p><p>Start with a floor that the current suite can satisfy comfortably, then ratchet up in later iterations rather than blocking progress on an overly aggressive first gate.</p><p><strong>Step 4: Run verification</strong></p><p>Run:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> lint</span></span>
35
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> tsc</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --noEmit</span></span>
36
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test</span></span>
37
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">npm</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> test:coverage</span></span></code></pre></div><p>Expected: all four commands pass with enforceable, non-zero thresholds.</p><h2 id="task-7-update-traceability-and-execution-status" tabindex="-1">Task 7: Update traceability and execution status <a class="header-anchor" href="#task-7-update-traceability-and-execution-status" aria-label="Permalink to &quot;Task 7: Update traceability and execution status&quot;">​</a></h2><p>This task keeps the docs aligned with reality once implementation catches up.</p><p><strong>Files:</strong></p><ul><li>Modify: <code>docs/records/plans/2026-03-05-testing-infrastructure-design.md</code></li><li>Optional create: <code>docs/records/bugs/2026-03-10-&lt;topic&gt;-bugfix.md</code> if non-trivial defects are fixed during the rollout</li></ul><p><strong>Step 1: Update status language</strong></p><p>Replace outdated statements such as &quot;zero tests&quot; and &quot;Draft — pending approval&quot; once the rollout milestone is complete.</p><p><strong>Step 2: Record actual delivered phase status</strong></p><p>Document which phases are complete, which are partial, and which hardening items remain open.</p><p><strong>Step 3: Keep the record factual</strong></p><p>Report actual commands, actual coverage, and actual remaining gaps instead of restating estimates.</p><h2 id="recommended-execution-order" tabindex="-1">Recommended execution order <a class="header-anchor" href="#recommended-execution-order" aria-label="Permalink to &quot;Recommended execution order&quot;">​</a></h2><p>Use this order to keep momentum and avoid mixing structural cleanup with new surface area.</p><ol><li>Finish Task 1.</li><li>Implement Task 2.</li><li>Implement Task 3.</li><li>Implement Task 4.</li><li>Implement Task 5.</li><li>Implement Task 6.</li><li>Close with Task 7.</li></ol><h2 id="verification-checklist" tabindex="-1">Verification checklist <a class="header-anchor" href="#verification-checklist" aria-label="Permalink to &quot;Verification checklist&quot;">​</a></h2><p>Use this checklist before calling the testing rollout complete.</p><ul><li><code>npm test</code> passes.</li><li><code>npx tsc --noEmit</code> passes.</li><li><code>npm run lint</code> passes for <code>src</code> and <code>test</code>.</li><li><code>npm run test:coverage</code> passes with non-zero thresholds.</li><li><code>MapManager</code>, <code>RoomManager</code>, and <code>browser.ts</code> are no longer uncovered.</li><li>The design record reflects the actual delivered state.</li></ul><h2 id="next-steps" tabindex="-1">Next steps <a class="header-anchor" href="#next-steps" aria-label="Permalink to &quot;Next steps&quot;">​</a></h2><p>If you want to execute this in the current session, the cleanest next move is to treat <strong>Task 1 plus Task 2</strong> as the first batch. That closes the in-flight refactor and lands the smallest missing manager slice before tackling the much larger <code>MapManager</code> surface.</p></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><!----><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>最后更新于: <time datetime="2026-03-16T09:34:32.000Z" data-v-e98dd255></time></p></div></div><!----></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
38
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"guide_advanced-usage.md\":\"COVLyRkA\",\"guide_concepts.md\":\"CJ87tk-r\",\"guide_getting-started.md\":\"BoT_seGX\",\"guide_mcp.md\":\"CabCiX8Z\",\"index.md\":\"wTsFvv0N\",\"plans_2026-03-04-detected-objects-visibility-design.md\":\"Dqboot5W\",\"plans_2026-03-04-show-detected-objects-implementation-plan.md\":\"CDWwQtWj\",\"plans_2026-03-10-simulator-debug-design.md\":\"BZibn7uw\",\"plans_2026-03-10-simulator-events-console-design.md\":\"BVmEzCbR\",\"plans_2026-03-10-simulator-events-console-implementation-plan.md\":\"S2f1zs9-\",\"plans_2026-03-10-simulator-runtime-controls-design.md\":\"mqeNaYgg\",\"plans_2026-03-10-simulator-runtime-controls-implementation-plan.md\":\"BXG1UWFt\",\"plans_2026-03-10-testing-rollout-next-steps-plan.md\":\"CGR6uZic\",\"plans_2026-03-11-simulator-logger-dump-implementation-plan.md\":\"Ck5BGdoX\",\"records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md\":\"BbQpA41Y\",\"records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md\":\"DbHxPv4D\",\"records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md\":\"w7--2hvH\",\"records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md\":\"B6gIem2P\",\"records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md\":\"GGWCjkok\",\"records_bugs_2026-03-11-render-result-runtime-sync-bugfix.md\":\"DRNUuaFT\",\"records_plans_2026-03-02-furniture-feature-plan.md\":\"CqSsyNDo\",\"records_plans_2026-03-05-testing-infrastructure-design.md\":\"DLHGz5Ez\",\"records_plans_2026-03-10-simulator-events-console-plan.md\":\"CfHLEHcc\",\"records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md\":\"Z2RoK239\",\"records_plans_2026-03-10-simulator-map-parsed-view-plan.md\":\"S9jPz75o\",\"records_plans_2026-03-10-simulator-map-playground-refactor-plan.md\":\"BuILlmcV\",\"records_plans_2026-03-10-simulator-playground-plan.md\":\"CQAR-T7p\",\"records_plans_2026-03-10-simulator-runtime-controls-plan.md\":\"DSVD-qCa\",\"records_plans_2026-03-11-docs-cli-ui-polish-plan.md\":\"B8oZt_5R\",\"records_plans_2026-03-11-simulator-logger-dump-plan.md\":\"CkjDCM2N\",\"records_plans_2026-03-11-simulator-src-migration-implementation.md\":\"FnB5Cx6R\",\"records_plans_2026-03-11-simulator-src-migration-plan.md\":\"BBfaeRrq\",\"records_plans_2026-03-11-simulator-style-tokenization-plan.md\":\"D4BgkNlO\",\"reference_callbacks.md\":\"DdQU431C\",\"reference_config.md\":\"C6eF1KzO\",\"reference_data.md\":\"B_XpUFrn\",\"reference_methods.md\":\"BvtVJ2dG\",\"reference_runtime.md\":\"80-Ieel4\",\"reference_types.md\":\"hikiO8Cq\",\"reference_utils.md\":\"Dy6XKVWh\",\"simulator_index.md\":\"CF95Y_c9\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"Tuya Robot Map\",\"description\":\"涂鸦扫地机地图组件\",\"base\":\"/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"siteTitle\":\"Tuya Robot Map\",\"outline\":{\"level\":[2,6],\"label\":\"页面导航\"},\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/guide/concepts\",\"activeMatch\":\"^/guide/\"},{\"text\":\"参考\",\"link\":\"/reference/data\",\"activeMatch\":\"^/reference/\"},{\"text\":\"模拟调试\",\"link\":\"/simulator/\",\"activeMatch\":\"^/simulator/\"}],\"sidebar\":{\"/guide/\":[{\"text\":\"指南\",\"items\":[{\"text\":\"基本概念\",\"link\":\"/guide/concepts\"},{\"text\":\"快速开始\",\"link\":\"/guide/getting-started\"},{\"text\":\"进阶使用\",\"link\":\"/guide/advanced-usage\"}]}],\"/reference/\":[{\"text\":\"组件Props\",\"items\":[{\"text\":\"数据\",\"link\":\"/reference/data\"},{\"text\":\"配置\",\"link\":\"/reference/config\"},{\"text\":\"运行时\",\"link\":\"/reference/runtime\"},{\"text\":\"地图事件回调\",\"link\":\"/reference/callbacks\"}]},{\"text\":\"方法\",\"items\":[{\"text\":\"地图方法\",\"link\":\"/reference/methods\"},{\"text\":\"工具方法\",\"link\":\"/reference/utils\"}]},{\"text\":\"类型定义\",\"items\":[{\"text\":\"类型定义\",\"link\":\"/reference/types\"}]}],\"/simulator/\":[{\"text\":\"模拟调试\",\"items\":[{\"text\":\"实时模拟调试\",\"link\":\"/simulator/\"}]}]},\"search\":{\"provider\":\"local\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\"}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
39
+
40
+ </body>
41
+ </html>