Billionaire
Live Hass Proxy
hass injected into <script> is now a live Proxy. Every property access (hass.states, hass.callService, etc.) transparently resolves to the latest HA object at call time. Closures, event handlers, and async callbacks no longer hold stale references.
┌─────────────────┐ set hass() ┌──────────────┐
│ HA Frontend │ ──────────────► │ html-pro-card │
│ (frequent push) │ │ this._hass │
└─────────────────┘ └───────┬────────┘
│
Proxy get(_, prop)
│
┌────────▼────────┐
│ script scope │
│ hass.states[id] │ ← always fresh
│ hass.callService│ ← always bound
└─────────────────┘
Implementation: new Proxy({}, { get: (_, prop) => { const v = self._hass[prop]; return typeof v === 'function' ? v.bind(self._hass) : v; }}). Functions are .bind()-ed to preserve this context.
Event-Driven Live Updates
New _watchedEntities + _onHassUpdate mechanism replaces polling for dynamic JS cards.
root._watchedEntities = ['light.', 'climate.living_room'];
root._onHassUpdate = () => renderUI();Internally, _shouldUpdate() resolves watch patterns into concrete entity ID lists via _resolveWatchList(), caches the result, and performs O(1) reference comparison (oldHass.states[id] !== newHass.states[id]). The resolved list is invalidated when:
- The watch pattern array reference changes
- The total entity count in hass changes (new entities added/removed)
Overlay Auto-Delegation
Global overlay container (#html-pro-card-overlay) now has a click event listener using event delegation. Any [data-action] + [data-entity] element appended to the overlay — by any card, at any time — automatically gets toggle/turn_on/turn_off/more-info handling without manual addEventListener calls.
Domain routing in overlay matches card-internal routing:
lock→ lock/unlock based on current statecover→ open_cover/close_cover based on current statebutton→ pressscene→ turn_onscript→ script.{name}- Others → {domain}.toggle
Overlay Ownership & Isolation
Each card instance generates a unique _instanceId on connectedCallback. The overlay variable passed to scripts is a Proxy that intercepts appendChild/append/prepend and auto-stamps each child with data-hpc-owner="${instanceId}".
On disconnectedCallback, only elements matching the card's own _instanceId are removed — other cards' overlay content is preserved.
Card A overlay content: <div data-hpc-owner="hpc_a3k2m1">...</div>
Card B overlay content: <div data-hpc-owner="hpc_x9f4j2">...</div>
↑ Card A disconnect only removes hpc_a3k2m1
Previous behavior (overlay.innerHTML = '') wiped all cards' content on any single card disconnect — this is now fixed.
Overlay Container Fix
Removed overflow: hidden from the global overlay container CSS. Child elements with overflow: auto (e.g., scrollable popup sheets) now scroll correctly.
Removed Global Close Button
The red circle close button (#claw-overlay-close) that auto-appeared at bottom-right is removed. Cards are responsible for their own close UI within overlay content.
Bug Fixes
- lock domain toggle:
lock→unlockwhen locked,lockwhen unlocked - cover domain toggle:
close_coverwhen open/opening,open_coverotherwise - Function binding in Proxy:
hass.callService()and other methods now have correctthiscontext via.bind(self._hass) root.hassexposed:set hass()now syncsthis._rootElement.hass = hassfor direct access
README
Complete AI prompt rewrite. Key additions:
- Live proxy hass documentation
_watchedEntities+_onHassUpdateusage pattern- Overlay usage rules, auto-delegation, auto-cleanup
window.clawAPI reference tabledata-mapstate text mappingborder-radiuscorrected to 10px- lock/cover domain mapping
- Icon rules: mdi, inline SVG, SVG libraries (Lucide/Feather/Tabler)
- Expanded banned patterns list
Full Changelog: v3.3...v3.5