@ray-js/robot-map-sdk 0.0.9 → 0.0.11

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 (139) hide show
  1. package/bin/docs-server.js +195 -0
  2. package/dist/index.d.ts +355 -3818
  3. package/dist-docs/404.html +3 -3
  4. package/dist-docs/assets/{app.BJnAJzet.js → app.3-ianRvb.js} +1 -1
  5. package/dist-docs/assets/chunks/@localSearchIndexroot.l5uunL9n.js +1 -0
  6. package/dist-docs/assets/chunks/BitmapFont.C8awBCd1.js +4 -0
  7. package/dist-docs/assets/chunks/BufferResource.C5TLxka4.js +155 -0
  8. package/dist-docs/assets/chunks/CanvasRenderer.DyglCOE2.js +1 -0
  9. package/dist-docs/assets/chunks/RenderTargetSystem._cMCUdmu.js +172 -0
  10. package/dist-docs/assets/chunks/{VPLocalSearchBox.D9iYIKMO.js → VPLocalSearchBox.DYzATQt_.js} +2 -2
  11. package/dist-docs/assets/chunks/WebGLRenderer.C_pauwH4.js +156 -0
  12. package/dist-docs/assets/chunks/WebGPURenderer.DuRPdsh5.js +41 -0
  13. package/dist-docs/assets/chunks/browserAll.BebatlLr.js +14 -0
  14. package/dist-docs/assets/chunks/framework.CBLqO2Q1.js +18 -0
  15. package/dist-docs/assets/chunks/index.DR0yN-kU.js +744 -0
  16. package/dist-docs/assets/chunks/json-editor-vue.CBQvp8j1.js +3882 -0
  17. package/dist-docs/assets/chunks/mapValues.D2X8cRgC.js +1 -0
  18. package/dist-docs/assets/chunks/theme.Dn4kNa0x.js +4 -0
  19. package/dist-docs/assets/chunks/vanilla-picker.B6E6ObS_.js +8 -0
  20. package/dist-docs/assets/chunks/webworkerAll.BAL0vGum.js +56 -0
  21. package/dist-docs/assets/doubleBed.CzextF6m.png +0 -0
  22. package/dist-docs/assets/{guide_advanced-usage.md.BPrKHNKt.js → guide_advanced-usage.md.COVLyRkA.js} +96 -3
  23. package/dist-docs/assets/guide_advanced-usage.md.COVLyRkA.lean.js +1 -0
  24. package/dist-docs/assets/{guide_concepts.md.DBFk-g-l.js → guide_concepts.md.CJ87tk-r.js} +1 -1
  25. package/dist-docs/assets/{guide_concepts.md.DBFk-g-l.lean.js → guide_concepts.md.CJ87tk-r.lean.js} +1 -1
  26. package/dist-docs/assets/{guide_getting-started.md.Zvm4buzY.js → guide_getting-started.md.DzTPTYGC.js} +2 -2
  27. package/dist-docs/assets/guide_getting-started.md.DzTPTYGC.lean.js +1 -0
  28. package/dist-docs/assets/{guide_mcp.md.1UIpY4E0.js → guide_mcp.md.CabCiX8Z.js} +1 -1
  29. package/dist-docs/assets/{guide_mcp.md.1UIpY4E0.lean.js → guide_mcp.md.CabCiX8Z.lean.js} +1 -1
  30. package/dist-docs/assets/{index.md.Sm6vD2Gl.js → index.md.wTsFvv0N.js} +1 -1
  31. package/dist-docs/assets/{index.md.Sm6vD2Gl.lean.js → index.md.wTsFvv0N.lean.js} +1 -1
  32. package/dist-docs/assets/{plans_2026-03-04-detected-objects-visibility-design.md.530AI9zE.js → plans_2026-03-04-detected-objects-visibility-design.md.Dqboot5W.js} +1 -1
  33. package/dist-docs/assets/{plans_2026-03-04-detected-objects-visibility-design.md.530AI9zE.lean.js → plans_2026-03-04-detected-objects-visibility-design.md.Dqboot5W.lean.js} +1 -1
  34. package/dist-docs/assets/{plans_2026-03-04-show-detected-objects-implementation-plan.md.foeG7qiK.js → plans_2026-03-04-show-detected-objects-implementation-plan.md.CDWwQtWj.js} +1 -1
  35. package/dist-docs/assets/{plans_2026-03-04-show-detected-objects-implementation-plan.md.foeG7qiK.lean.js → plans_2026-03-04-show-detected-objects-implementation-plan.md.CDWwQtWj.lean.js} +1 -1
  36. package/dist-docs/assets/plans_2026-03-10-simulator-debug-design.md.BZibn7uw.js +1 -0
  37. package/dist-docs/assets/plans_2026-03-10-simulator-debug-design.md.BZibn7uw.lean.js +1 -0
  38. package/dist-docs/assets/plans_2026-03-10-simulator-events-console-design.md.BVmEzCbR.js +8 -0
  39. package/dist-docs/assets/plans_2026-03-10-simulator-events-console-design.md.BVmEzCbR.lean.js +1 -0
  40. package/dist-docs/assets/plans_2026-03-10-simulator-events-console-implementation-plan.md.S2f1zs9-.js +1 -0
  41. package/dist-docs/assets/plans_2026-03-10-simulator-events-console-implementation-plan.md.S2f1zs9-.lean.js +1 -0
  42. package/dist-docs/assets/plans_2026-03-10-simulator-runtime-controls-design.md.mqeNaYgg.js +1 -0
  43. package/dist-docs/assets/plans_2026-03-10-simulator-runtime-controls-design.md.mqeNaYgg.lean.js +1 -0
  44. package/dist-docs/assets/plans_2026-03-10-simulator-runtime-controls-implementation-plan.md.BXG1UWFt.js +1 -0
  45. package/dist-docs/assets/plans_2026-03-10-simulator-runtime-controls-implementation-plan.md.BXG1UWFt.lean.js +1 -0
  46. package/dist-docs/assets/{records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md.BT3816jW.js → records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md.BbQpA41Y.js} +1 -1
  47. package/dist-docs/assets/{records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md.BT3816jW.lean.js → records_bugs_2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md.BbQpA41Y.lean.js} +1 -1
  48. package/dist-docs/assets/records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md.DbHxPv4D.js +1 -0
  49. package/dist-docs/assets/records_bugs_2026-03-10-events-drawer-toolbar-scroll-bugfix.md.DbHxPv4D.lean.js +1 -0
  50. package/dist-docs/assets/records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md.w7--2hvH.js +1 -0
  51. package/dist-docs/assets/records_bugs_2026-03-10-simulator-initial-render-layout-bugfix.md.w7--2hvH.lean.js +1 -0
  52. package/dist-docs/assets/records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md.B6gIem2P.js +1 -0
  53. package/dist-docs/assets/records_bugs_2026-03-10-simulator-wheel-scroll-leak-bugfix.md.B6gIem2P.lean.js +1 -0
  54. package/dist-docs/assets/records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md.GGWCjkok.js +1 -0
  55. package/dist-docs/assets/records_bugs_2026-03-11-docs-server-bin-clean-bugfix.md.GGWCjkok.lean.js +1 -0
  56. package/dist-docs/assets/{records_plans_2026-03-02-furniture-feature-plan.md.DkXKivuL.js → records_plans_2026-03-02-furniture-feature-plan.md.CqSsyNDo.js} +1 -1
  57. package/dist-docs/assets/{records_plans_2026-03-02-furniture-feature-plan.md.DkXKivuL.lean.js → records_plans_2026-03-02-furniture-feature-plan.md.CqSsyNDo.lean.js} +1 -1
  58. package/dist-docs/assets/records_plans_2026-03-10-simulator-events-console-plan.md.CfHLEHcc.js +1 -0
  59. package/dist-docs/assets/records_plans_2026-03-10-simulator-events-console-plan.md.CfHLEHcc.lean.js +1 -0
  60. package/dist-docs/assets/records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md.Z2RoK239.js +1 -0
  61. package/dist-docs/assets/records_plans_2026-03-10-simulator-last-successful-combo-cache-plan.md.Z2RoK239.lean.js +1 -0
  62. package/dist-docs/assets/records_plans_2026-03-10-simulator-map-parsed-view-plan.md.S9jPz75o.js +1 -0
  63. package/dist-docs/assets/records_plans_2026-03-10-simulator-map-parsed-view-plan.md.S9jPz75o.lean.js +1 -0
  64. package/dist-docs/assets/records_plans_2026-03-10-simulator-map-playground-refactor-plan.md.BuILlmcV.js +1 -0
  65. package/dist-docs/assets/records_plans_2026-03-10-simulator-map-playground-refactor-plan.md.BuILlmcV.lean.js +1 -0
  66. package/dist-docs/assets/records_plans_2026-03-10-simulator-playground-plan.md.CQAR-T7p.js +1 -0
  67. package/dist-docs/assets/records_plans_2026-03-10-simulator-playground-plan.md.CQAR-T7p.lean.js +1 -0
  68. package/dist-docs/assets/records_plans_2026-03-10-simulator-runtime-controls-plan.md.DSVD-qCa.js +1 -0
  69. package/dist-docs/assets/records_plans_2026-03-10-simulator-runtime-controls-plan.md.DSVD-qCa.lean.js +1 -0
  70. package/dist-docs/assets/records_plans_2026-03-11-simulator-src-migration-implementation.md.FnB5Cx6R.js +1 -0
  71. package/dist-docs/assets/records_plans_2026-03-11-simulator-src-migration-implementation.md.FnB5Cx6R.lean.js +1 -0
  72. package/dist-docs/assets/records_plans_2026-03-11-simulator-src-migration-plan.md.BBfaeRrq.js +1 -0
  73. package/dist-docs/assets/records_plans_2026-03-11-simulator-src-migration-plan.md.BBfaeRrq.lean.js +1 -0
  74. package/dist-docs/assets/{reference_callbacks.md.CwvDSJWk.js → reference_callbacks.md.BIwuGR3s.js} +16 -2
  75. package/dist-docs/assets/reference_callbacks.md.BIwuGR3s.lean.js +1 -0
  76. package/dist-docs/assets/{reference_config.md.CK4ueBig.js → reference_config.md.DHynhVxG.js} +1 -1
  77. package/dist-docs/assets/{reference_config.md.CK4ueBig.lean.js → reference_config.md.DHynhVxG.lean.js} +1 -1
  78. package/dist-docs/assets/{reference_data.md.DciSLVC8.js → reference_data.md.B_XpUFrn.js} +38 -2
  79. package/dist-docs/assets/reference_data.md.B_XpUFrn.lean.js +1 -0
  80. package/dist-docs/assets/{reference_methods.md.CL2sjTJ7.js → reference_methods.md.eH-UCMbE.js} +23 -3
  81. package/dist-docs/assets/reference_methods.md.eH-UCMbE.lean.js +1 -0
  82. package/dist-docs/assets/{reference_runtime.md.aDpGKfHs.js → reference_runtime.md.BEy8BhSZ.js} +2 -2
  83. package/dist-docs/assets/reference_runtime.md.BEy8BhSZ.lean.js +1 -0
  84. package/dist-docs/assets/{reference_types.md.D2IglsHQ.js → reference_types.md.hikiO8Cq.js} +20 -3
  85. package/dist-docs/assets/reference_types.md.hikiO8Cq.lean.js +1 -0
  86. package/dist-docs/assets/{reference_utils.md.CSshxnp0.js → reference_utils.md.Dy6XKVWh.js} +1 -1
  87. package/dist-docs/assets/{reference_utils.md.CSshxnp0.lean.js → reference_utils.md.Dy6XKVWh.lean.js} +1 -1
  88. package/dist-docs/assets/robot.CSiuukeH.png +0 -0
  89. package/dist-docs/assets/simulator_index.md.CF95Y_c9.js +1 -0
  90. package/dist-docs/assets/simulator_index.md.CF95Y_c9.lean.js +1 -0
  91. package/dist-docs/assets/sleep.CRKZ3XeQ.png +0 -0
  92. package/dist-docs/assets/sleep.C_YKDk6M.json +879 -0
  93. package/dist-docs/assets/{style.CN_tJoU2.css → style.DrlDtCux.css} +1 -1
  94. package/dist-docs/guide/advanced-usage.html +102 -9
  95. package/dist-docs/guide/concepts.html +7 -7
  96. package/dist-docs/guide/getting-started.html +7 -7
  97. package/dist-docs/guide/mcp.html +7 -7
  98. package/dist-docs/hashmap.json +1 -1
  99. package/dist-docs/index.html +7 -7
  100. package/dist-docs/plans/2026-03-04-detected-objects-visibility-design.html +7 -7
  101. package/dist-docs/plans/2026-03-04-show-detected-objects-implementation-plan.html +7 -7
  102. package/dist-docs/plans/2026-03-10-simulator-debug-design.html +25 -0
  103. package/dist-docs/plans/2026-03-10-simulator-events-console-design.html +32 -0
  104. package/dist-docs/plans/2026-03-10-simulator-events-console-implementation-plan.html +25 -0
  105. package/dist-docs/plans/2026-03-10-simulator-runtime-controls-design.html +25 -0
  106. package/dist-docs/plans/2026-03-10-simulator-runtime-controls-implementation-plan.html +25 -0
  107. package/dist-docs/records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.html +7 -7
  108. package/dist-docs/records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.html +25 -0
  109. package/dist-docs/records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.html +25 -0
  110. package/dist-docs/records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.html +25 -0
  111. package/dist-docs/records/bugs/2026-03-11-docs-server-bin-clean-bugfix.html +25 -0
  112. package/dist-docs/records/plans/2026-03-02-furniture-feature-plan.html +7 -7
  113. package/dist-docs/records/plans/2026-03-10-simulator-events-console-plan.html +25 -0
  114. package/dist-docs/records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.html +25 -0
  115. package/dist-docs/records/plans/2026-03-10-simulator-map-parsed-view-plan.html +25 -0
  116. package/dist-docs/records/plans/2026-03-10-simulator-map-playground-refactor-plan.html +25 -0
  117. package/dist-docs/records/plans/2026-03-10-simulator-playground-plan.html +25 -0
  118. package/dist-docs/records/plans/2026-03-10-simulator-runtime-controls-plan.html +25 -0
  119. package/dist-docs/records/plans/2026-03-11-simulator-src-migration-implementation.html +25 -0
  120. package/dist-docs/records/plans/2026-03-11-simulator-src-migration-plan.html +25 -0
  121. package/dist-docs/reference/callbacks.html +22 -8
  122. package/dist-docs/reference/config.html +7 -7
  123. package/dist-docs/reference/data.html +44 -8
  124. package/dist-docs/reference/methods.html +29 -9
  125. package/dist-docs/reference/runtime.html +8 -8
  126. package/dist-docs/reference/types.html +26 -9
  127. package/dist-docs/reference/utils.html +7 -7
  128. package/dist-docs/simulator/index.html +25 -0
  129. package/package.json +8 -4
  130. package/dist-docs/assets/chunks/@localSearchIndexroot.HZmZuAtg.js +0 -1
  131. package/dist-docs/assets/chunks/framework.DRADY2L-.js +0 -18
  132. package/dist-docs/assets/chunks/theme.D78lSkQK.js +0 -2
  133. package/dist-docs/assets/guide_advanced-usage.md.BPrKHNKt.lean.js +0 -1
  134. package/dist-docs/assets/guide_getting-started.md.Zvm4buzY.lean.js +0 -1
  135. package/dist-docs/assets/reference_callbacks.md.CwvDSJWk.lean.js +0 -1
  136. package/dist-docs/assets/reference_data.md.DciSLVC8.lean.js +0 -1
  137. package/dist-docs/assets/reference_methods.md.CL2sjTJ7.lean.js +0 -1
  138. package/dist-docs/assets/reference_runtime.md.aDpGKfHs.lean.js +0 -1
  139. package/dist-docs/assets/reference_types.md.D2IglsHQ.lean.js +0 -1
@@ -1 +1 @@
1
- import{_ as t,c as i,o as a,ag as o}from"./chunks/framework.DRADY2L-.js";const p=JSON.parse('{"title":"Detected objects visibility toggle design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-detected-objects-visibility-design.md","filePath":"plans/2026-03-04-detected-objects-visibility-design.md","lastUpdated":1772624993000}'),d={name:"plans/2026-03-04-detected-objects-visibility-design.md"};function c(s,e,l,n,r,u){return a(),i("div",null,[...e[0]||(e[0]=[o('<h1 id="detected-objects-visibility-toggle-design" tabindex="-1">Detected objects visibility toggle design <a class="header-anchor" href="#detected-objects-visibility-toggle-design" aria-label="Permalink to &quot;Detected objects visibility toggle design&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>The SDK already supports rendering detected objects through <code>drawDetectedObjects()</code>, but it does not provide a runtime switch to hide or show them. This design adds <code>runtime.showDetectedObjects</code> so callers can toggle visibility without changing detected object data.</p><h2 id="goal-and-scope" tabindex="-1">Goal and scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal and scope&quot;">​</a></h2><p>This design defines how to add a runtime visibility toggle for detected objects.</p><ul><li>Add <code>runtime.showDetectedObjects</code> with a default value of <code>true</code>.</li><li>Let consumers hide and show all detected objects at runtime.</li><li>Keep existing detected object data synchronization behavior unchanged.</li></ul><p>Out of scope:</p><ul><li>Per-object visibility flags.</li><li>New public methods for detected object visibility.</li><li>Data deletion when visibility is turned off.</li></ul><h2 id="approaches-considered" tabindex="-1">Approaches considered <a class="header-anchor" href="#approaches-considered" aria-label="Permalink to &quot;Approaches considered&quot;">​</a></h2><p>This section summarizes three options and their trade-offs.</p><ol><li><p><strong>Recommended: manager-level runtime subscription</strong></p><ul><li>Add <code>showDetectedObjects</code> to runtime types and defaults.</li><li>Subscribe in <code>DetectedObjectManager</code> and toggle <code>LAYER_DETECTED_OBJECT.visible</code>.</li><li>Pros: aligns with current manager pattern, minimal code impact, no unnecessary object recreation.</li><li>Cons: requires one additional subscription and cleanup path.</li></ul></li><li><p><strong>MapApplication-level runtime dispatch</strong></p><ul><li>Detect runtime changes in <code>MapApplication.updateRuntime()</code> and call a manager method.</li><li>Pros: centralized runtime handling.</li><li>Cons: increases coupling and makes <code>updateRuntime()</code> heavier over time.</li></ul></li><li><p><strong>Per-object subscription in DetectedObject component</strong></p><ul><li>Each detected object subscribes to runtime visibility updates.</li><li>Pros: local component autonomy.</li><li>Cons: scales poorly with many objects and adds avoidable subscription overhead.</li></ul></li></ol><h2 id="selected-design" tabindex="-1">Selected design <a class="header-anchor" href="#selected-design" aria-label="Permalink to &quot;Selected design&quot;">​</a></h2><p>The selected design uses option 1: manager-level runtime subscription.</p><h3 id="runtime-schema-and-defaults" tabindex="-1">Runtime schema and defaults <a class="header-anchor" href="#runtime-schema-and-defaults" aria-label="Permalink to &quot;Runtime schema and defaults&quot;">​</a></h3><p>Add a new runtime field:</p><ul><li><code>RuntimeConfig.showDetectedObjects: boolean</code></li><li><code>DEFAULT_RUNTIME_CONFIG.showDetectedObjects = true</code></li></ul><p>This keeps backward compatibility because current behavior is to render detected objects by default.</p><h3 id="rendering-control-point" tabindex="-1">Rendering control point <a class="header-anchor" href="#rendering-control-point" aria-label="Permalink to &quot;Rendering control point&quot;">​</a></h3><p><code>DetectedObjectManager</code> becomes the single control point for this visibility state.</p><ul><li>On initialization, subscribe to <code>runtime.showDetectedObjects</code>.</li><li>In the callback, read <code>LAYER_DETECTED_OBJECT</code> from <code>AppContainer</code> and set the layer visibility.</li><li>Keep <code>drawDetectedObjects()</code> behavior unchanged for create/update/remove data flow.</li></ul><p>This means visibility control is independent from data synchronization.</p><h3 id="lifecycle-and-cleanup" tabindex="-1">Lifecycle and cleanup <a class="header-anchor" href="#lifecycle-and-cleanup" aria-label="Permalink to &quot;Lifecycle and cleanup&quot;">​</a></h3><p><code>DetectedObjectManager.destroy()</code> must also unsubscribe from the new runtime listener to avoid stale callbacks.</p><h2 id="impacted-files" tabindex="-1">Impacted files <a class="header-anchor" href="#impacted-files" aria-label="Permalink to &quot;Impacted files&quot;">​</a></h2><p>This change affects the following files.</p><ul><li><code>src/core/@types/index.d.ts</code><ul><li>Add <code>showDetectedObjects</code> to <code>RuntimeConfig</code>.</li></ul></li><li><code>src/core/constant/config.ts</code><ul><li>Add <code>showDetectedObjects: true</code> to <code>DEFAULT_RUNTIME_CONFIG</code>.</li></ul></li><li><code>src/core/managers/DetectedObjectManager.ts</code><ul><li>Add runtime subscription and layer visibility toggle.</li><li>Add unsubscribe cleanup in <code>destroy()</code>.</li></ul></li><li><code>src/app/debugTools/index.ts</code> (optional) <ul><li>Add a debug toggle action for <code>showDetectedObjects</code>.</li></ul></li></ul><h2 id="edge-cases" tabindex="-1">Edge cases <a class="header-anchor" href="#edge-cases" aria-label="Permalink to &quot;Edge cases&quot;">​</a></h2><p>The implementation handles these expected cases.</p><ul><li>If the detected object layer is not available yet, the visibility callback exits safely.</li><li>If visibility is off and new detected object data arrives, manager data state still updates, and objects become visible immediately after toggling on.</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><p>Per user request, this task does not include a dedicated test execution step.</p><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>After this design is accepted, create an implementation plan and then apply the code changes in the impacted files.</p>',33)])])}const b=t(d,[["render",c]]);export{p as __pageData,b as default};
1
+ import{_ as t,c as i,o as a,aq as o}from"./chunks/framework.CBLqO2Q1.js";const p=JSON.parse('{"title":"Detected objects visibility toggle design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-detected-objects-visibility-design.md","filePath":"plans/2026-03-04-detected-objects-visibility-design.md","lastUpdated":1772624993000}'),d={name:"plans/2026-03-04-detected-objects-visibility-design.md"};function c(s,e,l,n,r,u){return a(),i("div",null,[...e[0]||(e[0]=[o('<h1 id="detected-objects-visibility-toggle-design" tabindex="-1">Detected objects visibility toggle design <a class="header-anchor" href="#detected-objects-visibility-toggle-design" aria-label="Permalink to &quot;Detected objects visibility toggle design&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>The SDK already supports rendering detected objects through <code>drawDetectedObjects()</code>, but it does not provide a runtime switch to hide or show them. This design adds <code>runtime.showDetectedObjects</code> so callers can toggle visibility without changing detected object data.</p><h2 id="goal-and-scope" tabindex="-1">Goal and scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal and scope&quot;">​</a></h2><p>This design defines how to add a runtime visibility toggle for detected objects.</p><ul><li>Add <code>runtime.showDetectedObjects</code> with a default value of <code>true</code>.</li><li>Let consumers hide and show all detected objects at runtime.</li><li>Keep existing detected object data synchronization behavior unchanged.</li></ul><p>Out of scope:</p><ul><li>Per-object visibility flags.</li><li>New public methods for detected object visibility.</li><li>Data deletion when visibility is turned off.</li></ul><h2 id="approaches-considered" tabindex="-1">Approaches considered <a class="header-anchor" href="#approaches-considered" aria-label="Permalink to &quot;Approaches considered&quot;">​</a></h2><p>This section summarizes three options and their trade-offs.</p><ol><li><p><strong>Recommended: manager-level runtime subscription</strong></p><ul><li>Add <code>showDetectedObjects</code> to runtime types and defaults.</li><li>Subscribe in <code>DetectedObjectManager</code> and toggle <code>LAYER_DETECTED_OBJECT.visible</code>.</li><li>Pros: aligns with current manager pattern, minimal code impact, no unnecessary object recreation.</li><li>Cons: requires one additional subscription and cleanup path.</li></ul></li><li><p><strong>MapApplication-level runtime dispatch</strong></p><ul><li>Detect runtime changes in <code>MapApplication.updateRuntime()</code> and call a manager method.</li><li>Pros: centralized runtime handling.</li><li>Cons: increases coupling and makes <code>updateRuntime()</code> heavier over time.</li></ul></li><li><p><strong>Per-object subscription in DetectedObject component</strong></p><ul><li>Each detected object subscribes to runtime visibility updates.</li><li>Pros: local component autonomy.</li><li>Cons: scales poorly with many objects and adds avoidable subscription overhead.</li></ul></li></ol><h2 id="selected-design" tabindex="-1">Selected design <a class="header-anchor" href="#selected-design" aria-label="Permalink to &quot;Selected design&quot;">​</a></h2><p>The selected design uses option 1: manager-level runtime subscription.</p><h3 id="runtime-schema-and-defaults" tabindex="-1">Runtime schema and defaults <a class="header-anchor" href="#runtime-schema-and-defaults" aria-label="Permalink to &quot;Runtime schema and defaults&quot;">​</a></h3><p>Add a new runtime field:</p><ul><li><code>RuntimeConfig.showDetectedObjects: boolean</code></li><li><code>DEFAULT_RUNTIME_CONFIG.showDetectedObjects = true</code></li></ul><p>This keeps backward compatibility because current behavior is to render detected objects by default.</p><h3 id="rendering-control-point" tabindex="-1">Rendering control point <a class="header-anchor" href="#rendering-control-point" aria-label="Permalink to &quot;Rendering control point&quot;">​</a></h3><p><code>DetectedObjectManager</code> becomes the single control point for this visibility state.</p><ul><li>On initialization, subscribe to <code>runtime.showDetectedObjects</code>.</li><li>In the callback, read <code>LAYER_DETECTED_OBJECT</code> from <code>AppContainer</code> and set the layer visibility.</li><li>Keep <code>drawDetectedObjects()</code> behavior unchanged for create/update/remove data flow.</li></ul><p>This means visibility control is independent from data synchronization.</p><h3 id="lifecycle-and-cleanup" tabindex="-1">Lifecycle and cleanup <a class="header-anchor" href="#lifecycle-and-cleanup" aria-label="Permalink to &quot;Lifecycle and cleanup&quot;">​</a></h3><p><code>DetectedObjectManager.destroy()</code> must also unsubscribe from the new runtime listener to avoid stale callbacks.</p><h2 id="impacted-files" tabindex="-1">Impacted files <a class="header-anchor" href="#impacted-files" aria-label="Permalink to &quot;Impacted files&quot;">​</a></h2><p>This change affects the following files.</p><ul><li><code>src/core/@types/index.d.ts</code><ul><li>Add <code>showDetectedObjects</code> to <code>RuntimeConfig</code>.</li></ul></li><li><code>src/core/constant/config.ts</code><ul><li>Add <code>showDetectedObjects: true</code> to <code>DEFAULT_RUNTIME_CONFIG</code>.</li></ul></li><li><code>src/core/managers/DetectedObjectManager.ts</code><ul><li>Add runtime subscription and layer visibility toggle.</li><li>Add unsubscribe cleanup in <code>destroy()</code>.</li></ul></li><li><code>src/app/debugTools/index.ts</code> (optional) <ul><li>Add a debug toggle action for <code>showDetectedObjects</code>.</li></ul></li></ul><h2 id="edge-cases" tabindex="-1">Edge cases <a class="header-anchor" href="#edge-cases" aria-label="Permalink to &quot;Edge cases&quot;">​</a></h2><p>The implementation handles these expected cases.</p><ul><li>If the detected object layer is not available yet, the visibility callback exits safely.</li><li>If visibility is off and new detected object data arrives, manager data state still updates, and objects become visible immediately after toggling on.</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><p>Per user request, this task does not include a dedicated test execution step.</p><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>After this design is accepted, create an implementation plan and then apply the code changes in the impacted files.</p>',33)])])}const b=t(d,[["render",c]]);export{p as __pageData,b as default};
@@ -1 +1 @@
1
- import{_ as t,c as i,o as a,ag as o}from"./chunks/framework.DRADY2L-.js";const p=JSON.parse('{"title":"Detected objects visibility toggle design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-detected-objects-visibility-design.md","filePath":"plans/2026-03-04-detected-objects-visibility-design.md","lastUpdated":1772624993000}'),d={name:"plans/2026-03-04-detected-objects-visibility-design.md"};function c(s,e,l,n,r,u){return a(),i("div",null,[...e[0]||(e[0]=[o("",33)])])}const b=t(d,[["render",c]]);export{p as __pageData,b as default};
1
+ import{_ as t,c as i,o as a,aq as o}from"./chunks/framework.CBLqO2Q1.js";const p=JSON.parse('{"title":"Detected objects visibility toggle design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-detected-objects-visibility-design.md","filePath":"plans/2026-03-04-detected-objects-visibility-design.md","lastUpdated":1772624993000}'),d={name:"plans/2026-03-04-detected-objects-visibility-design.md"};function c(s,e,l,n,r,u){return a(),i("div",null,[...e[0]||(e[0]=[o("",33)])])}const b=t(d,[["render",c]]);export{p as __pageData,b as default};
@@ -1,4 +1,4 @@
1
- import{_ as i,c as e,o as t,ag as a}from"./chunks/framework.DRADY2L-.js";const c=JSON.parse('{"title":"Show detected objects runtime toggle implementation plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","filePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","lastUpdated":1772624993000}'),n={name:"plans/2026-03-04-show-detected-objects-implementation-plan.md"};function l(p,s,h,d,r,o){return t(),e("div",null,[...s[0]||(s[0]=[a(`<h1 id="show-detected-objects-runtime-toggle-implementation-plan" tabindex="-1">Show detected objects runtime toggle implementation plan <a class="header-anchor" href="#show-detected-objects-runtime-toggle-implementation-plan" aria-label="Permalink to &quot;Show detected objects runtime toggle 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 <code>runtime.showDetectedObjects</code> to control detected object visibility at runtime, with default behavior unchanged (<code>true</code>).</p><p><strong>Architecture:</strong> Extend runtime schema and defaults, then subscribe to the new runtime field inside <code>DetectedObjectManager</code> to toggle <code>LAYER_DETECTED_OBJECT.visible</code>. Keep <code>drawDetectedObjects()</code> data sync logic unchanged so visibility control stays independent from object CRUD.</p><p><strong>Tech Stack:</strong> TypeScript, PIXI.js 8 layer containers, Valtio <code>subscribeKey</code>, VitePress docs.</p><hr><h2 id="constraints-and-scope" tabindex="-1">Constraints and scope <a class="header-anchor" href="#constraints-and-scope" aria-label="Permalink to &quot;Constraints and scope&quot;">​</a></h2><p>This plan follows these constraints:</p><ul><li>Implement only the requested feature.</li><li>Do not add or run dedicated feature tests (explicit user request).</li><li>Keep project-required static verification (<code>npm run lint</code>, <code>npx tsc --noEmit</code>).</li><li>Do not create commits unless the user explicitly requests a commit.</li></ul><h2 id="task-1-add-runtime-type-field" tabindex="-1">Task 1: Add runtime type field <a class="header-anchor" href="#task-1-add-runtime-type-field" aria-label="Permalink to &quot;Task 1: Add runtime type field&quot;">​</a></h2><p><strong>Files:</strong></p><ul><li>Modify: <code>src/core/@types/index.d.ts:639-651</code></li></ul><p><strong>Step 1: Add <code>showDetectedObjects</code> to <code>RuntimeConfig</code></strong></p><p>Insert a new boolean field near existing visibility toggles:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">/** 是否显示 AI 检测物体 */</span></span>
1
+ import{_ as i,c as e,o as t,aq as a}from"./chunks/framework.CBLqO2Q1.js";const c=JSON.parse('{"title":"Show detected objects runtime toggle implementation plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","filePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","lastUpdated":1772624993000}'),n={name:"plans/2026-03-04-show-detected-objects-implementation-plan.md"};function l(p,s,h,d,r,o){return t(),e("div",null,[...s[0]||(s[0]=[a(`<h1 id="show-detected-objects-runtime-toggle-implementation-plan" tabindex="-1">Show detected objects runtime toggle implementation plan <a class="header-anchor" href="#show-detected-objects-runtime-toggle-implementation-plan" aria-label="Permalink to &quot;Show detected objects runtime toggle 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 <code>runtime.showDetectedObjects</code> to control detected object visibility at runtime, with default behavior unchanged (<code>true</code>).</p><p><strong>Architecture:</strong> Extend runtime schema and defaults, then subscribe to the new runtime field inside <code>DetectedObjectManager</code> to toggle <code>LAYER_DETECTED_OBJECT.visible</code>. Keep <code>drawDetectedObjects()</code> data sync logic unchanged so visibility control stays independent from object CRUD.</p><p><strong>Tech Stack:</strong> TypeScript, PIXI.js 8 layer containers, Valtio <code>subscribeKey</code>, VitePress docs.</p><hr><h2 id="constraints-and-scope" tabindex="-1">Constraints and scope <a class="header-anchor" href="#constraints-and-scope" aria-label="Permalink to &quot;Constraints and scope&quot;">​</a></h2><p>This plan follows these constraints:</p><ul><li>Implement only the requested feature.</li><li>Do not add or run dedicated feature tests (explicit user request).</li><li>Keep project-required static verification (<code>npm run lint</code>, <code>npx tsc --noEmit</code>).</li><li>Do not create commits unless the user explicitly requests a commit.</li></ul><h2 id="task-1-add-runtime-type-field" tabindex="-1">Task 1: Add runtime type field <a class="header-anchor" href="#task-1-add-runtime-type-field" aria-label="Permalink to &quot;Task 1: Add runtime type field&quot;">​</a></h2><p><strong>Files:</strong></p><ul><li>Modify: <code>src/core/@types/index.d.ts:639-651</code></li></ul><p><strong>Step 1: Add <code>showDetectedObjects</code> to <code>RuntimeConfig</code></strong></p><p>Insert a new boolean field near existing visibility toggles:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">/** 是否显示 AI 检测物体 */</span></span>
2
2
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">showDetectedObjects</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: boolean</span></span></code></pre></div><p><strong>Step 2: Keep property order stable in visibility section</strong></p><p>Place <code>showDetectedObjects</code> after <code>showCarpet</code> so related runtime flags stay clustered.</p><h2 id="task-2-add-runtime-default-value" tabindex="-1">Task 2: Add runtime default value <a class="header-anchor" href="#task-2-add-runtime-default-value" aria-label="Permalink to &quot;Task 2: Add runtime default value&quot;">​</a></h2><p><strong>Files:</strong></p><ul><li>Modify: <code>src/core/constant/config.ts:635-651</code></li></ul><p><strong>Step 1: Add default value in <code>DEFAULT_RUNTIME_CONFIG</code></strong></p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</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;">showCarpet</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
3
3
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">showDetectedObjects</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
4
4
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">showChargingStationRing</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span></code></pre></div><p><strong>Step 2: Keep backward-compatible default behavior</strong></p><p>Ensure the default is <code>true</code> so existing integrations continue to display objects without additional config.</p><h2 id="task-3-add-manager-level-visibility-subscription" tabindex="-1">Task 3: Add manager-level visibility subscription <a class="header-anchor" href="#task-3-add-manager-level-visibility-subscription" aria-label="Permalink to &quot;Task 3: Add manager-level visibility subscription&quot;">​</a></h2><p><strong>Files:</strong></p><ul><li>Modify: <code>src/core/managers/DetectedObjectManager.ts:1-121</code></li></ul><p><strong>Step 1: Add Valtio subscription import</strong></p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { subscribeKey } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;valtio/vanilla/utils&#39;</span></span></code></pre></div><p><strong>Step 2: Add unsubscribe holder</strong></p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">private </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">unsubscribeShowDetectedObjects</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: (() </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> void</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">|</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span></span></code></pre></div><p><strong>Step 3: Initialize layer visibility from runtime in constructor</strong></p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</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;">constructor</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(private appService: AppService) {</span></span>
@@ -1 +1 @@
1
- import{_ as i,c as e,o as t,ag as a}from"./chunks/framework.DRADY2L-.js";const c=JSON.parse('{"title":"Show detected objects runtime toggle implementation plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","filePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","lastUpdated":1772624993000}'),n={name:"plans/2026-03-04-show-detected-objects-implementation-plan.md"};function l(p,s,h,d,r,o){return t(),e("div",null,[...s[0]||(s[0]=[a("",70)])])}const g=i(n,[["render",l]]);export{c as __pageData,g as default};
1
+ import{_ as i,c as e,o as t,aq as a}from"./chunks/framework.CBLqO2Q1.js";const c=JSON.parse('{"title":"Show detected objects runtime toggle implementation plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","filePath":"plans/2026-03-04-show-detected-objects-implementation-plan.md","lastUpdated":1772624993000}'),n={name:"plans/2026-03-04-show-detected-objects-implementation-plan.md"};function l(p,s,h,d,r,o){return t(),e("div",null,[...s[0]||(s[0]=[a("",70)])])}const g=i(n,[["render",l]]);export{c as __pageData,g as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as i,o,aq as t}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator debug design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-debug-design.md","filePath":"plans/2026-03-10-simulator-debug-design.md","lastUpdated":1773123455000}'),l={name:"plans/2026-03-10-simulator-debug-design.md"};function n(d,e,r,s,c,u){return o(),i("div",null,[...e[0]||(e[0]=[t('<h1 id="simulator-debug-design" tabindex="-1">Simulator debug design <a class="header-anchor" href="#simulator-debug-design" aria-label="Permalink to &quot;Simulator debug 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 docs need an embedded simulator panel so developers can paste map payloads and validate rendering without leaving VitePress.</p><h2 id="scope" tabindex="-1">Scope <a class="header-anchor" href="#scope" aria-label="Permalink to &quot;Scope&quot;">​</a></h2><ul><li>Add a new top-level docs section: <code>simulator</code>.</li><li>Build a lightweight playground component with a clean UI.</li><li>Support <code>mapHex</code> (required), <code>pathHex</code> (optional), and <code>roomProperties</code> JSON (optional).</li></ul><h2 id="design-choices" tabindex="-1">Design choices <a class="header-anchor" href="#design-choices" aria-label="Permalink to &quot;Design choices&quot;">​</a></h2><ol><li>Keep implementation independent from <code>src/app/debugTools</code>.</li><li>Use a browser-only VitePress component and wrap it with <code>ClientOnly</code>.</li><li>Determine map type from input prefix: <ul><li><code>7b22</code>: structured map</li><li>otherwise: raster map</li></ul></li><li>Default sample input uses only <code>mapHex</code> from existing mock data.</li><li>Provide full-screen editing for long payloads.</li></ol><h2 id="ux" tabindex="-1">UX <a class="header-anchor" href="#ux" aria-label="Permalink to &quot;UX&quot;">​</a></h2><ul><li>Two-column layout on desktop, stacked layout on mobile.</li><li>Explicit render action instead of auto-render while typing.</li><li>Inline status and error messages with field-level failure context.</li></ul><h2 id="verification" tabindex="-1">Verification <a class="header-anchor" href="#verification" aria-label="Permalink to &quot;Verification&quot;">​</a></h2><ul><li>New nav item <code>模拟调试</code> appears next to <code>参考</code>.</li><li><code>/simulator/</code> renders and can draw map from default sample.</li><li>Optional inputs can be empty without blocking map rendering.</li></ul>',11)])])}const h=a(l,[["render",n]]);export{m as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as i,o,aq as t}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator debug design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-debug-design.md","filePath":"plans/2026-03-10-simulator-debug-design.md","lastUpdated":1773123455000}'),l={name:"plans/2026-03-10-simulator-debug-design.md"};function n(d,e,r,s,c,u){return o(),i("div",null,[...e[0]||(e[0]=[t("",11)])])}const h=a(l,[["render",n]]);export{m as __pageData,h as default};
@@ -0,0 +1,8 @@
1
+ import{_ as a,c as i,o as t,aq as l}from"./chunks/framework.CBLqO2Q1.js";const u=JSON.parse('{"title":"Simulator events console design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-events-console-design.md","filePath":"plans/2026-03-10-simulator-events-console-design.md","lastUpdated":1773138773000}'),o={name:"plans/2026-03-10-simulator-events-console-design.md"};function s(r,e,n,c,d,h){return t(),i("div",null,[...e[0]||(e[0]=[l(`<h1 id="simulator-events-console-design" tabindex="-1">Simulator events console design <a class="header-anchor" href="#simulator-events-console-design" aria-label="Permalink to &quot;Simulator events console 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 now covers source data input and runtime controls, but it still lacks visibility into SDK callbacks. Developers can click rooms and tune runtime values, yet they cannot see which public callbacks the SDK actually fires or inspect the payload shape without writing custom code.</p><p>This design adds an <code>Events</code> console to the simulator so developers can verify SDK callback behavior from the docs UI.</p><h2 id="goals" tabindex="-1">Goals <a class="header-anchor" href="#goals" aria-label="Permalink to &quot;Goals&quot;">​</a></h2><ul><li>Record only SDK public callbacks that are meaningful to integrators.</li><li>Show callback names exactly as they appear in <code>MapCallbacks</code>.</li><li>Make event payloads easy to scan, expand, and copy.</li><li>Keep the map preview large and preserve the simulator&#39;s minimal visual style.</li><li>Introduce a reusable UI primitive layer for popovers, tooltips, and menus without forcing a heavy component framework into the docs site.</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 record simulator-internal actions such as runtime patches, auto-render, cache restore, or example reset.</li><li>Do not build a general-purpose logging system for the SDK.</li><li>Do not add toast notifications for every callback.</li><li>Do not replace all existing simulator controls with third-party primitives 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-toast-plus-history" tabindex="-1">Option 1: toast plus history <a class="header-anchor" href="#option-1-toast-plus-history" aria-label="Permalink to &quot;Option 1: toast plus history&quot;">​</a></h3><p>Show a transient toast for each callback and also append the event to a history panel.</p><ul><li>Pros: immediate feedback.</li><li>Cons: noisy, distracts from map interaction, and scales poorly during rapid clicks.</li></ul><h3 id="option-2-dedicated-events-console" tabindex="-1">Option 2: dedicated events console <a class="header-anchor" href="#option-2-dedicated-events-console" aria-label="Permalink to &quot;Option 2: dedicated events console&quot;">​</a></h3><p>Add a fixed <code>Events</code> panel near the map. Each callback appends a structured record with a short summary and expandable JSON payload.</p><ul><li>Pros: developer-friendly, easy to filter, easy to copy, and aligned with how engineers debug SDK integrations.</li><li>Cons: weaker instant feedback than a toast, but still clear enough in a live panel.</li></ul><h3 id="option-3-console-plus-map-overlay" tabindex="-1">Option 3: console plus map overlay <a class="header-anchor" href="#option-3-console-plus-map-overlay" aria-label="Permalink to &quot;Option 3: console plus map overlay&quot;">​</a></h3><p>Combine the event console with a temporary overlay that shows the latest event inside the map preview.</p><ul><li>Pros: strongest immediate feedback.</li><li>Cons: more UI complexity and more risk of visual noise.</li></ul><p>This design uses option 2.</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 keeps the current two-column layout.</p><ul><li>Left column: <ul><li><code>Data</code></li><li><code>Runtime</code></li><li><code>Inspector</code></li></ul></li><li>Right column: <ul><li>map preview</li><li><code>Events</code></li></ul></li></ul><p>The <code>Events</code> panel belongs with the map, not with the left control column. Events are a result of interacting with the SDK surface, so the event stream should remain visually close to the preview that triggers it.</p><h2 id="event-model" tabindex="-1">Event model <a class="header-anchor" href="#event-model" aria-label="Permalink to &quot;Event model&quot;">​</a></h2><p>The event console records only SDK callbacks exposed through <code>MapCallbacks</code>.</p><p>V1 starts with callbacks that already exist and matter in the current simulator flow:</p><ul><li><code>onClickRoom</code></li><li><code>onClickRoomProperties</code></li></ul><p>Each event record has this shape:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">type</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SimulatorEventRecord</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
2
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> id</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
3
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> name</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> keyof</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> MapCallbacks</span></span>
4
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> timestamp</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> number</span></span>
5
+ <span class="line"><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> timeLabel</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> string</span></span>
6
+ <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>
7
+ <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>
8
+ <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>`,77)])])}const m=a(o,[["render",s]]);export{u as __pageData,m as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as i,o as t,aq as l}from"./chunks/framework.CBLqO2Q1.js";const u=JSON.parse('{"title":"Simulator events console design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-events-console-design.md","filePath":"plans/2026-03-10-simulator-events-console-design.md","lastUpdated":1773138773000}'),o={name:"plans/2026-03-10-simulator-events-console-design.md"};function s(r,e,n,c,d,h){return t(),i("div",null,[...e[0]||(e[0]=[l("",77)])])}const m=a(o,[["render",s]]);export{u as __pageData,m as default};
@@ -0,0 +1 @@
1
+ import{_ as t,c as o,o as a,aq as n}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator events console Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-events-console-implementation-plan.md","filePath":"plans/2026-03-10-simulator-events-console-implementation-plan.md","lastUpdated":1773138773000}'),s={name:"plans/2026-03-10-simulator-events-console-implementation-plan.md"};function l(i,e,r,p,d,c){return a(),o("div",null,[...e[0]||(e[0]=[n('<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>',80)])])}const h=t(s,[["render",l]]);export{m as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as t,c as o,o as a,aq as n}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator events console Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-events-console-implementation-plan.md","filePath":"plans/2026-03-10-simulator-events-console-implementation-plan.md","lastUpdated":1773138773000}'),s={name:"plans/2026-03-10-simulator-events-console-implementation-plan.md"};function l(i,e,r,p,d,c){return a(),o("div",null,[...e[0]||(e[0]=[n("",80)])])}const h=t(s,[["render",l]]);export{m as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as o,c as i,o as a,aq as t}from"./chunks/framework.CBLqO2Q1.js";const p=JSON.parse('{"title":"Simulator runtime controls design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-runtime-controls-design.md","filePath":"plans/2026-03-10-simulator-runtime-controls-design.md","lastUpdated":1773145284000}'),l={name:"plans/2026-03-10-simulator-runtime-controls-design.md"};function d(n,e,r,s,c,u){return a(),i("div",null,[...e[0]||(e[0]=[t('<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>',74)])])}const h=o(l,[["render",d]]);export{p as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as o,c as i,o as a,aq as t}from"./chunks/framework.CBLqO2Q1.js";const p=JSON.parse('{"title":"Simulator runtime controls design","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-runtime-controls-design.md","filePath":"plans/2026-03-10-simulator-runtime-controls-design.md","lastUpdated":1773145284000}'),l={name:"plans/2026-03-10-simulator-runtime-controls-design.md"};function d(n,e,r,s,c,u){return a(),i("div",null,[...e[0]||(e[0]=[t("",74)])])}const h=o(l,[["render",d]]);export{p as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as t,c as o,o as i,aq as n}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator runtime controls Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-runtime-controls-implementation-plan.md","filePath":"plans/2026-03-10-simulator-runtime-controls-implementation-plan.md","lastUpdated":1773145284000}'),s={name:"plans/2026-03-10-simulator-runtime-controls-implementation-plan.md"};function l(a,e,r,p,d,c){return i(),o("div",null,[...e[0]||(e[0]=[n('<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>',92)])])}const h=t(s,[["render",l]]);export{m as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as t,c as o,o as i,aq as n}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator runtime controls Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"plans/2026-03-10-simulator-runtime-controls-implementation-plan.md","filePath":"plans/2026-03-10-simulator-runtime-controls-implementation-plan.md","lastUpdated":1773145284000}'),s={name:"plans/2026-03-10-simulator-runtime-controls-implementation-plan.md"};function l(a,e,r,p,d,c){return i(),o("div",null,[...e[0]||(e[0]=[n("",92)])])}const h=t(s,[["render",l]]);export{m as __pageData,h as default};
@@ -1,2 +1,2 @@
1
- import{_ as o,c as i,o as s,ag as a}from"./chunks/framework.DRADY2L-.js";const u=JSON.parse('{"title":"2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","filePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","lastUpdated":1772253529000}'),r={name:"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md"};function t(n,e,c,l,d,h){return s(),i("div",null,[...e[0]||(e[0]=[a(`<h1 id="_2026-02-28-fix-pixi-webgpu-snapshot-roominfo-white-screen" tabindex="-1">2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen <a class="header-anchor" href="#_2026-02-28-fix-pixi-webgpu-snapshot-roominfo-white-screen" aria-label="Permalink to &quot;2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>After upgrading <code>pixi.js</code> to <code>8.16.0</code>, the WebGPU rendering flow started failing in one specific sequence: call <code>snapshotByData</code>, then render room information in the main instance.</p><p>This record captures the reproduction path, root cause, fix, and regression checklist so future Pixi upgrades are easier to verify.</p><h2 id="symptom" tabindex="-1">Symptom <a class="header-anchor" href="#symptom" aria-label="Permalink to &quot;Symptom&quot;">​</a></h2><p>In the demo, run this sequence:</p><ol><li>Render either Raster Map or Structured Map.</li><li>Click <strong>Snapshot Other Map</strong> (this triggers <code>snapshotByData</code>).</li><li>Click <strong>Draw roomInfo</strong>.</li></ol><p>The map turns white and the console reports:</p><ul><li><code>BindGroupSystem._createBindGroup</code></li><li><code>Cannot read properties of null (reading &#39;0&#39;/&#39;2&#39;)</code></li></ul><h2 id="root-cause" tabindex="-1">Root cause <a class="header-anchor" href="#root-cause" aria-label="Permalink to &quot;Root cause&quot;">​</a></h2><p>The issue is in Pixi <code>BindGroup.setResource(resource, index)</code>.</p><p>When replacing a resource, the old logic incorrectly called <code>off(&#39;change&#39;)</code> on the <strong>new</strong> resource instead of the <strong>previous</strong> resource (<code>currentResource</code>). Because of this, stale listeners can survive on the old resource. After the old resource is destroyed, it can still trigger the current BindGroup callback and null out <code>resources[i]</code>, which later crashes WebGPU bind group creation.</p><h2 id="fix" tabindex="-1">Fix <a class="header-anchor" href="#fix" aria-label="Permalink to &quot;Fix&quot;">​</a></h2><p>The project patch updates both CJS and ESM files:</p><ul><li><code>node_modules/pixi.js/lib/rendering/renderers/gpu/shader/BindGroup.js</code></li><li><code>node_modules/pixi.js/lib/rendering/renderers/gpu/shader/BindGroup.mjs</code></li></ul><p>Key change:</p><div class="language-diff vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">diff</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#B31D28;--shiki-dark:#FDAEB7;">- resource.off?.(&quot;change&quot;, this.onResourceChange, this)</span></span>
1
+ import{_ as o,c as i,o as s,aq as a}from"./chunks/framework.CBLqO2Q1.js";const u=JSON.parse('{"title":"2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","filePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","lastUpdated":1772253529000}'),r={name:"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md"};function t(n,e,c,l,d,h){return s(),i("div",null,[...e[0]||(e[0]=[a(`<h1 id="_2026-02-28-fix-pixi-webgpu-snapshot-roominfo-white-screen" tabindex="-1">2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen <a class="header-anchor" href="#_2026-02-28-fix-pixi-webgpu-snapshot-roominfo-white-screen" aria-label="Permalink to &quot;2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>After upgrading <code>pixi.js</code> to <code>8.16.0</code>, the WebGPU rendering flow started failing in one specific sequence: call <code>snapshotByData</code>, then render room information in the main instance.</p><p>This record captures the reproduction path, root cause, fix, and regression checklist so future Pixi upgrades are easier to verify.</p><h2 id="symptom" tabindex="-1">Symptom <a class="header-anchor" href="#symptom" aria-label="Permalink to &quot;Symptom&quot;">​</a></h2><p>In the demo, run this sequence:</p><ol><li>Render either Raster Map or Structured Map.</li><li>Click <strong>Snapshot Other Map</strong> (this triggers <code>snapshotByData</code>).</li><li>Click <strong>Draw roomInfo</strong>.</li></ol><p>The map turns white and the console reports:</p><ul><li><code>BindGroupSystem._createBindGroup</code></li><li><code>Cannot read properties of null (reading &#39;0&#39;/&#39;2&#39;)</code></li></ul><h2 id="root-cause" tabindex="-1">Root cause <a class="header-anchor" href="#root-cause" aria-label="Permalink to &quot;Root cause&quot;">​</a></h2><p>The issue is in Pixi <code>BindGroup.setResource(resource, index)</code>.</p><p>When replacing a resource, the old logic incorrectly called <code>off(&#39;change&#39;)</code> on the <strong>new</strong> resource instead of the <strong>previous</strong> resource (<code>currentResource</code>). Because of this, stale listeners can survive on the old resource. After the old resource is destroyed, it can still trigger the current BindGroup callback and null out <code>resources[i]</code>, which later crashes WebGPU bind group creation.</p><h2 id="fix" tabindex="-1">Fix <a class="header-anchor" href="#fix" aria-label="Permalink to &quot;Fix&quot;">​</a></h2><p>The project patch updates both CJS and ESM files:</p><ul><li><code>node_modules/pixi.js/lib/rendering/renderers/gpu/shader/BindGroup.js</code></li><li><code>node_modules/pixi.js/lib/rendering/renderers/gpu/shader/BindGroup.mjs</code></li></ul><p>Key change:</p><div class="language-diff vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">diff</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#B31D28;--shiki-dark:#FDAEB7;">- resource.off?.(&quot;change&quot;, this.onResourceChange, this)</span></span>
2
2
  <span class="line"><span style="--shiki-light:#22863A;--shiki-dark:#85E89D;">+ currentResource.off?.(&quot;change&quot;, this.onResourceChange, this)</span></span></code></pre></div><p>Patch location:</p><ul><li><code>patches/pixi.js+8.16.0.patch</code></li></ul><h2 id="risk-assessment" tabindex="-1">Risk assessment <a class="header-anchor" href="#risk-assessment" aria-label="Permalink to &quot;Risk assessment&quot;">​</a></h2><p>This is a low-intrusion lifecycle fix. It only changes listener cleanup in the resource replacement path. It does not change rendering strategy or public business APIs.</p><h2 id="regression-checklist" tabindex="-1">Regression checklist <a class="header-anchor" href="#regression-checklist" aria-label="Permalink to &quot;Regression checklist&quot;">​</a></h2><p>Run these checks after each Pixi upgrade or patch refresh:</p><ol><li>Raster -&gt; Snapshot Other Map -&gt; Draw roomInfo.</li><li>Structured -&gt; Snapshot Other Map -&gt; Draw roomInfo.</li><li>Repeat snapshot multiple times, then toggle <code>showRoomProperty</code>.</li><li>Run one core flow on both WebGPU and WebGL.</li></ol><h2 id="related-changes" tabindex="-1">Related changes <a class="header-anchor" href="#related-changes" aria-label="Permalink to &quot;Related changes&quot;">​</a></h2><ul><li><code>package.json</code>: upgrade <code>pixi.js</code> to <code>8.16.0</code></li><li><code>yarn.lock</code>: lockfile update</li><li><code>patches/pixi.js+8.16.0.patch</code>: new versioned patch (includes this fix)</li></ul>`,26)])])}const g=o(r,[["render",t]]);export{u as __pageData,g as default};
@@ -1 +1 @@
1
- import{_ as o,c as i,o as s,ag as a}from"./chunks/framework.DRADY2L-.js";const u=JSON.parse('{"title":"2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","filePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","lastUpdated":1772253529000}'),r={name:"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md"};function t(n,e,c,l,d,h){return s(),i("div",null,[...e[0]||(e[0]=[a("",26)])])}const g=o(r,[["render",t]]);export{u as __pageData,g as default};
1
+ import{_ as o,c as i,o as s,aq as a}from"./chunks/framework.CBLqO2Q1.js";const u=JSON.parse('{"title":"2026-02-28 fix: Pixi WebGPU snapshot roomInfo white screen","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","filePath":"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md","lastUpdated":1772253529000}'),r={name:"records/bugs/2026-02-28-fix-pixi-bindgroup-webgpu-snapshot-whitescreen-bugfix.md"};function t(n,e,c,l,d,h){return s(),i("div",null,[...e[0]||(e[0]=[a("",26)])])}const g=o(r,[["render",t]]);export{u as __pageData,g as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as t,o,aq as r}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Events drawer toolbar and scroll bugfix","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.md","filePath":"records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.md","lastUpdated":1773145284000}'),l={name:"records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.md"};function s(i,e,n,d,c,h){return o(),t("div",null,[...e[0]||(e[0]=[r('<h1 id="events-drawer-toolbar-and-scroll-bugfix" tabindex="-1">Events drawer toolbar and scroll bugfix <a class="header-anchor" href="#events-drawer-toolbar-and-scroll-bugfix" aria-label="Permalink to &quot;Events drawer toolbar and scroll bugfix&quot;">​</a></h1><p>This record captures a small simulator follow-up that simplified the Events panel and fixed the drawer scroll container behavior.</p><h2 id="symptom" tabindex="-1">Symptom <a class="header-anchor" href="#symptom" aria-label="Permalink to &quot;Symptom&quot;">​</a></h2><p>The Events drawer exposed controls that were not useful in the current simulator workflow. It also showed a subtle visual overflow when the event list became long. The last event card could appear to extend slightly past the visible drawer boundary.</p><h2 id="reproducible-steps" tabindex="-1">Reproducible steps <a class="header-anchor" href="#reproducible-steps" aria-label="Permalink to &quot;Reproducible steps&quot;">​</a></h2><ol><li>Open the simulator page.</li><li>Open the Events drawer from the map preview.</li><li>Trigger enough SDK callbacks to populate a longer list.</li><li>Scroll to the bottom of the drawer.</li><li>Observe that the final event item appears to sit slightly outside the container edge.</li></ol><h2 id="root-cause" tabindex="-1">Root cause <a class="header-anchor" href="#root-cause" aria-label="Permalink to &quot;Root cause&quot;">​</a></h2><p>The drawer mixed fixed-height assumptions with a scrollable list that used a <code>calc()</code>-based max-height. That layout became fragile once the drawer header and content height varied. The panel also retained extra toolbar actions that no longer matched the intended minimal UX.</p><h2 id="patch-summary" tabindex="-1">Patch summary <a class="header-anchor" href="#patch-summary" aria-label="Permalink to &quot;Patch summary&quot;">​</a></h2><ul><li>Removed the unused Events actions and kept only <code>Close</code> and <code>Clear</code>.</li><li>Simplified <code>useSimulatorEvents()</code> to remove filter, pause, and copy state.</li><li>Converted the Events drawer to a column flex layout.</li><li>Let the event list consume remaining space with <code>flex: 1</code> and <code>min-height: 0</code>.</li><li>Added inner scroll padding to avoid the final item visually touching the container boundary.</li></ul><h2 id="risk-assessment" tabindex="-1">Risk assessment <a class="header-anchor" href="#risk-assessment" aria-label="Permalink to &quot;Risk assessment&quot;">​</a></h2><p>This change is localized to the simulator Events UI and its local state store. It does not change SDK callback wiring or event payload recording.</p><h2 id="regression-checklist" tabindex="-1">Regression checklist <a class="header-anchor" href="#regression-checklist" aria-label="Permalink to &quot;Regression checklist&quot;">​</a></h2><ul><li>Confirm the Events drawer still opens and closes from the preview panel.</li><li>Confirm <code>Clear</code> removes all recorded entries.</li><li>Confirm event recording still works for <code>onClickRoom</code> and <code>onClickRoomProperties</code>.</li><li>Confirm long event lists scroll entirely within the drawer.</li></ul>',14)])])}const p=a(l,[["render",s]]);export{m as __pageData,p as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as t,o,aq as r}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Events drawer toolbar and scroll bugfix","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.md","filePath":"records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.md","lastUpdated":1773145284000}'),l={name:"records/bugs/2026-03-10-events-drawer-toolbar-scroll-bugfix.md"};function s(i,e,n,d,c,h){return o(),t("div",null,[...e[0]||(e[0]=[r("",14)])])}const p=a(l,[["render",s]]);export{m as __pageData,p as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as i,o as t,aq as r}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator initial render and layout bugfix (March 10, 2026)","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.md","filePath":"records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.md","lastUpdated":1773123455000}'),o={name:"records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.md"};function l(s,e,n,d,c,u){return t(),i("div",null,[...e[0]||(e[0]=[r('<h1 id="simulator-initial-render-and-layout-bugfix-march-10-2026" tabindex="-1">Simulator initial render and layout bugfix (March 10, 2026) <a class="header-anchor" href="#simulator-initial-render-and-layout-bugfix-march-10-2026" aria-label="Permalink to &quot;Simulator initial render and layout bugfix (March 10, 2026)&quot;">​</a></h1><h2 id="symptom" tabindex="-1">Symptom <a class="header-anchor" href="#symptom" aria-label="Permalink to &quot;Symptom&quot;">​</a></h2><p>The simulator page showed an empty canvas after load even though default <code>mapHex</code> data existed. The map preview area also looked too small for practical inspection of large maps.</p><h2 id="reproducible-steps" tabindex="-1">Reproducible steps <a class="header-anchor" href="#reproducible-steps" aria-label="Permalink to &quot;Reproducible steps&quot;">​</a></h2><ol><li>Open <code>/simulator/</code> in docs.</li><li>Observe status text before any action.</li><li>Observe preview panel size on desktop.</li></ol><h2 id="root-cause" tabindex="-1">Root cause <a class="header-anchor" href="#root-cause" aria-label="Permalink to &quot;Root cause&quot;">​</a></h2><ul><li>The component only prefilled <code>mapHex</code> state and initialized canvas, but did not trigger first render.</li><li>The page inherited default docs content width and the previous grid split, which constrained the preview area.</li></ul><h2 id="patch-summary" tabindex="-1">Patch summary <a class="header-anchor" href="#patch-summary" aria-label="Permalink to &quot;Patch summary&quot;">​</a></h2><ul><li>Trigger initial <code>renderMap()</code> on mount.</li><li>Switch layout to preview-first with a larger desktop map area.</li><li>Expand simulator page content width and disable page aside via frontmatter.</li><li>Increase preview container minimum height.</li></ul><h2 id="risk-assessment" tabindex="-1">Risk assessment <a class="header-anchor" href="#risk-assessment" aria-label="Permalink to &quot;Risk assessment&quot;">​</a></h2><ul><li>Low risk. Changes are isolated to simulator docs UI.</li><li>No runtime SDK behavior changes.</li></ul><h2 id="regression-checklist" tabindex="-1">Regression checklist <a class="header-anchor" href="#regression-checklist" aria-label="Permalink to &quot;Regression checklist&quot;">​</a></h2><ul><li>[ ] <code>/simulator/</code> renders default <code>mapHex</code> without manual click.</li><li>[ ] Preview area is significantly larger on desktop.</li><li>[ ] Mobile layout remains stacked and usable.</li><li>[ ] <code>mapHex</code> required behavior remains unchanged.</li><li>[ ] Optional <code>pathHex</code> and <code>roomProperties</code> remain non-blocking.</li></ul>',13)])])}const p=a(o,[["render",l]]);export{m as __pageData,p as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as i,o as t,aq as r}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator initial render and layout bugfix (March 10, 2026)","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.md","filePath":"records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.md","lastUpdated":1773123455000}'),o={name:"records/bugs/2026-03-10-simulator-initial-render-layout-bugfix.md"};function l(s,e,n,d,c,u){return t(),i("div",null,[...e[0]||(e[0]=[r("",13)])])}const p=a(o,[["render",l]]);export{m as __pageData,p as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as l,o,aq as r}from"./chunks/framework.CBLqO2Q1.js";const d=JSON.parse('{"title":"Simulator wheel scroll leak bugfix (March 10, 2026)","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.md","filePath":"records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.md","lastUpdated":1773123455000}'),s={name:"records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.md"};function t(i,e,c,h,n,u){return o(),l("div",null,[...e[0]||(e[0]=[r('<h1 id="simulator-wheel-scroll-leak-bugfix-march-10-2026" tabindex="-1">Simulator wheel scroll leak bugfix (March 10, 2026) <a class="header-anchor" href="#simulator-wheel-scroll-leak-bugfix-march-10-2026" aria-label="Permalink to &quot;Simulator wheel scroll leak bugfix (March 10, 2026)&quot;">​</a></h1><h2 id="symptom" tabindex="-1">Symptom <a class="header-anchor" href="#symptom" aria-label="Permalink to &quot;Symptom&quot;">​</a></h2><p>When users use the mouse wheel over the map preview area to zoom the map, the whole docs page scrolls at the same time.</p><h2 id="reproducible-steps" tabindex="-1">Reproducible steps <a class="header-anchor" href="#reproducible-steps" aria-label="Permalink to &quot;Reproducible steps&quot;">​</a></h2><ol><li>Open <code>/simulator/</code>.</li><li>Move cursor over the map canvas area.</li><li>Scroll mouse wheel.</li><li>Observe map zoom and page scroll happening together.</li></ol><h2 id="root-cause" tabindex="-1">Root cause <a class="header-anchor" href="#root-cause" aria-label="Permalink to &quot;Root cause&quot;">​</a></h2><p>Wheel events in the map container did not prevent browser default page scroll. The map interaction consumed wheel input for zoom, but the document scroll behavior was still active.</p><h2 id="patch-summary" tabindex="-1">Patch summary <a class="header-anchor" href="#patch-summary" aria-label="Permalink to &quot;Patch summary&quot;">​</a></h2><ul><li>Added wheel handler on map container to call <code>preventDefault()</code>.</li><li>Added <code>overscroll-behavior: contain</code> to the map container.</li><li>Moved parsed map result panel to the right-side data panel to improve visual hierarchy.</li></ul><h2 id="risk-assessment" tabindex="-1">Risk assessment <a class="header-anchor" href="#risk-assessment" aria-label="Permalink to &quot;Risk assessment&quot;">​</a></h2><ul><li>Low risk and isolated to simulator docs page UI.</li><li>Does not change SDK runtime logic.</li></ul><h2 id="regression-checklist" tabindex="-1">Regression checklist <a class="header-anchor" href="#regression-checklist" aria-label="Permalink to &quot;Regression checklist&quot;">​</a></h2><ul><li>[ ] Wheel zoom over map no longer scrolls the whole page.</li><li>[ ] Page can still scroll normally when cursor is outside map area.</li><li>[ ] Parsed map summary and tree are still available after rendering.</li></ul>',13)])])}const p=a(s,[["render",t]]);export{d as __pageData,p as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as l,o,aq as r}from"./chunks/framework.CBLqO2Q1.js";const d=JSON.parse('{"title":"Simulator wheel scroll leak bugfix (March 10, 2026)","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.md","filePath":"records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.md","lastUpdated":1773123455000}'),s={name:"records/bugs/2026-03-10-simulator-wheel-scroll-leak-bugfix.md"};function t(i,e,c,h,n,u){return o(),l("div",null,[...e[0]||(e[0]=[r("",13)])])}const p=a(s,[["render",t]]);export{d as __pageData,p as default};
@@ -0,0 +1 @@
1
+ import{_ as o,c as s,o as i,aq as c}from"./chunks/framework.CBLqO2Q1.js";const b=JSON.parse('{"title":"2026-03-11 docs server bin deletion bugfix","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-11-docs-server-bin-clean-bugfix.md","filePath":"records/bugs/2026-03-11-docs-server-bin-clean-bugfix.md","lastUpdated":1773214888000}'),a={name:"records/bugs/2026-03-11-docs-server-bin-clean-bugfix.md"};function r(d,e,t,l,n,u){return i(),s("div",null,[...e[0]||(e[0]=[c('<h1 id="_2026-03-11-docs-server-bin-deletion-bugfix" tabindex="-1">2026-03-11 docs server bin deletion bugfix <a class="header-anchor" href="#_2026-03-11-docs-server-bin-deletion-bugfix" aria-label="Permalink to &quot;2026-03-11 docs server bin deletion bugfix&quot;">​</a></h1><h2 id="symptom" tabindex="-1">Symptom <a class="header-anchor" href="#symptom" aria-label="Permalink to &quot;Symptom&quot;">​</a></h2><p>After publishing version <code>0.0.10</code>, running <code>npx -y -p @ray-js/robot-map-sdk@latest robot-map-docs</code> failed with <code>command not found</code>.</p><h2 id="reproducible-steps" tabindex="-1">Reproducible steps <a class="header-anchor" href="#reproducible-steps" aria-label="Permalink to &quot;Reproducible steps&quot;">​</a></h2><ol><li>Run <code>npm run mcp:build</code>.</li><li>Observe that <code>bin/docs-server.js</code> is removed.</li><li>Publish package with <code>package.json</code> still declaring <code>&quot;robot-map-docs&quot;: &quot;./bin/docs-server.js&quot;</code>.</li><li>Execute <code>npx ... robot-map-docs</code> from a clean environment.</li></ol><h2 id="root-cause" tabindex="-1">Root cause <a class="header-anchor" href="#root-cause" aria-label="Permalink to &quot;Root cause&quot;">​</a></h2><p><code>tsup.mcp.config.ts</code> used:</p><ul><li><code>outDir: &#39;bin&#39;</code></li><li><code>clean: true</code></li></ul><p><code>mcp:build</code> therefore cleaned the entire <code>bin/</code> folder and rebuilt only <code>mcp-server</code>, deleting <code>docs-server.js</code>.</p><h2 id="patch-summary" tabindex="-1">Patch summary <a class="header-anchor" href="#patch-summary" aria-label="Permalink to &quot;Patch summary&quot;">​</a></h2><ul><li>Restored <code>bin/docs-server.js</code>.</li><li>Changed MCP tsup config to <code>clean: false</code> so <code>mcp:build</code> no longer wipes other <code>bin</code> scripts.</li><li>Hardened publish guard in <code>prepublishOnly</code>: fail fast if <code>bin/docs-server.js</code> is missing before publish.</li></ul><h2 id="risk-assessment" tabindex="-1">Risk assessment <a class="header-anchor" href="#risk-assessment" aria-label="Permalink to &quot;Risk assessment&quot;">​</a></h2><ul><li>Low runtime risk.</li><li>Main tradeoff: with <code>clean: false</code>, stale MCP artifacts could remain in <code>bin/</code> if filenames change in the future.</li></ul><h2 id="regression-checklist" tabindex="-1">Regression checklist <a class="header-anchor" href="#regression-checklist" aria-label="Permalink to &quot;Regression checklist&quot;">​</a></h2><ul><li>[x] <code>bin/docs-server.js</code> exists after <code>npm run mcp:build</code>.</li><li>[x] <code>npm run lint</code> passes.</li><li>[x] <code>npx tsc --noEmit</code> passes.</li><li>[x] <code>npm pack --dry-run --json</code> includes <code>bin/docs-server.js</code>.</li></ul>',15)])])}const h=o(a,[["render",r]]);export{b as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as o,c as s,o as i,aq as c}from"./chunks/framework.CBLqO2Q1.js";const b=JSON.parse('{"title":"2026-03-11 docs server bin deletion bugfix","description":"","frontmatter":{},"headers":[],"relativePath":"records/bugs/2026-03-11-docs-server-bin-clean-bugfix.md","filePath":"records/bugs/2026-03-11-docs-server-bin-clean-bugfix.md","lastUpdated":1773214888000}'),a={name:"records/bugs/2026-03-11-docs-server-bin-clean-bugfix.md"};function r(d,e,t,l,n,u){return i(),s("div",null,[...e[0]||(e[0]=[c("",15)])])}const h=o(a,[["render",r]]);export{b as __pageData,h as default};
@@ -1 +1 @@
1
- import{_ as t,c as o,o as d,ag as r}from"./chunks/framework.DRADY2L-.js";const h=JSON.parse('{"title":"Furniture Feature Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-02-furniture-feature-plan.md","filePath":"records/plans/2026-03-02-furniture-feature-plan.md","lastUpdated":1772616139000}'),a={name:"records/plans/2026-03-02-furniture-feature-plan.md"};function i(n,e,c,s,l,u){return d(),o("div",null,[...e[0]||(e[0]=[r('<h1 id="furniture-feature-implementation-plan" tabindex="-1">Furniture Feature Implementation Plan <a class="header-anchor" href="#furniture-feature-implementation-plan" aria-label="Permalink to &quot;Furniture Feature Implementation Plan&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>Robot vacuum map applications commonly support furniture placement to help users visualize and manage their home layout. This feature allows placing furniture images on the map with full editing capabilities (move, scale, rotate).</p><h2 id="goal-and-scope" tabindex="-1">Goal and Scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal and Scope&quot;">​</a></h2><p>Implement a furniture placement and editing feature for the robot vacuum map SDK:</p><ul><li>Render furniture as image sprites on the map using a points-based coordinate system (4 corner vertices)</li><li>Support click-to-rotate (90-degree increments), drag-to-move, and handle-to-scale interactions</li><li>Follow the <code>ControlsManager</code> + <code>Zone</code> architecture pattern for manager structure and CRUD logic</li><li>Expose public API methods (<code>drawFurnitures</code>, <code>getFurniturePointsByViewportCenter</code>) and callbacks (<code>onRemoveFurniture</code>, <code>onUpdateFurniture</code>, <code>onClickFurniture</code>)</li></ul><h2 id="chosen-approach" tabindex="-1">Chosen Approach <a class="header-anchor" href="#chosen-approach" aria-label="Permalink to &quot;Chosen Approach&quot;">​</a></h2><ul><li><strong>Parameter Design</strong>: <code>FurnitureParam</code> uses the same 4-point model as <code>ZoneParam</code>, with an additional <code>furnitureType</code> field for asset matching</li><li><strong>Architecture</strong>: <code>FurnitureManager</code> manages CRUD via diff-based updates; <code>Furniture</code> component combines <code>Sprite</code> + <code>EditControlLayer</code> + <code>TapRotateButton</code></li><li><strong>Config</strong>: <code>FurnitureConfig</code> added as a top-level <code>AppConfig</code> property with asset definitions, opacity, and outline styling</li><li><strong>Rotation</strong>: New <code>TapRotateButton</code> component (extending <code>BaseControlButton</code>) provides click-to-rotate-90-degree behavior, replacing the standard drag-rotate control</li><li><strong>Layer</strong>: <code>LAYER_FURNITURE</code> inserted between <code>LAYER_PATH</code> and <code>LAYER_CONTROLS</code> in the rendering order</li></ul><h2 id="impacted-files-modules" tabindex="-1">Impacted Files/Modules <a class="header-anchor" href="#impacted-files-modules" aria-label="Permalink to &quot;Impacted Files/Modules&quot;">​</a></h2><h3 id="new-files" tabindex="-1">New Files <a class="header-anchor" href="#new-files" aria-label="Permalink to &quot;New Files&quot;">​</a></h3><table tabindex="0"><thead><tr><th>File</th><th>Purpose</th></tr></thead><tbody><tr><td><code>src/core/managers/FurnitureManager.ts</code></td><td>Texture loading, CRUD via <code>drawFurnitures</code>, edit-state subscription</td></tr><tr><td><code>src/core/components/Furniture/Furniture.ts</code></td><td>Sprite display + <code>EditControlLayer</code> + <code>TapRotateButton</code></td></tr><tr><td><code>src/core/components/Base/TapRotateButton.ts</code></td><td>Click-to-rotate-90-degrees button</td></tr></tbody></table><h3 id="modified-files" tabindex="-1">Modified Files <a class="header-anchor" href="#modified-files" aria-label="Permalink to &quot;Modified Files&quot;">​</a></h3><table tabindex="0"><thead><tr><th>File</th><th>Changes</th></tr></thead><tbody><tr><td><code>src/core/@types/index.d.ts</code></td><td>Added <code>FurnitureParam</code>, <code>FurnitureAsset</code>, <code>FurnitureConfig</code> types; <code>furniture</code> to <code>AppConfig</code>; <code>editingFurnitureIds</code> to <code>RuntimeConfig</code></td></tr><tr><td><code>src/core/@types/callbacks.ts</code></td><td>Added <code>onRemoveFurniture</code>, <code>onUpdateFurniture</code>, <code>onClickFurniture</code></td></tr><tr><td><code>src/core/@types/methods.ts</code></td><td>Added <code>drawFurnitures</code>, <code>getFurniturePointsByViewportCenter</code>; <code>furnitures</code> to <code>snapshotByData</code> data param</td></tr><tr><td><code>src/core/constant/methods.ts</code></td><td>Added method/callback names for RJS bundle exposure</td></tr><tr><td><code>src/core/constant/config.ts</code></td><td>Added furniture defaults to <code>DEFAULT_CONFIG</code> and <code>DEFAULT_RUNTIME_CONFIG</code></td></tr><tr><td><code>src/core/application/AppContainer.ts</code></td><td>Added <code>LAYER_FURNITURE</code> constant and layer ordering</td></tr><tr><td><code>src/core/application/MapApplication.ts</code></td><td>Registered <code>FurnitureManager</code>, exposed public API, wired asset preloading/snapshot/origin</td></tr><tr><td><code>src/core/application/AppService.ts</code></td><td>Added <code>furnitureManager</code> and <code>furnitureConfig</code> accessors</td></tr><tr><td><code>src/core/index.docs.ts</code></td><td>Exported <code>FurnitureParam</code> type</td></tr><tr><td><code>src/app/debugTools/index.ts</code></td><td>Added &quot;Test Furniture&quot; button for development verification</td></tr></tbody></table><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><ul><li>[x] <code>FurnitureParam</code>, <code>FurnitureAsset</code>, <code>FurnitureConfig</code> types defined</li><li>[x] Callbacks (<code>onRemoveFurniture</code>, <code>onUpdateFurniture</code>, <code>onClickFurniture</code>) registered</li><li>[x] Public API methods (<code>drawFurnitures</code>, <code>getFurniturePointsByViewportCenter</code>) exposed</li><li>[x] Default config values provided with <code>doubleBed.png</code> asset</li><li>[x] <code>LAYER_FURNITURE</code> added between <code>LAYER_PATH</code> and <code>LAYER_CONTROLS</code></li><li>[x] <code>TapRotateButton</code> component created</li><li>[x] <code>Furniture</code> component renders sprite from points with editing controls</li><li>[x] <code>FurnitureManager</code> handles CRUD, edit-state, and layer positioning</li><li>[x] Integration in <code>MapApplication</code> (managers, assets, snapshot, origin, destroy)</li><li>[x] Demo app test button functional</li><li>[x] <code>npm run lint</code> passes</li><li>[x] <code>npx tsc --noEmit</code> passes</li></ul>',15)])])}const m=t(a,[["render",i]]);export{h as __pageData,m as default};
1
+ import{_ as t,c as o,o as d,aq as r}from"./chunks/framework.CBLqO2Q1.js";const h=JSON.parse('{"title":"Furniture Feature Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-02-furniture-feature-plan.md","filePath":"records/plans/2026-03-02-furniture-feature-plan.md","lastUpdated":1772616139000}'),a={name:"records/plans/2026-03-02-furniture-feature-plan.md"};function i(n,e,c,s,l,u){return d(),o("div",null,[...e[0]||(e[0]=[r('<h1 id="furniture-feature-implementation-plan" tabindex="-1">Furniture Feature Implementation Plan <a class="header-anchor" href="#furniture-feature-implementation-plan" aria-label="Permalink to &quot;Furniture Feature Implementation Plan&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>Robot vacuum map applications commonly support furniture placement to help users visualize and manage their home layout. This feature allows placing furniture images on the map with full editing capabilities (move, scale, rotate).</p><h2 id="goal-and-scope" tabindex="-1">Goal and Scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal and Scope&quot;">​</a></h2><p>Implement a furniture placement and editing feature for the robot vacuum map SDK:</p><ul><li>Render furniture as image sprites on the map using a points-based coordinate system (4 corner vertices)</li><li>Support click-to-rotate (90-degree increments), drag-to-move, and handle-to-scale interactions</li><li>Follow the <code>ControlsManager</code> + <code>Zone</code> architecture pattern for manager structure and CRUD logic</li><li>Expose public API methods (<code>drawFurnitures</code>, <code>getFurniturePointsByViewportCenter</code>) and callbacks (<code>onRemoveFurniture</code>, <code>onUpdateFurniture</code>, <code>onClickFurniture</code>)</li></ul><h2 id="chosen-approach" tabindex="-1">Chosen Approach <a class="header-anchor" href="#chosen-approach" aria-label="Permalink to &quot;Chosen Approach&quot;">​</a></h2><ul><li><strong>Parameter Design</strong>: <code>FurnitureParam</code> uses the same 4-point model as <code>ZoneParam</code>, with an additional <code>furnitureType</code> field for asset matching</li><li><strong>Architecture</strong>: <code>FurnitureManager</code> manages CRUD via diff-based updates; <code>Furniture</code> component combines <code>Sprite</code> + <code>EditControlLayer</code> + <code>TapRotateButton</code></li><li><strong>Config</strong>: <code>FurnitureConfig</code> added as a top-level <code>AppConfig</code> property with asset definitions, opacity, and outline styling</li><li><strong>Rotation</strong>: New <code>TapRotateButton</code> component (extending <code>BaseControlButton</code>) provides click-to-rotate-90-degree behavior, replacing the standard drag-rotate control</li><li><strong>Layer</strong>: <code>LAYER_FURNITURE</code> inserted between <code>LAYER_PATH</code> and <code>LAYER_CONTROLS</code> in the rendering order</li></ul><h2 id="impacted-files-modules" tabindex="-1">Impacted Files/Modules <a class="header-anchor" href="#impacted-files-modules" aria-label="Permalink to &quot;Impacted Files/Modules&quot;">​</a></h2><h3 id="new-files" tabindex="-1">New Files <a class="header-anchor" href="#new-files" aria-label="Permalink to &quot;New Files&quot;">​</a></h3><table tabindex="0"><thead><tr><th>File</th><th>Purpose</th></tr></thead><tbody><tr><td><code>src/core/managers/FurnitureManager.ts</code></td><td>Texture loading, CRUD via <code>drawFurnitures</code>, edit-state subscription</td></tr><tr><td><code>src/core/components/Furniture/Furniture.ts</code></td><td>Sprite display + <code>EditControlLayer</code> + <code>TapRotateButton</code></td></tr><tr><td><code>src/core/components/Base/TapRotateButton.ts</code></td><td>Click-to-rotate-90-degrees button</td></tr></tbody></table><h3 id="modified-files" tabindex="-1">Modified Files <a class="header-anchor" href="#modified-files" aria-label="Permalink to &quot;Modified Files&quot;">​</a></h3><table tabindex="0"><thead><tr><th>File</th><th>Changes</th></tr></thead><tbody><tr><td><code>src/core/@types/index.d.ts</code></td><td>Added <code>FurnitureParam</code>, <code>FurnitureAsset</code>, <code>FurnitureConfig</code> types; <code>furniture</code> to <code>AppConfig</code>; <code>editingFurnitureIds</code> to <code>RuntimeConfig</code></td></tr><tr><td><code>src/core/@types/callbacks.ts</code></td><td>Added <code>onRemoveFurniture</code>, <code>onUpdateFurniture</code>, <code>onClickFurniture</code></td></tr><tr><td><code>src/core/@types/methods.ts</code></td><td>Added <code>drawFurnitures</code>, <code>getFurniturePointsByViewportCenter</code>; <code>furnitures</code> to <code>snapshotByData</code> data param</td></tr><tr><td><code>src/core/constant/methods.ts</code></td><td>Added method/callback names for RJS bundle exposure</td></tr><tr><td><code>src/core/constant/config.ts</code></td><td>Added furniture defaults to <code>DEFAULT_CONFIG</code> and <code>DEFAULT_RUNTIME_CONFIG</code></td></tr><tr><td><code>src/core/application/AppContainer.ts</code></td><td>Added <code>LAYER_FURNITURE</code> constant and layer ordering</td></tr><tr><td><code>src/core/application/MapApplication.ts</code></td><td>Registered <code>FurnitureManager</code>, exposed public API, wired asset preloading/snapshot/origin</td></tr><tr><td><code>src/core/application/AppService.ts</code></td><td>Added <code>furnitureManager</code> and <code>furnitureConfig</code> accessors</td></tr><tr><td><code>src/core/index.docs.ts</code></td><td>Exported <code>FurnitureParam</code> type</td></tr><tr><td><code>src/app/debugTools/index.ts</code></td><td>Added &quot;Test Furniture&quot; button for development verification</td></tr></tbody></table><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><ul><li>[x] <code>FurnitureParam</code>, <code>FurnitureAsset</code>, <code>FurnitureConfig</code> types defined</li><li>[x] Callbacks (<code>onRemoveFurniture</code>, <code>onUpdateFurniture</code>, <code>onClickFurniture</code>) registered</li><li>[x] Public API methods (<code>drawFurnitures</code>, <code>getFurniturePointsByViewportCenter</code>) exposed</li><li>[x] Default config values provided with <code>doubleBed.png</code> asset</li><li>[x] <code>LAYER_FURNITURE</code> added between <code>LAYER_PATH</code> and <code>LAYER_CONTROLS</code></li><li>[x] <code>TapRotateButton</code> component created</li><li>[x] <code>Furniture</code> component renders sprite from points with editing controls</li><li>[x] <code>FurnitureManager</code> handles CRUD, edit-state, and layer positioning</li><li>[x] Integration in <code>MapApplication</code> (managers, assets, snapshot, origin, destroy)</li><li>[x] Demo app test button functional</li><li>[x] <code>npm run lint</code> passes</li><li>[x] <code>npx tsc --noEmit</code> passes</li></ul>',15)])])}const m=t(a,[["render",i]]);export{h as __pageData,m as default};
@@ -1 +1 @@
1
- import{_ as t,c as o,o as d,ag as r}from"./chunks/framework.DRADY2L-.js";const h=JSON.parse('{"title":"Furniture Feature Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-02-furniture-feature-plan.md","filePath":"records/plans/2026-03-02-furniture-feature-plan.md","lastUpdated":1772616139000}'),a={name:"records/plans/2026-03-02-furniture-feature-plan.md"};function i(n,e,c,s,l,u){return d(),o("div",null,[...e[0]||(e[0]=[r("",15)])])}const m=t(a,[["render",i]]);export{h as __pageData,m as default};
1
+ import{_ as t,c as o,o as d,aq as r}from"./chunks/framework.CBLqO2Q1.js";const h=JSON.parse('{"title":"Furniture Feature Implementation Plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-02-furniture-feature-plan.md","filePath":"records/plans/2026-03-02-furniture-feature-plan.md","lastUpdated":1772616139000}'),a={name:"records/plans/2026-03-02-furniture-feature-plan.md"};function i(n,e,c,s,l,u){return d(),o("div",null,[...e[0]||(e[0]=[r("",15)])])}const m=t(a,[["render",i]]);export{h as __pageData,m as default};
@@ -0,0 +1 @@
1
+ import{_ as o,c as a,o as i,aq as l}from"./chunks/framework.CBLqO2Q1.js";const u=JSON.parse('{"title":"Simulator events console plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-10-simulator-events-console-plan.md","filePath":"records/plans/2026-03-10-simulator-events-console-plan.md","lastUpdated":1773138773000}'),t={name:"records/plans/2026-03-10-simulator-events-console-plan.md"};function s(n,e,c,r,d,p){return i(),a("div",null,[...e[0]||(e[0]=[l('<h1 id="simulator-events-console-plan" tabindex="-1">Simulator events console plan <a class="header-anchor" href="#simulator-events-console-plan" aria-label="Permalink to &quot;Simulator events console plan&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>The simulator page already helps developers validate source data input and runtime configuration, but it does not expose SDK callback activity. Developers can interact with the map yet still need custom code to inspect which callbacks fire and what payloads they receive.</p><h2 id="goal-and-scope" tabindex="-1">Goal and scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal and scope&quot;">​</a></h2><p>This iteration adds a developer-facing <code>Events</code> console to the simulator.</p><p>In scope:</p><ul><li>record SDK public callbacks only</li><li>start with <code>onClickRoom</code> and <code>onClickRoomProperties</code></li><li>show callback names, times, summaries, and expandable JSON payloads</li><li>add pause, clear, copy, and filter actions</li><li>place the console near the map preview</li><li>introduce <code>reka-ui</code> as a lightweight primitive layer for new overlays and collapsible UI</li></ul><p>Out of scope:</p><ul><li>logging simulator-internal actions</li><li>toast notifications for each callback</li><li>a generic SDK logging framework</li><li>a full migration of simulator controls to <code>reka-ui</code></li></ul><h2 id="chosen-approach" tabindex="-1">Chosen approach <a class="header-anchor" href="#chosen-approach" aria-label="Permalink to &quot;Chosen approach&quot;">​</a></h2><p>Use a dedicated <code>Events</code> console placed with the map preview. Record events by wrapping the SDK <code>MapCallbacks</code> passed into the map instance. Persist only a bounded in-memory event list, with lightweight helpers for summaries, filtering, and JSON export.</p><p>Introduce <code>reka-ui</code> only for the new interaction primitives that need stronger accessibility and structure, such as collapsible payload details and event filter controls.</p><h2 id="impacted-files-or-modules" tabindex="-1">Impacted files or modules <a class="header-anchor" href="#impacted-files-or-modules" aria-label="Permalink to &quot;Impacted files or modules&quot;">​</a></h2><p>Expected implementation targets:</p><ul><li><code>docs/.vitepress/theme/components/MapPlayground.vue</code></li><li><code>docs/.vitepress/theme/components/simulator/useMapPlayground.ts</code></li><li><code>docs/.vitepress/theme/components/simulator/useMapCanvas.ts</code></li><li><code>docs/.vitepress/theme/components/simulator/usePlaygroundRender.ts</code></li><li><code>docs/.vitepress/theme/components/simulator/types.ts</code></li><li><code>docs/.vitepress/theme/components/simulator/sdkTypes.ts</code></li><li>new event composables under <code>docs/.vitepress/theme/components/simulator/</code></li><li>new event UI components under <code>docs/.vitepress/theme/components/simulator/</code></li><li><code>package.json</code> and lockfile for the new UI primitive dependency</li></ul><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><ul><li>[ ] Clicking a room appends an <code>onClickRoom</code> record.</li><li>[ ] Clicking a room property appends an <code>onClickRoomProperties</code> record.</li><li>[ ] Event rows show exact callback names and readable summaries.</li><li>[ ] Pause stops new records without clearing the list.</li><li>[ ] Clear resets only the event log.</li><li>[ ] Copy exports valid JSON.</li><li>[ ] The event list is bounded to the latest <code>100</code> entries.</li><li>[ ] <code>npm run lint</code> passes.</li><li>[ ] <code>npx tsc --noEmit</code> passes.</li><li>[ ] <code>npm run docs:build</code> passes.</li></ul>',17)])])}const h=o(t,[["render",s]]);export{u as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as o,c as a,o as i,aq as l}from"./chunks/framework.CBLqO2Q1.js";const u=JSON.parse('{"title":"Simulator events console plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-10-simulator-events-console-plan.md","filePath":"records/plans/2026-03-10-simulator-events-console-plan.md","lastUpdated":1773138773000}'),t={name:"records/plans/2026-03-10-simulator-events-console-plan.md"};function s(n,e,c,r,d,p){return i(),a("div",null,[...e[0]||(e[0]=[l("",17)])])}const h=o(t,[["render",s]]);export{u as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as o,o as l,aq as s}from"./chunks/framework.CBLqO2Q1.js";const h=JSON.parse('{"title":"Simulator Last Successful Combo Cache Plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.md","filePath":"records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.md","lastUpdated":1773123455000}'),c={name:"records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.md"};function i(t,e,r,n,d,u){return l(),o("div",null,[...e[0]||(e[0]=[s('<h1 id="simulator-last-successful-combo-cache-plan" tabindex="-1">Simulator Last Successful Combo Cache Plan <a class="header-anchor" href="#simulator-last-successful-combo-cache-plan" aria-label="Permalink to &quot;Simulator Last Successful Combo Cache Plan&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>The simulator page allows developers to paste <code>mapHex</code>, optional <code>pathHex</code>, and optional <code>roomProperties</code> for real-time rendering. Refreshing the page currently risks losing in-progress data.</p><h2 id="goal-and-scope" tabindex="-1">Goal And Scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal And Scope&quot;">​</a></h2><p>Persist the last successfully rendered combination locally so developers can refresh and continue without data loss.</p><p>In scope:</p><ul><li>Save input combo after successful render.</li><li>Restore input combo on page load.</li><li>Fallback to built-in demo defaults when no cache hit exists.</li><li>Provide an explicit cache clear action.</li></ul><p>Out of scope:</p><ul><li>Cross-device sync.</li><li>Server-side persistence.</li><li>IndexedDB migration.</li></ul><h2 id="chosen-approach" tabindex="-1">Chosen Approach <a class="header-anchor" href="#chosen-approach" aria-label="Permalink to &quot;Chosen Approach&quot;">​</a></h2><ul><li>Use browser <code>localStorage</code> with key <code>rayRobotMap:simulator:lastSuccessfulCombo:v1</code>.</li><li>Store payload with version and timestamp: <ul><li><code>mapHex</code></li><li><code>pathHex</code></li><li><code>roomProperties</code></li></ul></li><li>Read and validate cache shape at startup.</li><li>Only persist when full render completes without layer errors.</li><li>Keep render behavior unchanged for optional inputs.</li><li>Add <code>清除缓存</code> action to remove stored combo manually.</li></ul><h2 id="impacted-files-or-modules" tabindex="-1">Impacted Files Or Modules <a class="header-anchor" href="#impacted-files-or-modules" aria-label="Permalink to &quot;Impacted Files Or Modules&quot;">​</a></h2><ul><li><code>docs/.vitepress/theme/components/MapPlayground.vue</code></li></ul><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><ul><li><code>npm run lint</code> passes (project lint scope currently covers <code>src</code> only).</li><li><code>npm run docs:build</code> passes.</li><li><code>npx tsc --noEmit</code> still fails due existing unrelated test typing issues in <code>test/core/application/Interaction.test.ts</code>.</li></ul>',15)])])}const m=a(c,[["render",i]]);export{h as __pageData,m as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as o,o as l,aq as s}from"./chunks/framework.CBLqO2Q1.js";const h=JSON.parse('{"title":"Simulator Last Successful Combo Cache Plan","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.md","filePath":"records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.md","lastUpdated":1773123455000}'),c={name:"records/plans/2026-03-10-simulator-last-successful-combo-cache-plan.md"};function i(t,e,r,n,d,u){return l(),o("div",null,[...e[0]||(e[0]=[s("",15)])])}const m=a(c,[["render",i]]);export{h as __pageData,m as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as r,o as i,aq as o}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator map parsed view plan (March 10, 2026)","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-10-simulator-map-parsed-view-plan.md","filePath":"records/plans/2026-03-10-simulator-map-parsed-view-plan.md","lastUpdated":1773123455000}'),l={name:"records/plans/2026-03-10-simulator-map-parsed-view-plan.md"};function t(d,e,s,n,c,p){return i(),r("div",null,[...e[0]||(e[0]=[o('<h1 id="simulator-map-parsed-view-plan-march-10-2026" tabindex="-1">Simulator map parsed view plan (March 10, 2026) <a class="header-anchor" href="#simulator-map-parsed-view-plan-march-10-2026" aria-label="Permalink to &quot;Simulator map parsed view plan (March 10, 2026)&quot;">​</a></h1><h2 id="background" tabindex="-1">Background <a class="header-anchor" href="#background" aria-label="Permalink to &quot;Background&quot;">​</a></h2><p>The simulator currently visualizes only the rendered map. Developers also need an inspectable parsed-data view to compare raw <code>mapHex</code> input with decoded map structure during debugging.</p><h2 id="goal-and-scope" tabindex="-1">Goal and scope <a class="header-anchor" href="#goal-and-scope" aria-label="Permalink to &quot;Goal and scope&quot;">​</a></h2><p>Add a parsed map data panel in the simulator that:</p><ul><li>Shows map parse summary fields for quick verification.</li><li>Supports on-demand tree inspection for large decoded objects.</li><li>Keeps the main map rendering workflow unchanged.</li></ul><p>Out of scope:</p><ul><li>Path parsed-view panel.</li><li>Diff view between raw hex and parsed JSON.</li></ul><h2 id="chosen-approach" tabindex="-1">Chosen approach <a class="header-anchor" href="#chosen-approach" aria-label="Permalink to &quot;Chosen approach&quot;">​</a></h2><p>Use <code>json-editor-vue</code> in read-only tree mode and render it lazily behind a &quot;展开详情&quot; toggle. Keep summary cards visible by default and load the full tree only when requested.</p><h2 id="impacted-files-and-modules" tabindex="-1">Impacted files and modules <a class="header-anchor" href="#impacted-files-and-modules" aria-label="Permalink to &quot;Impacted files and modules&quot;">​</a></h2><ul><li><code>package.json</code></li><li><code>yarn.lock</code></li><li><code>docs/.vitepress/theme/components/MapPlayground.vue</code></li></ul><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><ul><li>[ ] Structured map parse result appears in summary panel.</li><li>[ ] Tree viewer expands and collapses without blocking map interaction.</li><li>[ ] Copy JSON action works in secure browser context.</li><li>[ ] <code>npm run lint</code> passes.</li><li>[ ] <code>npm run docs:build</code> passes.</li><li>[ ] <code>npx tsc --noEmit</code> status is recorded.</li></ul>',14)])])}const h=a(l,[["render",t]]);export{m as __pageData,h as default};
@@ -0,0 +1 @@
1
+ import{_ as a,c as r,o as i,aq as o}from"./chunks/framework.CBLqO2Q1.js";const m=JSON.parse('{"title":"Simulator map parsed view plan (March 10, 2026)","description":"","frontmatter":{},"headers":[],"relativePath":"records/plans/2026-03-10-simulator-map-parsed-view-plan.md","filePath":"records/plans/2026-03-10-simulator-map-parsed-view-plan.md","lastUpdated":1773123455000}'),l={name:"records/plans/2026-03-10-simulator-map-parsed-view-plan.md"};function t(d,e,s,n,c,p){return i(),r("div",null,[...e[0]||(e[0]=[o("",14)])])}const h=a(l,[["render",t]]);export{m as __pageData,h as default};