- Unified graph node colors with card color system (shared localStorage) - Added color picker palette button to node overlay toolbar - Auto-focus graph container for keyboard shortcuts to work immediately - Trap Tab key to prevent focus escaping to footer - Added mandatory bundle rebuild note to CLAUDE.md files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.0 KiB
Claude Instructions for WLED Screen Controller Server
Development Workflow
Server Restart Policy
IMPORTANT: When making changes to server code (Python files in src/wled_controller/), you MUST restart the server if it's currently running to ensure the changes take effect.
NOTE: Auto-reload is currently disabled (reload=False in main.py) due to watchfiles causing an infinite reload loop. Changes to server code will NOT be automatically picked up - manual server restart is required.
When to restart:
- After modifying API routes (
api/routes.py,api/schemas.py) - After updating core logic (
core/*.py) - After changing configuration (
config.py) - After modifying utilities (
utils/*.py) - After updating data models or database schemas
How to check if server is running:
# Look for running Python processes with wled_controller
ps aux | grep wled_controller
# Or check for processes listening on port 8080
netstat -an | grep 8080
How to restart:
- Find the task ID of the running server (look for background bash tasks in conversation)
- Stop the server using TaskStop with the task ID
- Check for port conflicts (port 8080 may still be in use):
If a process is still using port 8080, kill it:
netstat -ano | findstr :8080powershell -Command "Stop-Process -Id <PID> -Force" - Start a new server instance in the background:
Use
cd server && python -m wled_controller.mainrun_in_background: trueparameter in Bash tool - Wait 3 seconds for server to initialize:
sleep 3 - Verify startup by reading the output file:
- Look for "Uvicorn running on http://0.0.0.0:8080"
- Check for any errors in stderr
- Verify "Application startup complete" message
Common Issues:
- Port 8080 in use: Old process didn't terminate cleanly - kill it manually
- Module import errors: Check that all Python files are syntactically correct
- Permission errors: Ensure file permissions allow Python to execute
Files that DON'T require restart:
- Static files (
static/*.html,static/*.css,static/*.js) - but you MUST rebuild the bundle after changes:cd server && npm run build - Locale files (
static/locales/*.json) - loaded by frontend - Documentation files (
*.md) - Configuration files in
config/if server supports hot-reload (check implementation)
Git Commit and Push Policy
CRITICAL: NEVER commit OR push code changes without explicit user approval.
Rules
- You MUST NOT create commits without explicit user instruction
- You MUST NOT push commits unless explicitly instructed by the user
- Wait for the user to review changes and ask you to commit
- If the user says "commit", create a commit but DO NOT push
- If the user says "commit and push", you may push after committing
- Always wait for explicit permission before any commit or push operation
Workflow
- Make changes to code
- STOP and WAIT - inform the user of changes and wait for instruction
- Only create commit when user explicitly requests it (e.g., "commit", "create a commit")
- STOP and WAIT - do not push
- Only push when user explicitly requests it (e.g., "push", "commit and push", "push to remote")
Testing Changes
After restarting the server with new code:
- Test the modified endpoints/functionality
- Check browser console for any JavaScript errors
- Verify API responses match updated schemas
- Test with different locales if i18n was modified
Project Structure Notes
src/wled_controller/main.py- FastAPI application entry pointsrc/wled_controller/api/- REST API endpoints and schemassrc/wled_controller/core/- Core business logic (screen capture, WLED client, processing)src/wled_controller/utils/- Utility functions (logging, monitor detection)src/wled_controller/static/- Frontend files (HTML, CSS, JS, locales)config/- Configuration files (YAML)data/- Runtime data (devices.json, persistence)
Common Tasks
Adding a new API endpoint:
- Add route to
api/routes.py - Define request/response schemas in
api/schemas.py - Restart the server
- Test the endpoint via
/docs(Swagger UI)
Adding a new field to existing API:
- Update Pydantic schema in
api/schemas.py - Update corresponding dataclass (if applicable)
- Update backend logic to populate the field
- Restart the server
- Update frontend to display the new field
Modifying display/monitor detection:
- Update functions in
utils/monitor_names.pyorcore/screen_capture.py - Restart the server
- Test with
GET /api/v1/config/displays
Modifying server login:
- Update the logic.
- Restart the server
Adding translations:
- Add keys to
static/locales/en.jsonandstatic/locales/ru.json - Add
data-i18nattributes to HTML elements instatic/index.html - Use
t('key')function instatic/app.jsfor dynamic content - No server restart needed (frontend only)
Frontend UI Patterns
Entity Cards
All entity cards (devices, targets, CSS sources, streams, scenes, automations, etc.) must support clone functionality. Clone buttons use the ICON_CLONE (📋) icon in .card-actions.
Clone pattern: Clone must open the entity's add/create modal with fields prefilled from the cloned item. It must never silently create a duplicate — the user should review and confirm.
Implementation:
- Export a
cloneMyEntity(id)function that fetches (or finds in cache) the entity data - Call the add/create modal function, passing the entity data as
cloneData - In the modal opener, detect clone mode (no ID + cloneData present) and prefill all fields
- Append
' (Copy)'to the name - Set the modal title to the "add" variant (not "edit")
- The save action creates a new entity (POST), not an update (PUT)
export async function cloneMyEntity(id) {
const entity = myCache.data.find(e => e.id === id);
if (!entity) return;
showMyEditor(null, entity); // null id = create mode, entity = cloneData
}
Register the clone function in app.js window exports so inline onclick handlers can call it.
Modal Dialogs
IMPORTANT: All modal dialogs must follow these standards for consistent UX:
Backdrop Click Behavior
All modals MUST close when the user clicks outside the dialog (on the backdrop). Implement this by adding a click handler that checks if the clicked element is the modal backdrop itself:
// Show modal
const modal = document.getElementById('my-modal');
modal.style.display = 'flex';
// Add backdrop click handler to close modal
modal.onclick = function(event) {
if (event.target === modal) {
closeMyModal();
}
};
Where to add: In every function that shows a modal (e.g., showAddTemplateModal(), editTemplate(), showTestTemplateModal()).
Close Button Requirement
Each modal dialog that has a "Cancel" button MUST also have a cross (×) close button at the top-right corner of the dialog. This provides users with multiple intuitive ways to dismiss the dialog:
- Click the backdrop (outside the dialog)
- Click the × button (top-right corner)
- Click the Cancel button (bottom of dialog)
- Press Escape key (if implemented)
HTML Structure:
<div class="modal-content">
<button class="close-btn" onclick="closeMyModal()">×</button>
<h2>Dialog Title</h2>
<!-- dialog content -->
<div class="modal-actions">
<button onclick="closeMyModal()">Cancel</button>
<button onclick="submitAction()">Submit</button>
</div>
</div>
CSS Requirements:
- Close button should be positioned absolutely at top-right
- Should be easily clickable (min 24px × 24px hit area)
- Should have clear hover state
Authentication
Server uses API key authentication. Keys are configured in:
config/default_config.yamlunderauth.api_keys- Or via environment variables:
WLED_AUTH__API_KEYS
For development, ensure at least one API key is configured or the server won't start.