docs(design): 补充控制面板设计稿

补充控制面板设计说明,并细化 RuntimeHost 状态与主界面线框图,便于后续实现对齐交互范围。
This commit is contained in:
2026-06-10 18:06:55 +08:00
parent 5cfa0fc591
commit 6ee80834ee
3 changed files with 467 additions and 156 deletions
+148
View File
@@ -0,0 +1,148 @@
# Control Panel Design Language
## Overall Structure
The control panel uses a clear engineering-dashboard layout. Screens are divided into large functional regions, not decorative sections. A detail screen should usually split into:
- a left information column
- a right controls column
- stacked status/log panels when more than one information region is needed
Panels should align their titles with their primary content. If a title describes a card grid, align the title with the grid's left edge. If a title describes a log window, align it with the log window's left edge.
Do not use decorative icons beside section titles. Titles should read as labels for the content region, not as illustrated headers.
## Color System
Use a restrained white-and-gray base with small semantic accents.
- Page background: `#F4F6F8`
- Main panel background: `#FFFFFF`
- Normal card background: `#FFFFFF`
- Main panel border: `#C9D1D9`
- Inner card border: `#D5DDE5`
- Primary text: `#17202A`
- Secondary text: `#52616F`
- Muted text: `#7B8794`
Semantic colors:
- Primary blue: `#2F80ED`
- Primary blue fill: `#F3F8FF`
- Soft blue control fill: `#E8F1FF`
- Success green: `#31A66A`
- Success green fill: `#D9F5E5`
- Warning yellow: `#D99000`
- Warning yellow fill: `#FFFBED`
- Scrollbar track: `#E5E9EE`
- Scrollbar thumb: `#A4AFBA`
Avoid large colored surfaces. Blue, green, and yellow are reserved for semantic accents: primary operations, connected/success states, warnings, and log categories.
## Radius
Except scrollbars, all rectangular UI surfaces use one radius:
- Standard radius: `10px`
This applies to main panels, status cards, operation cards, chips, log windows, and reserved areas.
Scrollbars are auxiliary controls and may keep smaller radii:
- Scrollbar track radius: `6px`
- Scrollbar thumb radius: `4.5px`
## Typography
Use straightforward system-safe typography.
- Primary UI font: `Arial, sans-serif`
- Log/monospace font: `Courier, monospace`
Text hierarchy:
- Main section title: `22px`, `700`, `#17202A`
- Section description: `14px`, `#52616F`
- Operation card title: `22px`, `700`, `#17202A`
- Operation card description: `14px`, `#52616F`
- Status card label: `14px`, `600`, `#52616F`
- Status card value: `38px`, `700`, `#17202A`
- Log line: `15px`, monospace
## RuntimeHost Detail Layout
The RuntimeHost detail view is a two-column detail page.
Left column:
- top panel: runtime status summary
- bottom panel: session log
Right column:
- full-height controls panel
### Runtime Status Panel
The status panel contains:
- a title and one-line description
- a bound-state chip aligned to the title row
- three horizontal status cards
Status cards use white backgrounds, gray borders, and the standard 10px radius. Each status card has three levels:
- small label
- large core value
- small semantic detail
Use semantic detail colors sparingly:
- connected/ready detail: `#31A66A`
- warning/detail requiring attention: `#D99000`
- informational detail: `#2F80ED`
### Session Log Panel
The log panel contains:
- a title and one-line description
- a compact `Start / Stop` control on the title row
- a large log window
- a slim scrollbar
The log window is white with a gray border. Log text is monospace.
Log color mapping:
- TX: `#2F80ED`
- RX: `#31A66A`
- SYS: `#7B8794`
### Controls Panel
The controls panel contains:
- a title and one-line description
- a regular operation-card grid
- a reserved area at the bottom for future actions
Operation cards should have consistent size, spacing, title alignment, and radius.
Operation card color mapping:
- primary operations: fill `#F3F8FF`, border `#2F80ED`
- normal query operations: fill `#FFFFFF`, border `#D5DDE5`
- attention operations: fill `#FFFBED`, border `#D99000`
- reserved/future area: fill `#FFFFFF`, border `#C9D1D9`, text `#52616F`
## Visual Rules
- Keep large surfaces white.
- Use gray borders to define structure.
- Use color only for semantics.
- Avoid gradients, decorative textures, and illustrated title icons.
- Avoid mixed corner radii in the same screen.
- Align section titles to the primary content edge.
- Keep controls in a predictable grid.
- Keep logs dense and scannable.
+168
View File
@@ -0,0 +1,168 @@
<svg width="1600" height="960" viewBox="0 0 1600 960" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="bg" x1="220" y1="96" x2="1364" y2="902" gradientUnits="userSpaceOnUse">
<stop stop-color="#F4F6F8"/>
<stop offset="1" stop-color="#F4F6F8"/>
</linearGradient>
<filter id="cardShadow" x="0" y="0" width="2000" height="1400" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feOffset dy="20"/>
<feGaussianBlur stdDeviation="20"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.133333 0 0 0 0 0.180392 0 0 0 0 0.258824 0 0 0 0.1 0"/>
<feBlend in2="SourceGraphic" result="shape"/>
</filter>
<linearGradient id="statusGlow" x1="136" y1="156" x2="696" y2="428" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFFFFF"/>
<stop offset="1" stop-color="#FFFFFF"/>
</linearGradient>
<linearGradient id="controlGlow" x1="844" y1="132" x2="1440" y2="836" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFFFFF"/>
<stop offset="1" stop-color="#FFFFFF"/>
</linearGradient>
</defs>
<rect width="1600" height="960" fill="url(#bg)"/>
<g filter="url(#cardShadow)">
<rect x="20" y="20" width="1560" height="920" rx="10" fill="#F4F6F8"/>
</g>
<g filter="url(#cardShadow)">
<rect x="36" y="36" width="724" height="302" rx="10" fill="url(#statusGlow)"/>
<rect x="36.75" y="36.75" width="722.5" height="300.5" rx="10" stroke="#C9D1D9" stroke-width="2"/>
<text x="72" y="120" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">RuntimeHost Status</text>
<text x="72" y="148" fill="#52616F" font-family="Arial, sans-serif" font-size="14" font-weight="500">Service lifecycle, bind state, runtime snapshot</text>
<rect x="584" y="94" width="142" height="40" rx="10" fill="#D9F5E5" stroke="#31A66A"/>
<circle cx="610" cy="114" r="6" fill="#31A66A"/>
<text x="625" y="118" fill="#27313B" font-family="Arial, sans-serif" font-size="14" font-weight="700">BOUND</text>
<rect x="72" y="184" width="216" height="118" rx="10" fill="#FFFFFF"/>
<rect x="72.75" y="184.75" width="214.5" height="116.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="98" y="217" fill="#52616F" font-family="Arial, sans-serif" font-size="14" font-weight="600">Connection</text>
<text x="98" y="263" fill="#17202A" font-family="Arial, sans-serif" font-size="38" font-weight="700">Active</text>
<text x="98" y="286" fill="#31A66A" font-family="Arial, sans-serif" font-size="14" font-weight="700">USB Ready</text>
<rect x="304" y="184" width="216" height="118" rx="10" fill="#FFFFFF"/>
<rect x="304.75" y="184.75" width="214.5" height="116.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="330" y="217" fill="#52616F" font-family="Arial, sans-serif" font-size="14" font-weight="600">Runtime State</text>
<text x="330" y="263" fill="#17202A" font-family="Arial, sans-serif" font-size="38" font-weight="700">Warm</text>
<text x="330" y="286" fill="#D99000" font-family="Arial, sans-serif" font-size="14" font-weight="700">Last ping 00:01.2</text>
<rect x="536" y="184" width="190" height="118" rx="10" fill="#FFFFFF"/>
<rect x="536.75" y="184.75" width="188.5" height="116.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="562" y="217" fill="#52616F" font-family="Arial, sans-serif" font-size="14" font-weight="600">Health</text>
<text x="562" y="263" fill="#17202A" font-family="Arial, sans-serif" font-size="38" font-weight="700">98%</text>
<text x="562" y="286" fill="#2F80ED" font-family="Arial, sans-serif" font-size="14" font-weight="700">No crash signal</text>
<text x="72" y="322" fill="#7B8794" font-family="Courier, monospace" font-size="13">Updated 14:32:08 [SDK]</text>
</g>
<g filter="url(#cardShadow)">
<rect x="36" y="346" width="724" height="558" rx="10" fill="#FFFFFF"/>
<rect x="36.75" y="346.75" width="722.5" height="556.5" rx="10" stroke="#C9D1D9" stroke-width="2"/>
<text x="72" y="402" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Session Log</text>
<text x="72" y="428" fill="#52616F" font-family="Arial, sans-serif" font-size="14" font-weight="500">Tx blue, Rx green, system purple</text>
<rect x="574" y="378" width="154" height="42" rx="10" fill="#E8F1FF"/>
<rect x="574.75" y="378.75" width="152.5" height="40.5" rx="10" stroke="#2F80ED" stroke-width="1.5"/>
<circle cx="598" cy="399" r="7" fill="#31A66A"/>
<text x="656" y="404" text-anchor="middle" fill="#2F80ED" font-family="Arial, sans-serif" font-size="15" font-weight="700">Start / Stop</text>
<rect x="72" y="452" width="640" height="416" rx="10" fill="#FFFFFF"/>
<rect x="72.75" y="452.75" width="638.5" height="414.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="104" y="492" fill="#2F80ED" font-family="Courier, monospace" font-size="15">14:32:06.212 [TX] bind request sent</text>
<text x="104" y="518" fill="#31A66A" font-family="Courier, monospace" font-size="15">14:32:06.438 [RX] ping =&gt; &quot;pong&quot;</text>
<text x="104" y="544" fill="#7B8794" font-family="Courier, monospace" font-size="15">14:32:07.042 [SYS] state poll updated</text>
<text x="104" y="570" fill="#31A66A" font-family="Courier, monospace" font-size="15">14:32:08.115 [RX] getHealthStateJson =&gt; {&quot;ok&quot;:true}</text>
<text x="104" y="596" fill="#2F80ED" font-family="Courier, monospace" font-size="15">14:32:08.640 [TX] request warm start</text>
<text x="104" y="622" fill="#7B8794" font-family="Courier, monospace" font-size="15">14:32:09.021 [SYS] log stream running</text>
<text x="104" y="648" fill="#31A66A" font-family="Courier, monospace" font-size="15">14:32:09.302 [RX] runtime lifecycle =&gt; WARM</text>
<text x="104" y="674" fill="#2F80ED" font-family="Courier, monospace" font-size="15">14:32:09.618 [TX] getDebugSnapshotJson</text>
<text x="104" y="700" fill="#31A66A" font-family="Courier, monospace" font-size="15">14:32:09.774 [RX] debug snapshot =&gt; 1.4 KB</text>
<text x="104" y="726" fill="#7B8794" font-family="Courier, monospace" font-size="15">14:32:10.001 [SYS] snapshot cached</text>
<rect x="684" y="486" width="12" height="330" rx="6" fill="#E5E9EE"/>
<rect x="685.5" y="566" width="9" height="106" rx="4.5" fill="#A4AFBA"/>
<circle cx="690" cy="474" r="12" fill="#EEF1F4"/>
<path d="M685.5 477L690 471L694.5 477" stroke="#7B8794" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="690" cy="832" r="12" fill="#EEF1F4"/>
<path d="M685.5 829L690 835L694.5 829" stroke="#7B8794" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<g filter="url(#cardShadow)">
<rect x="772" y="36" width="792" height="868" rx="10" fill="url(#controlGlow)"/>
<rect x="772.75" y="36.75" width="790.5" height="866.5" rx="10" stroke="#C9D1D9" stroke-width="2"/>
<text x="832" y="120" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Controls</text>
<text x="832" y="148" fill="#52616F" font-family="Arial, sans-serif" font-size="14" font-weight="500">Rounded grid buttons fill control card</text>
<g>
<rect x="832" y="214" width="208" height="136" rx="10" fill="#F3F8FF"/>
<rect x="832.75" y="214.75" width="206.5" height="134.5" rx="10" stroke="#2F80ED" stroke-width="1.5"/>
<text x="936" y="276" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Bind</text>
<text x="936" y="306" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">Start bridge</text>
<text x="936" y="326" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">session</text>
</g>
<g>
<rect x="1064" y="214" width="208" height="136" rx="10" fill="#F3F8FF"/>
<rect x="1064.75" y="214.75" width="206.5" height="134.5" rx="10" stroke="#2F80ED" stroke-width="1.5"/>
<text x="1168" y="276" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Unbind</text>
<text x="1168" y="306" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">Close service</text>
<text x="1168" y="326" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">link</text>
</g>
<g>
<rect x="1296" y="214" width="208" height="136" rx="10" fill="#F3F8FF"/>
<rect x="1296.75" y="214.75" width="206.5" height="134.5" rx="10" stroke="#2F80ED" stroke-width="1.5"/>
<text x="1400" y="276" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Ping</text>
<text x="1400" y="306" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">Check round</text>
<text x="1400" y="326" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">trip</text>
</g>
<g>
<rect x="832" y="370" width="208" height="136" rx="10" fill="#FFFFFF"/>
<rect x="832.75" y="370.75" width="206.5" height="134.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="936" y="432" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Runtime State</text>
<text x="936" y="462" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">getRuntime</text>
<text x="936" y="482" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">StateJson</text>
</g>
<g>
<rect x="1064" y="370" width="208" height="136" rx="10" fill="#FFFFFF"/>
<rect x="1064.75" y="370.75" width="206.5" height="134.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="1168" y="432" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Health</text>
<text x="1168" y="462" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">getHealth</text>
<text x="1168" y="482" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">StateJson</text>
</g>
<g>
<rect x="1296" y="370" width="208" height="136" rx="10" fill="#FFFFFF"/>
<rect x="1296.75" y="370.75" width="206.5" height="134.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="1400" y="432" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Debug</text>
<text x="1400" y="462" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">getDebug</text>
<text x="1400" y="482" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">SnapshotJson</text>
</g>
<g>
<rect x="832" y="526" width="208" height="136" rx="10" fill="#FFFFFF"/>
<rect x="832.75" y="526.75" width="206.5" height="134.5" rx="10" stroke="#D5DDE5" stroke-width="1.5"/>
<text x="936" y="588" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Lifecycle</text>
<text x="936" y="618" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">getRuntimeLifecycle</text>
<text x="936" y="638" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">StateJson</text>
</g>
<g>
<rect x="1064" y="526" width="440" height="136" rx="10" fill="#FFFBED"/>
<rect x="1064.75" y="526.75" width="438.5" height="134.5" rx="10" stroke="#D99000" stroke-width="1.5"/>
<text x="1284" y="588" text-anchor="middle" fill="#17202A" font-family="Arial, sans-serif" font-size="22" font-weight="700">Warm Start</text>
<text x="1284" y="618" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">requestRuntime</text>
<text x="1284" y="638" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">WarmStart</text>
</g>
<g opacity="0.8">
<rect x="832" y="682" width="672" height="140" rx="10" fill="#FFFFFF"/>
<rect x="832.75" y="682.75" width="670.5" height="138.5" rx="10" stroke="#C9D1D9" stroke-width="1.5"/>
<text x="1168" y="744" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="22" font-weight="700">Room for future actions</text>
<text x="1168" y="774" text-anchor="middle" fill="#52616F" font-family="Arial, sans-serif" font-size="14">without shrinking button grid</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

+151 -156
View File
@@ -1,175 +1,170 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="1120" viewBox="0 0 1600 1120"> <svg xmlns="http://www.w3.org/2000/svg" width="3840" height="2160" viewBox="0 0 3840 2160">
<defs> <defs>
<style> <style>
.bg { fill: #f4f6f8; } .bg { fill: #f4f6f8; }
.panel { fill: #ffffff; stroke: #c9d1d9; stroke-width: 2; } .panel { fill: #ffffff; stroke: #c9d1d9; stroke-width: 3; }
.panel-disabled { fill: #eef1f4; stroke: #c9d1d9; stroke-width: 2; } .panel-disabled { fill: #eef1f4; stroke: #c9d1d9; stroke-width: 3; }
.panel-active { fill: #ffffff; stroke: #2f80ed; stroke-width: 3; } .panel-active { fill: #ffffff; stroke: #2f80ed; stroke-width: 4; }
.preview { fill: #101820; stroke: #2f80ed; stroke-width: 2; } .preview { fill: #101820; stroke: #2f80ed; stroke-width: 3; }
.title { font-family: Arial; font-size: 25px; font-weight: 700; fill: #17202a; } .title { font-family: Arial; font-size: 48px; font-weight: 700; fill: #17202a; }
.subtitle { font-family: Arial; font-size: 16px; fill: #52616f; } .subtitle { font-family: Arial; font-size: 28px; fill: #52616f; }
.section { font-family: Arial; font-size: 17px; font-weight: 700; fill: #17202a; } .section { font-family: Arial; font-size: 32px; font-weight: 700; fill: #17202a; }
.label { font-family: Arial; font-size: 14px; fill: #27313b; } .label { font-family: Arial; font-size: 24px; fill: #27313b; }
.muted { font-family: Arial; font-size: 13px; fill: #7b8794; } .muted { font-family: Arial; font-size: 23px; fill: #7b8794; }
.disabled-text { font-family: Arial; font-size: 14px; fill: #8a96a3; } .disabled-text { font-family: Arial; font-size: 24px; fill: #8a96a3; }
.mono { font-family: Courier; font-size: 12px; fill: #39434d; } .mono { font-family: Courier; font-size: 24px; fill: #39434d; }
.mono-light { font-family: Courier; font-size: 12px; fill: #c9d9ea; } .mono-light { font-family: Courier; font-size: 30px; fill: #c9d9ea; }
.chip-ok { fill: #d9f5e5; stroke: #31a66a; } .chip-ok { fill: #d9f5e5; stroke: #31a66a; stroke-width: 2; }
.chip-warn { fill: #fff4d7; stroke: #d99000; } .chip-warn { fill: #fff4d7; stroke: #d99000; stroke-width: 2; }
.chip-off { fill: #e5e9ee; stroke: #a4afba; } .chip-off { fill: #e5e9ee; stroke: #a4afba; stroke-width: 2; }
.button { fill: #f8fafc; stroke: #aab4bf; stroke-width: 1.5; } .button { fill: #ffffff; stroke: #aab4bf; stroke-width: 2; }
.button-primary { fill: #e8f1ff; stroke: #2f80ed; stroke-width: 1.5; } .button-primary { fill: #e8f1ff; stroke: #2f80ed; stroke-width: 2; }
.button-disabled { fill: #e3e7eb; stroke: #c2cbd3; stroke-width: 1.5; } .button-disabled { fill: #e3e7eb; stroke: #c2cbd3; stroke-width: 2; }
</style> </style>
</defs> </defs>
<rect class="bg" x="0" y="0" width="1600" height="1120"/> <rect class="bg" x="0" y="0" width="3840" height="2160"/>
<text class="title" x="40" y="50">kiwii-sdk-control-panel</text> <text class="title" x="80" y="90">kiwii-sdk-control-panel</text>
<text class="subtitle" x="40" y="78">AAR SDK validation control panel. Device components stay visible; unavailable components stay gray until capability detected.</text> <text class="subtitle" x="80" y="136">AAR SDK validation control panel. Components stay visible; unavailable surfaces stay gray until detected.</text>
<rect class="panel-active" x="40" y="105" width="1520" height="120" rx="8"/> <rect class="panel-active" x="80" y="190" width="3680" height="230" rx="10"/>
<text class="section" x="64" y="140">Global RuntimeHost Status</text> <text class="section" x="130" y="246">Global RuntimeHost Status</text>
<rect class="chip-warn" x="64" y="158" width="145" height="32" rx="16"/> <text class="muted" x="130" y="288">RuntimeHost binding controls SDK access. Component availability remains detected per device.</text>
<text class="label" x="86" y="179">Bound: false</text>
<rect class="chip-off" x="228" y="158" width="175" height="32" rx="16"/>
<text class="label" x="250" y="179">Ping: NOT_BOUND</text>
<text class="muted" x="425" y="178">Last API: none</text>
<text class="muted" x="610" y="178">Last error: waiting for RuntimeHost bind</text>
<rect class="button-primary" x="64" y="200" width="85" height="32" rx="6"/>
<text class="label" x="92" y="221">Bind</text>
<rect class="button" x="160" y="200" width="95" height="32" rx="6"/>
<text class="label" x="187" y="221">Unbind</text>
<rect class="button" x="266" y="200" width="85" height="32" rx="6"/>
<text class="label" x="295" y="221">Ping</text>
<text class="mono" x="375" y="220">RuntimeHost bound enables component detection; component availability is still per-device.</text>
<rect class="panel-active" x="40" y="255" width="365" height="205" rx="8"/> <rect class="chip-warn" x="130" y="320" width="230" height="54" rx="10"/>
<text class="section" x="62" y="290">RuntimeHostStatusComponent</text> <text class="label" x="170" y="355">Bound: false</text>
<rect class="chip-ok" x="62" y="307" width="112" height="28" rx="14"/> <rect class="chip-off" x="390" y="320" width="280" height="54" rx="10"/>
<text class="label" x="84" y="326">Active</text> <text class="label" x="428" y="355">Ping: NOT_BOUND</text>
<text class="muted" x="62" y="357">Always interactive; owns bind state refresh.</text> <text class="muted" x="720" y="355">Last API: none</text>
<rect class="button-primary" x="62" y="382" width="112" height="30" rx="6"/> <text class="muted" x="980" y="355">Last error: waiting for RuntimeHost bind</text>
<text class="label" x="86" y="402">Bind Host</text>
<rect class="button" x="186" y="382" width="112" height="30" rx="6"/>
<text class="label" x="214" y="402">Runtime</text>
<rect class="button" x="62" y="420" width="112" height="30" rx="6"/>
<text class="label" x="90" y="440">Health</text>
<rect class="button" x="186" y="420" width="112" height="30" rx="6"/>
<text class="label" x="212" y="440">Lifecycle</text>
<rect class="panel-disabled" x="425" y="255" width="365" height="205" rx="8"/> <rect class="button-primary" x="2980" y="260" width="180" height="64" rx="10"/>
<text class="section" x="447" y="290">CameraComponent</text> <text class="label" x="3035" y="301">Bind</text>
<rect class="chip-off" x="447" y="307" width="150" height="28" rx="14"/> <rect class="button" x="3190" y="260" width="200" height="64" rx="10"/>
<text class="disabled-text" x="469" y="326">Gray: not detected</text> <text class="label" x="3240" y="301">Unbind</text>
<text class="disabled-text" x="447" y="357">Needs RuntimeHost bound + camera state available.</text> <rect class="button" x="3420" y="260" width="160" height="64" rx="10"/>
<rect class="button" x="447" y="382" width="112" height="30" rx="6"/> <text class="label" x="3470" y="301">Ping</text>
<text class="label" x="486" y="402">Detect</text>
<rect class="button-disabled" x="571" y="382" width="112" height="30" rx="6"/>
<text class="disabled-text" x="598" y="402">State</text>
<rect class="button-disabled" x="447" y="420" width="236" height="30" rx="6"/>
<text class="disabled-text" x="502" y="440">Open Full Camera View</text>
<rect class="panel-disabled" x="810" y="255" width="365" height="205" rx="8"/> <rect class="panel-active" x="80" y="470" width="875" height="300" rx="10"/>
<text class="section" x="832" y="290">LeftHandleComponent</text> <text class="section" x="130" y="528">RuntimeHostStatus</text>
<rect class="chip-off" x="832" y="307" width="150" height="28" rx="14"/> <rect class="chip-ok" x="130" y="552" width="170" height="46" rx="10"/>
<text class="disabled-text" x="854" y="326">Gray: not detected</text> <text class="label" x="172" y="582">Active</text>
<text class="disabled-text" x="832" y="357">Needs left handle data.</text> <text class="muted" x="130" y="642">Always interactive. Owns bind, runtime, health, and lifecycle checks.</text>
<rect class="button" x="832" y="382" width="112" height="30" rx="6"/> <rect class="button-primary" x="130" y="682" width="180" height="54" rx="10"/>
<text class="label" x="871" y="402">Detect</text> <text class="label" x="168" y="717">Bind Host</text>
<rect class="button-disabled" x="956" y="382" width="112" height="30" rx="6"/> <rect class="button" x="330" y="682" width="180" height="54" rx="10"/>
<text class="disabled-text" x="984" y="402">IMU</text> <text class="label" x="378" y="717">Runtime</text>
<rect class="button-disabled" x="832" y="420" width="112" height="30" rx="6"/> <rect class="button" x="530" y="682" width="150" height="54" rx="10"/>
<text class="disabled-text" x="864" y="440">HE Static</text> <text class="label" x="573" y="717">Health</text>
<rect class="button-disabled" x="956" y="420" width="112" height="30" rx="6"/> <rect class="button" x="700" y="682" width="180" height="54" rx="10"/>
<text class="disabled-text" x="987" y="440">HE Stream</text> <text class="label" x="742" y="717">Lifecycle</text>
<rect class="panel-disabled" x="1195" y="255" width="365" height="205" rx="8"/> <rect class="panel-disabled" x="995" y="470" width="875" height="300" rx="10"/>
<text class="section" x="1217" y="290">RightHandleComponent</text> <text class="section" x="1045" y="528">Camera</text>
<rect class="chip-off" x="1217" y="307" width="150" height="28" rx="14"/> <rect class="chip-off" x="1045" y="552" width="270" height="46" rx="10"/>
<text class="disabled-text" x="1239" y="326">Gray: not detected</text> <text class="disabled-text" x="1085" y="582">Gray: not detected</text>
<text class="disabled-text" x="1217" y="357">Needs right handle data.</text> <text class="disabled-text" x="1045" y="642">Requires RuntimeHost binding and camera state availability.</text>
<rect class="button" x="1217" y="382" width="112" height="30" rx="6"/> <rect class="button" x="1045" y="682" width="180" height="54" rx="10"/>
<text class="label" x="1256" y="402">Detect</text> <text class="label" x="1100" y="717">Detect</text>
<rect class="button-disabled" x="1341" y="382" width="112" height="30" rx="6"/> <rect class="button-disabled" x="1245" y="682" width="160" height="54" rx="10"/>
<text class="disabled-text" x="1369" y="402">IMU</text> <text class="disabled-text" x="1293" y="717">State</text>
<rect class="button-disabled" x="1217" y="420" width="112" height="30" rx="6"/> <rect class="button-disabled" x="1425" y="682" width="280" height="54" rx="10"/>
<text class="disabled-text" x="1249" y="440">HE Static</text> <text class="disabled-text" x="1460" y="717">Full Camera View</text>
<rect class="button-disabled" x="1341" y="420" width="112" height="30" rx="6"/>
<text class="disabled-text" x="1372" y="440">HE Stream</text>
<rect class="panel-disabled" x="40" y="485" width="365" height="205" rx="8"/> <rect class="panel-disabled" x="1910" y="470" width="875" height="300" rx="10"/>
<text class="section" x="62" y="520">BalanceBoardComponent</text> <text class="section" x="1960" y="528">Left Handle</text>
<rect class="chip-off" x="62" y="537" width="150" height="28" rx="14"/> <rect class="chip-off" x="1960" y="552" width="270" height="46" rx="10"/>
<text class="disabled-text" x="84" y="556">Gray: not detected</text> <text class="disabled-text" x="2000" y="582">Gray: not detected</text>
<text class="disabled-text" x="62" y="587">Needs balance board data.</text> <text class="disabled-text" x="1960" y="642">Requires left handle data before IMU and haptics are enabled.</text>
<rect class="button" x="62" y="612" width="112" height="30" rx="6"/> <rect class="button" x="1960" y="682" width="180" height="54" rx="10"/>
<text class="label" x="101" y="632">Detect</text> <text class="label" x="2015" y="717">Detect</text>
<rect class="button-disabled" x="186" y="612" width="112" height="30" rx="6"/> <rect class="button-disabled" x="2160" y="682" width="150" height="54" rx="10"/>
<text class="disabled-text" x="216" y="632">State</text> <text class="disabled-text" x="2208" y="717">IMU</text>
<rect class="button-disabled" x="62" y="650" width="112" height="30" rx="6"/> <rect class="button-disabled" x="2330" y="682" width="180" height="54" rx="10"/>
<text class="disabled-text" x="93" y="670">Balance</text> <text class="disabled-text" x="2372" y="717">Haptics</text>
<rect class="button-disabled" x="186" y="650" width="112" height="30" rx="6"/>
<text class="disabled-text" x="217" y="670">Telemetry</text>
<rect class="panel-disabled" x="425" y="485" width="365" height="205" rx="8"/> <rect class="panel-disabled" x="2825" y="470" width="935" height="300" rx="10"/>
<text class="section" x="447" y="520">MotorComponent</text> <text class="section" x="2875" y="528">Right Handle</text>
<rect class="chip-off" x="447" y="537" width="150" height="28" rx="14"/> <rect class="chip-off" x="2875" y="552" width="270" height="46" rx="10"/>
<text class="disabled-text" x="469" y="556">Gray: not detected</text> <text class="disabled-text" x="2915" y="582">Gray: not detected</text>
<text class="disabled-text" x="447" y="587">Needs motor state/control state.</text> <text class="disabled-text" x="2875" y="642">Requires right handle data before IMU and haptics are enabled.</text>
<rect class="button" x="447" y="612" width="112" height="30" rx="6"/> <rect class="button" x="2875" y="682" width="180" height="54" rx="10"/>
<text class="label" x="486" y="632">Detect</text> <text class="label" x="2930" y="717">Detect</text>
<rect class="button-disabled" x="571" y="612" width="112" height="30" rx="6"/> <rect class="button-disabled" x="3075" y="682" width="150" height="54" rx="10"/>
<text class="disabled-text" x="605" y="632">Set Kg</text> <text class="disabled-text" x="3123" y="717">IMU</text>
<rect class="button-disabled" x="447" y="650" width="112" height="30" rx="6"/> <rect class="button-disabled" x="3245" y="682" width="180" height="54" rx="10"/>
<text class="disabled-text" x="475" y="670">Set Mode</text> <text class="disabled-text" x="3287" y="717">Haptics</text>
<rect class="button-disabled" x="571" y="650" width="112" height="30" rx="6"/>
<text class="disabled-text" x="604" y="670">State</text>
<rect class="panel-disabled" x="810" y="485" width="365" height="205" rx="8"/> <rect class="panel-disabled" x="80" y="820" width="875" height="300" rx="10"/>
<text class="section" x="832" y="520">TelemetrySafetyComponent</text> <text class="section" x="130" y="878">Balance Board</text>
<rect class="chip-off" x="832" y="537" width="125" height="28" rx="14"/> <rect class="chip-off" x="130" y="902" width="270" height="46" rx="10"/>
<text class="disabled-text" x="854" y="556">Gray: bound</text> <text class="disabled-text" x="170" y="932">Gray: not detected</text>
<text class="disabled-text" x="832" y="587">Available after RuntimeHost bound.</text> <text class="disabled-text" x="130" y="992">Requires balance board data before telemetry views are enabled.</text>
<rect class="button-disabled" x="832" y="612" width="112" height="30" rx="6"/> <rect class="button" x="130" y="1032" width="180" height="54" rx="10"/>
<text class="disabled-text" x="858" y="632">Telemetry</text> <text class="label" x="185" y="1067">Detect</text>
<rect class="button-disabled" x="956" y="612" width="112" height="30" rx="6"/> <rect class="button-disabled" x="330" y="1032" width="170" height="54" rx="10"/>
<text class="disabled-text" x="987" y="632">Safety</text> <text class="disabled-text" x="383" y="1067">State</text>
<rect class="button-disabled" x="832" y="650" width="112" height="30" rx="6"/> <rect class="button-disabled" x="520" y="1032" width="200" height="54" rx="10"/>
<text class="disabled-text" x="852" y="670">Device Cmd</text> <text class="disabled-text" x="570" y="1067">Balance</text>
<rect class="button-disabled" x="956" y="650" width="112" height="30" rx="6"/>
<text class="disabled-text" x="990" y="670">Trace</text>
<rect class="panel" x="1195" y="485" width="365" height="205" rx="8"/> <rect class="panel-disabled" x="995" y="820" width="875" height="300" rx="10"/>
<text class="section" x="1217" y="520">SessionLogComponent</text> <text class="section" x="1045" y="878">Motor</text>
<rect class="chip-ok" x="1217" y="537" width="112" height="28" rx="14"/> <rect class="chip-off" x="1045" y="902" width="270" height="46" rx="10"/>
<text class="label" x="1239" y="556">Active</text> <text class="disabled-text" x="1085" y="932">Gray: not detected</text>
<text class="muted" x="1217" y="587">Records all SDK calls.</text> <text class="disabled-text" x="1045" y="992">Requires motor state and motor control state.</text>
<rect x="1217" y="612" width="305" height="58" rx="6" fill="#f8fafc" stroke="#d5dde5"/> <rect class="button" x="1045" y="1032" width="180" height="54" rx="10"/>
<text class="mono" x="1232" y="636">16:27:00 bind() -> false</text> <text class="label" x="1100" y="1067">Detect</text>
<text class="mono" x="1232" y="660">16:27:05 camera.detect -> skipped</text> <rect class="button-disabled" x="1245" y="1032" width="180" height="54" rx="10"/>
<text class="disabled-text" x="1290" y="1067">Set Kg</text>
<rect class="button-disabled" x="1445" y="1032" width="180" height="54" rx="10"/>
<text class="disabled-text" x="1495" y="1067">Mode</text>
<rect class="panel" x="40" y="720" width="930" height="350" rx="8"/> <rect class="panel-disabled" x="1910" y="820" width="875" height="300" rx="10"/>
<text class="section" x="64" y="756">CameraComponent Detail View</text> <text class="section" x="1960" y="878">Telemetry Safety</text>
<text class="muted" x="64" y="786">When CameraComponent is selected, user can open full camera preview without hiding device cards.</text> <rect class="chip-off" x="1960" y="902" width="220" height="46" rx="10"/>
<rect class="preview" x="64" y="805" width="610" height="230" rx="8"/> <text class="disabled-text" x="1998" y="932">Gray: bound</text>
<text class="mono-light" x="268" y="925">Full Camera Preview</text> <text class="disabled-text" x="1960" y="992">Available after RuntimeHost is bound.</text>
<text class="mono-light" x="248" y="950">16:9 frame, full visible image</text> <rect class="button-disabled" x="1960" y="1032" width="210" height="54" rx="10"/>
<rect class="button-disabled" x="700" y="805" width="180" height="34" rx="6"/> <text class="disabled-text" x="2010" y="1067">Telemetry</text>
<text class="disabled-text" x="738" y="827">Camera State</text> <rect class="button-disabled" x="2190" y="1032" width="170" height="54" rx="10"/>
<rect class="button-disabled" x="700" y="852" width="180" height="34" rx="6"/> <text class="disabled-text" x="2240" y="1067">Safety</text>
<text class="disabled-text" x="736" y="874">Refresh Frame</text> <rect class="button-disabled" x="2380" y="1032" width="220" height="54" rx="10"/>
<rect class="button-disabled" x="700" y="899" width="180" height="34" rx="6"/> <text class="disabled-text" x="2425" y="1067">Device Cmd</text>
<text class="disabled-text" x="730" y="921">Open Fullscreen</text>
<text class="mono" x="700" y="970">status: unavailable</text>
<text class="mono" x="700" y="996">reason: Host not bound</text>
<rect class="panel" x="1000" y="720" width="560" height="350" rx="8"/> <rect class="panel" x="2825" y="820" width="935" height="300" rx="10"/>
<text class="section" x="1024" y="756">Selected Component Result</text> <text class="section" x="2875" y="878">Session Log</text>
<text class="muted" x="1024" y="786">Latest call, params, status, return summary, error summary.</text> <rect class="chip-ok" x="2875" y="902" width="170" height="46" rx="10"/>
<rect x="1024" y="805" width="500" height="150" rx="6" fill="#f8fafc" stroke="#d5dde5"/> <text class="label" x="2918" y="932">Active</text>
<text class="mono" x="1044" y="835">selected=CameraComponent</text> <text class="muted" x="2875" y="992">Records SDK calls and skipped actions.</text>
<text class="mono" x="1044" y="862">call=detect</text> <rect x="2875" y="1032" width="760" height="54" rx="10" fill="#ffffff" stroke="#d5dde5"/>
<text class="mono" x="1044" y="889">status=idle</text> <text class="mono" x="2900" y="1067">16:27:05 camera.detect -> skipped</text>
<text class="mono" x="1044" y="916">result=waiting for RuntimeHost bind</text>
<rect class="panel" x="80" y="1170" width="2390" height="850" rx="10"/>
<text class="section" x="130" y="1230">CameraComponent Detail View</text>
<text class="muted" x="130" y="1270">Selected camera detail keeps the component grid visible while showing a full preview and camera actions.</text>
<rect class="preview" x="130" y="1310" width="1520" height="580" rx="10"/>
<text class="mono-light" x="690" y="1588">Full Camera Preview</text>
<text class="mono-light" x="655" y="1636">16:9 frame, full visible image</text>
<rect class="button-disabled" x="1710" y="1310" width="320" height="64" rx="10"/>
<text class="disabled-text" x="1790" y="1352">Camera State</text>
<rect class="button-disabled" x="1710" y="1400" width="320" height="64" rx="10"/>
<text class="disabled-text" x="1780" y="1442">Refresh Frame</text>
<rect class="button-disabled" x="1710" y="1490" width="320" height="64" rx="10"/>
<text class="disabled-text" x="1775" y="1532">Open Fullscreen</text>
<text class="mono" x="1710" y="1645">status: unavailable</text>
<text class="mono" x="1710" y="1685">reason: Host not bound</text>
<rect class="panel" x="2530" y="1170" width="1230" height="850" rx="10"/>
<text class="section" x="2580" y="1230">Selected Component Result</text>
<text class="muted" x="2580" y="1270">Latest call, params, status, result, and error summary.</text>
<rect x="2580" y="1310" width="1040" height="210" rx="10" fill="#ffffff" stroke="#d5dde5"/>
<text class="mono" x="2610" y="1360">selected=CameraComponent</text>
<text class="mono" x="2610" y="1405">call=detect</text>
<text class="mono" x="2610" y="1450">status=idle</text>
<text class="mono" x="2610" y="1495">result=waiting for RuntimeHost bind</text>
<rect x="2580" y="1570" width="1040" height="340" rx="10" fill="#ffffff" stroke="#d5dde5"/>
<text class="mono" x="2610" y="1620">16:27:00 bind() -> false</text>
<text class="mono" x="2610" y="1665">16:27:05 camera.detect -> skipped</text>
<text class="mono" x="2610" y="1710">16:27:08 motor.detect -> skipped</text>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB