{"id":50069664,"url":"https://github.com/nicosandller/easy-floorplan","last_synced_at":"2026-06-01T08:00:35.656Z","repository":{"id":359270822,"uuid":"1245294334","full_name":"nicosandller/easy-floorplan","owner":"nicosandller","description":"Interactive Home Assistant floorplan card with a visual drag-and-drop editor for walls, doors, furniture, text and device controls","archived":false,"fork":false,"pushed_at":"2026-05-25T00:48:57.000Z","size":115,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-28T05:02:40.679Z","etag":null,"topics":["custom-card","floorplan","hacs","home-assistant","homeassistant","lovelace","lovelace-card"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicosandller.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-21T05:05:04.000Z","updated_at":"2026-05-27T15:43:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nicosandller/easy-floorplan","commit_stats":null,"previous_names":["nicosandller/easy-floorplan"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/nicosandller/easy-floorplan","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicosandller%2Feasy-floorplan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicosandller%2Feasy-floorplan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicosandller%2Feasy-floorplan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicosandller%2Feasy-floorplan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicosandller","download_url":"https://codeload.github.com/nicosandller/easy-floorplan/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicosandller%2Feasy-floorplan/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33765379,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["custom-card","floorplan","hacs","home-assistant","homeassistant","lovelace","lovelace-card"],"created_at":"2026-05-22T02:22:19.915Z","updated_at":"2026-06-01T08:00:35.649Z","avatar_url":"https://github.com/nicosandller.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Easy Floorplan\n\n[![hacs][hacs-badge]][hacs-url]\n[![release][release-badge]][release-url]\n[![license][license-badge]](LICENSE)\n\nA Home Assistant Lovelace card for building an interactive floorplan — **with a visual DRAG AND DROP \neditor**. Draw walls, drop doors and windows, add gray furniture diagrams and text\nlabels, and place your entities as icons, ripples or live state. Everything scales\nautomatically to the card and screen size.\n\n\u003cimg width=\"1080\" height=\"608\" alt=\"demo\" src=\"https://github.com/user-attachments/assets/98abaddc-b713-492f-be85-ca5f778f3779\" /\u003e\n\n## Features\n\n- **Visual editor** — draw walls (endpoints snap to nearby corners to close rooms),\n  click to drop doors/windows that snap onto walls, drag everything around, nudge with\n  arrow keys, undo/redo, zoom.\n- **Devices** — bind any entity to an icon. Click to toggle lights/switches or open the\n  more-info dialog. Optional live state label (incl. a paired temperature + humidity\n  entity), custom icon (with autocomplete + preview), size and rotation.\n- **Presence ripples** — render presence/movement sensors as animated concentric rings\n  that pulse while active and fade to a faint dot when idle.\n- **Animated doors \u0026 windows** — link a contact `binary_sensor` or `cover` so doors swing\n  and windows open on the plan as their real state changes, with an optional accent color\n  while open.\n- **Furniture** — gray line-art diagrams: table, round table, desk, chair, sofa, bed,\n  wardrobe, rug, plant, fridge, stove, sink, toilet, stairs, tv.\n- **Text labels** and a configurable **canvas background color**.\n- **Background image** — drop in a floor-plan image (per floor) and trace walls, doors and\n  devices over it, with adjustable opacity.\n- **Multiple floors** — group elements per floor and switch between them with a control in\n  the top-right (in both the editor and the live card).\n- **Multi-select \u0026 copy/paste** — shift/ctrl-click or drag a box to select many; move,\n  duplicate (Ctrl/Cmd+D), copy/paste (Ctrl/Cmd+C/V) or delete them together.\n- **Snapping** — by default walls and elements snap to the visible grid; switch **Snap to**\n  to **Off** for free placement, or **Custom** to snap to your own step.\n- **Auto-scaling** — a virtual coordinate space + SVG means the plan rescales to any\n  card or screen size with no reflow.\n\n## What you can end up with\n\n\u003cimg width=\"1103\" height=\"592\" alt=\"demo_screenshot\" src=\"https://github.com/user-attachments/assets/c05d32e3-8a9e-4643-8c25-79c1128dbb59\" /\u003e\n\n## Installation\n\n### HACS (recommended)\n\nThis is currently distributed as a **custom repository**. Click the badge to add it\nto your own Home Assistant in one step:\n\n[![Open Easy Floorplan in HACS](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=nicosandller\u0026repository=easy-floorplan\u0026category=frontend)\n\n…or add it manually:\n\n1. In Home Assistant, open **HACS**.\n2. Top-right **⋮ → Custom repositories**.\n3. Add repository URL `https://github.com/nicosandller/easy-floorplan` with category\n   **Dashboard** (a.k.a. Plugin).\n4. Find **Easy Floorplan** in HACS and click **Download**.\n5. Hard-refresh your browser (Cmd/Ctrl-Shift-R).\n\nHACS adds the dashboard resource automatically.\n\n### Manual\n\n1. Download `easy-floorplan-card.js` from the [latest release][release-url].\n2. Copy it to `\u003cconfig\u003e/www/easy-floorplan-card.js`.\n3. Add it as a dashboard resource (**Settings → Dashboards → ⋮ → Resources → Add**):\n   - URL `/local/easy-floorplan-card.js`\n   - Type **JavaScript module**\n4. Hard-refresh your browser.\n\n## Usage\n\nEdit a dashboard → **Add card** → search **Easy Floorplan**. The editor is laid out\ntop-to-bottom as a **tools row**, a **context row** with options/actions for whatever\nyou're doing, the **canvas**, and two sections below — **Element** (per-element editor\nfor the current selection) and **Project** (page-level settings like canvas size, grid,\nbackground):\n\n- **select** — the default tool. Click an element to select it; Shift/Ctrl-click or drag\n  a box to select several at once. Arrow keys nudge the selection (Shift+arrow jumps a\n  full grid cell), and **Ctrl/Cmd+C/V/D** copy / paste / duplicate. With a selection,\n  the context row offers **duplicate** and **delete**, and the **Element** section below\n  the canvas exposes the full property editor for whatever you have selected.\n- **wall** — drag to draw. Endpoints snap to nearby corners; start a new wall on an\n  existing corner to continue the perimeter. The context row's **straighten** toggle\n  keeps walls horizontal/vertical and corner-snapped (turn it off to draw freely), and\n  the **Snap** segmented control (`On` / `Off` / `Custom`) governs snapping for *all*\n  tools — `Custom` lets you snap to a percentage of the grid (e.g. 50% = half a cell).\n- **door / window** — click to drop; it snaps onto the nearest wall. The context row\n  shows a **Length** field for the *next* opening you place, so you can size doors and\n  windows before placing them. Assign a sensor after placement (in the **Element**\n  section) to animate the opening open/closed — see **Doors \u0026 windows**.\n- **+ device / + text / + furniture…** — drop a new element; the **Element** section\n  below the canvas shows its full property editor so you can configure it right away.\n- **floor** — add, rename, switch and delete floors.\n\nUndo/redo and a zoom slider live at the right of the tools row.\n\n## Elements\n\nEverything you place on the plan is an **element** you can select, move (freely or\nsnapped to a grid), nudge with arrow keys, copy/paste, duplicate and delete. The element\ntypes are **devices**, **doors \u0026 windows**, **furniture** and **text** — and each floor\nholds its own set of them.\n\n### Devices\n\nA **device** binds a Home Assistant entity to a spot on the plan. Add one with\n**+ device**, then pick the entity in the **Element** section below the canvas.\nBy default it shows an icon badge:\n\n- **Tap to act** — lights, switches, covers, fans and `input_boolean`s toggle on tap;\n  any other entity opens its more-info dialog.\n- **Live look** — the badge highlights when the entity is \"on\". Turn on **Show state**\n  to display the current value next to it. Add a **2nd entity** to show two readings in\n  one element — e.g. a temperature and a humidity sensor render together as `21 °C · 45 %`.\n- **Make it yours** — override the **icon** (with autocomplete + live preview), set a\n  custom **name**, change the **size**, **rotate** it, or hide the icon entirely.\n\n### Presence ripples\n\nFor motion/occupancy/presence sensors, switch a device's **Display** mode from *Icon\nbadge* to **Ripple** or **Icon + ripple**. Instead of a static icon it draws animated\nconcentric rings:\n\n- **Active** (sensor on) → the rings continuously pulse outward and fade, drawing the\n  eye to where motion is happening.\n- **Idle** (sensor off) → the rings stop and only a faint dot remains, so the spot stays\n  marked without being distracting.\n\nYou can set the **ripple color** and **ripple size** per device, so e.g. a calm blue\nring in the living room and a warmer one by the entrance. It works with any entity that\nreports an on/off-like state, not just presence sensors.\n\n\u003cimg width=\"540\" height=\"304\" alt=\"ripple_demo_gif\" src=\"https://github.com/user-attachments/assets/e43949cf-13a2-48f8-804d-73738299475f\" /\u003e\n\n### Doors \u0026 windows\n\nDrop a **door** or **window** from the toolbar and it snaps onto the nearest wall. On its\nown a door is drawn open (the familiar swing arc) and a window closed — a static floor\nplan, just like before.\n\nSelect the opening and bind a **Sensor** entity in the **Element** section below the canvas —\na contact `binary_sensor` or a `cover` — to make the opening track its real state:\n\n- **Open / closed** — the opening is drawn open when the entity is `on` / `open`, closed\n  otherwise. A door's leaf swings around its hinge; a window's two leaves swing outward\n  from the middle. When closed the swing arc is hidden; as the opening moves, the arc\n  **draws on**, tracing the path of the leaf edge — animated smoothly.\n- **Active color** — while actively open, the leaf/sash and arc take an accent color (the\n  same idea as presence ripples) so an open door is easy to spot. Defaults to the primary\n  color; pick your own per opening.\n- **Invert** — flip the open/closed interpretation for sensors wired the other way.\n\nOpenings without a sensor keep the static look.\n\n\u003cimg width=\"540\" height=\"304\" alt=\"door_window_demo\" src=\"https://github.com/user-attachments/assets/091b3c89-5202-4025-8a0f-0fe867276be2\" /\u003e\n\n\n## Configuration reference\n\nThe editor writes this config for you; manual editing is optional.\n\n### Top level\n\n| Option       | Type     | Default            | Description                                  |\n| ------------ | -------- | ------------------ | -------------------------------------------- |\n| `type`       | string   | —                  | `custom:easy-floorplan-card`                 |\n| `title`      | string   | —                  | Optional card header.                        |\n| `width`      | number   | `1000`             | Virtual canvas width, in canvas units.       |\n| `height`     | number   | `600`              | Virtual canvas height, in canvas units.      |\n| `grid`       | number   | `20`               | Gap between grid lines, in canvas units (so on a 1000-wide canvas, `20` ≈ 50 columns). A **smaller** number means a **finer** grid with more lines. |\n| `snap`       | number   | follows `grid`     | Snap step for placement / drag / nudge / wall drawing, in canvas units. Omit to snap to the visible grid; set `0` for free placement; set any other number for a custom step. The editor shows a custom step as a **percentage of the grid** (e.g. `50` % of a `20` grid is stored here as `10`), but the value here is always absolute. |\n| `background` | string   | card background    | Canvas background color (CSS / hex).         |\n| `floors`     | Floor[]  | —                  | Per-floor element groups (see **Floors**).   |\n| `defaultFloor`| string  | first floor        | Id of the floor shown first.                 |\n| `walls`      | Wall[]   | `[]`               | Wall segments (single-floor / floor 1).      |\n| `openings`   | Opening[]| `[]`               | Doors and windows.                           |\n| `items`      | Item[]   | `[]`               | Entity devices.                              |\n| `texts`      | Text[]   | `[]`               | Free text labels.                            |\n| `furniture`  | Furniture[]| `[]`             | Gray furniture/fixture diagrams.             |\n\nWhen `floors` is present each floor carries its own `walls`, `openings`, `items`, `texts`\nand `furniture`. The top-level arrays describe a single implicit floor and remain valid\nfor backward compatibility.\n\n### Floor\n\n`{ id, name, image?, imageOpacity?, walls, openings, items, texts, furniture }` — a named\nfloor with its own elements. Use the **floor** controls in the editor toolbar to add,\nrename, switch and delete floors; the live card shows a floor switcher in the top-right\nwhen there is more than one.\n\nSet **`image`** to a background image URL (e.g. `/local/floorplan.png` or an external\nURL) to draw it behind the elements — handy for tracing over a real floor plan. It fills\nthe canvas, so match the canvas `width`/`height` to the image's aspect ratio to avoid\ndistortion. **`imageOpacity`** (0–1, default 1) fades it.\n\n### Wall\n\n`{ id, x1, y1, x2, y2 }` — endpoints in virtual units.\n\n### Opening (door / window)\n\n| Field         | Type                | Description                                            |\n| ------------- | ------------------- | ------------------------------------------------------ |\n| `id`          | string              | Unique id.                                             |\n| `type`        | `door` \\| `window`  | Symbol drawn.                                          |\n| `x`, `y`      | number              | Center position.                                       |\n| `length`      | number              | Length along the wall.                                 |\n| `angle`       | number              | Rotation in degrees.                                   |\n| `entity`      | string              | Optional contact `binary_sensor` / `cover` driving open/closed. |\n| `invert`      | boolean             | Flip the open/closed interpretation.                   |\n| `activeColor` | string              | Leaf/arc color while actively open (default primary).  |\n\n### Item (device)\n\n| Field         | Type                                   | Default      | Description                                            |\n| ------------- | -------------------------------------- | ------------ | ------------------------------------------------------ |\n| `id`          | string                                 | —            | Unique id.                                             |\n| `entity`      | string                                 | —            | Entity id to bind.                                     |\n| `secondaryEntity` | string                             | —            | Optional 2nd entity shown alongside (e.g. humidity).   |\n| `x`, `y`      | number                                 | —            | Position.                                              |\n| `kind`        | light/switch/sensor/binary_sensor/climate/cover/generic | inferred | Used for the default icon.            |\n| `icon`        | string                                 | entity icon  | Override mdi icon.                                     |\n| `name`        | string                                 | friendly name| Label / tooltip override.                             |\n| `size`        | number                                 | `34`         | Icon badge diameter (px).                              |\n| `angle`       | number                                 | `0`          | Icon rotation (deg).                                   |\n| `display`     | `badge` \\| `ripple` \\| `iconRipple`    | `badge`      | How the device is drawn.                               |\n| `rippleColor` | string                                 | primary color| Ripple ring color (ripple modes).                     |\n| `rippleSize`  | number                                 | `80`         | Max ripple diameter (px).                              |\n| `showIcon`    | boolean                                | `true`       | Show the icon badge.                                   |\n| `showState`   | boolean                                | sensors only | Show the entity state label.                           |\n\nClicking a `light`, `switch`, `cover`, `fan` or `input_boolean` toggles it; other\ndomains open the more-info dialog.\n\n### Text\n\n`{ id, x, y, text, size?, color?, angle? }` — `size` px (default 16), `color` CSS/hex,\n`angle` degrees.\n\n### Furniture\n\n`{ id, type, x, y, w, h, angle?, color? }` where `type` is one of `table`, `roundTable`,\n`desk`, `chair`, `sofa`, `bed`, `wardrobe`, `rug`, `plant`, `fridge`, `stove`, `sink`,\n`toilet`, `stairs`, `tv`. `color` defaults to gray so furniture reads differently from\nwalls.\n\n### Example\n\n```yaml\ntype: custom:easy-floorplan-card\ntitle: Living Room\nwidth: 1000\nheight: 600\ngrid: 20\nbackground: \"#fafafa\"\nwalls:\n  - { id: w1, x1: 100, y1: 100, x2: 900, y2: 100 }\n  - { id: w2, x1: 900, y1: 100, x2: 900, y2: 500 }\n  - { id: w3, x1: 900, y1: 500, x2: 100, y2: 500 }\n  - { id: w4, x1: 100, y1: 500, x2: 100, y2: 100 }\nopenings:\n  - id: d1\n    type: door\n    x: 300\n    y: 500\n    length: 80\n    angle: 0\n    entity: binary_sensor.front_door   # swings open when the contact opens\n    activeColor: \"#ef5350\"\n  - { id: win1, type: window, x: 600, y: 100, length: 140, angle: 0 }\nitems:\n  - { id: i1, entity: light.living_room, x: 240, y: 200, kind: light }\n  - id: i2\n    entity: binary_sensor.presence\n    x: 380\n    y: 380\n    kind: binary_sensor\n    display: iconRipple\n    rippleColor: \"#26c6da\"\n    rippleSize: 120\n  - id: i3\n    entity: sensor.living_room_temperature\n    secondaryEntity: sensor.living_room_humidity\n    x: 700\n    y: 380\n    kind: sensor\n    showState: true\nfurniture:\n  - { id: f1, type: sofa, x: 250, y: 420, w: 170, h: 72, angle: 0 }\ntexts:\n  - { id: t1, x: 500, y: 60, text: Living Room, size: 22 }\n```\n\n## Development\n\n```bash\nnpm install\nnpm run build      # bundles to dist/easy-floorplan-card.js\nnpm run watch      # rebuild on change\n```\n\nReleases are built and attached automatically by GitHub Actions when a GitHub release\nis published.\n\n## License\n\n[MIT](LICENSE)\n\n[hacs-badge]: https://img.shields.io/badge/HACS-Custom-41BDF5.svg\n[hacs-url]: https://github.com/hacs/integration\n[release-badge]: https://img.shields.io/github/v/release/nicosandller/easy-floorplan\n[release-url]: https://github.com/nicosandller/easy-floorplan/releases\n[license-badge]: https://img.shields.io/github/license/nicosandller/easy-floorplan\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicosandller%2Feasy-floorplan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicosandller%2Feasy-floorplan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicosandller%2Feasy-floorplan/lists"}