From 151a6e5aee975b668d2b62402c7efa6ef75df2cc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 21 Dec 2025 20:27:00 +0000
Subject: [PATCH 1/3] Initial plan
From 8f4b41a670835c9f14551b4067805b27e7b4a7a5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 21 Dec 2025 20:39:10 +0000
Subject: [PATCH 2/3] Implement UI quiet companion behavior rules
- Create UI_RULES.md with 3 core behavior rules
- Implement Rule 1: Remove auto-tab switching on context events
- Rule 2: No notifications (verified - none exist)
- Rule 3: Passive status indicators (verified - already compliant)
- Fix TypeScript build error with NodeHelpView prop
Co-authored-by: lebduska <11066249+lebduska@users.noreply.github.com>
---
blendmate-app/docs/UI_RULES.md | 112 +++++++++++++++++++++++++++++++++
blendmate-app/src/App.tsx | 5 +-
2 files changed, 115 insertions(+), 2 deletions(-)
create mode 100644 blendmate-app/docs/UI_RULES.md
diff --git a/blendmate-app/docs/UI_RULES.md b/blendmate-app/docs/UI_RULES.md
new file mode 100644
index 0000000..63dc51c
--- /dev/null
+++ b/blendmate-app/docs/UI_RULES.md
@@ -0,0 +1,112 @@
+# UI Behavior Rules: "Quiet Companion"
+
+Blendmate is designed as a **quiet co-pilot**, not a needy chatbot. These rules ensure non-intrusive behavior that respects user focus and workflow.
+
+---
+
+## Core Principle
+
+**The app should be seen but not heard.** Information is always available when needed, but never forces itself into the user's attention.
+
+---
+
+## Implemented Rules
+
+### 1. No Auto-Opening Panels on Events
+
+**Rule:** When Blender sends events (like `context` messages for active nodes), the app MUST NOT automatically switch tabs or open new panels.
+
+**Rationale:** Users should maintain control over their workspace. Unsolicited UI changes are disruptive and break flow state.
+
+**Implementation:**
+- The `activeTab` state in `App.tsx` is user-controlled only
+- Incoming `context` messages update the `currentNodeId` state silently
+- When user manually switches to the 'nodes' tab, they see the updated node help
+- No modals, popups, or forced navigation based on WebSocket events
+
+**Code Toggles:**
+- `App.tsx`: Comment lines 17-19 to disable node switching behavior
+- Future: Add `settings.autoSwitchToNode` boolean config
+
+---
+
+### 2. Notifications Are Opt-In and Low-Priority
+
+**Rule:** The app MUST NOT generate system notifications, alert sounds, or attention-grabbing indicators unless explicitly enabled by the user.
+
+**Rationale:** Notifications break concentration. Blendmate provides ambient awareness, not urgent alerts.
+
+**Implementation:**
+- No browser/system notifications are used
+- Connection status is shown passively via a small indicator dot in the HUD
+- Message updates appear in footer's debug log only (non-intrusive monospace text)
+- No audio feedback or badge counts
+
+**Code Toggles:**
+- Currently: No notification code exists (by design)
+- Future: If notifications are added, gate them behind `settings.enableNotifications: false` (default off)
+
+---
+
+### 3. Default to Passive Status Indicators
+
+**Rule:** All status information (connection state, frame counters, stats) MUST be displayed passively without animation or bright colors that demand attention.
+
+**Rationale:** Status indicators should provide context at-a-glance but not distract. Users should be able to ignore them when focused.
+
+**Implementation:**
+- Connection indicator: Small dot (3x3px) in HUD, green when connected
+ - Subtle pulse animation (opacity only), no scaling or bright flashes
+ - Red when disconnected, but no alert or modal
+- Footer status bar: Low-contrast monospace text (white/20 opacity)
+ - Shows last message in truncated format
+ - Frame rate indicator with minimal animation (single dot pulse)
+- Stats cards: Present but styled with muted colors, only accent color on hover
+
+**Code Toggles:**
+- `HUD.tsx` lines 15-16: Connection status indicator
+- `Footer.tsx` lines 25-33: Passive status display
+- To disable animations: Remove `animate-ping` and `animate-pulse` classes
+
+---
+
+## Anti-Patterns to Avoid
+
+These behaviors violate the "quiet companion" principle and MUST NOT be implemented:
+
+- ❌ Auto-scrolling to new content
+- ❌ Flashing or pulsing UI elements (except connection pulse)
+- ❌ Modal dialogs that require dismissal
+- ❌ Browser notifications or system tray alerts
+- ❌ Sound effects or haptic feedback
+- ❌ Forced tab switching based on events
+- ❌ "What's new" overlays or tutorial popups
+- ❌ Badge counts or unread indicators
+
+---
+
+## Future Considerations
+
+As the app evolves, new features should be evaluated against these rules:
+
+- **Chat Interface:** Should be manually opened, never auto-focus input
+- **Error States:** Show inline, never block workflow with error modals
+- **Updates Available:** Passive indicator only, no "Update Now" dialogs
+- **Knowledge Base Loading:** Show subtle progress, no full-screen spinners
+
+---
+
+## Testing Compliance
+
+To verify "quiet companion" behavior:
+
+1. Connect Blender and trigger various events (frame change, node selection)
+2. Verify that tab state doesn't change unexpectedly
+3. Confirm no system notifications appear
+4. Check that all animations are subtle and non-distracting
+5. Ensure status indicators can be easily ignored when working
+
+---
+
+**Last Updated:** 2025-12-21
+**Maintained By:** Project team & agents working on UI components
diff --git a/blendmate-app/src/App.tsx b/blendmate-app/src/App.tsx
index c581a5b..ccb55fa 100644
--- a/blendmate-app/src/App.tsx
+++ b/blendmate-app/src/App.tsx
@@ -12,11 +12,12 @@ export default function App() {
const [currentNodeId, setCurrentNodeId] = useState('GeometryNodeInstanceOnPoints');
// React to incoming context messages from Blender
+ // Rule 1 (UI_RULES.md): No auto-opening panels on events
useEffect(() => {
if (lastMessage) {
if (lastMessage.type === 'context' && lastMessage.node_id) {
setCurrentNodeId(lastMessage.node_id as string);
- setActiveTab('nodes');
+ // Removed auto-switch to 'nodes' tab - user controls tab state
} else if (lastMessage.type === 'event' && lastMessage.event === 'frame_change') {
setFrame(lastMessage.frame as number);
}
@@ -60,7 +61,7 @@ export default function App() {