# Role and permissions matrix

> A dark violet permissions grid: toggles flip for two roles, a Save button is pressed and a confirmation toast appears.

- Category: Developer tools
- Version: 1.0
- Source: https://ownlyplans.com/bhaskar/role-and-permissions-matrix/

## Overview

A roles table with five roles and four permissions as toggle switches. The Support agent publish toggle switches on, the Editor publish toggle switches off, the two rows glow, Save is pressed and a green toast confirms. Topic inspired by OpenDesign's public dashboard prompt list; this prompt and design are written from scratch.

## Tech stack

- CSS
- Dashboard
- HTML

## Build steps

### 1. Paste the prompt

The AI builds the matrix and toggles.

Prompt:

```text
Create a single-file HTML roles and permissions matrix, 1280x720, deep violet background #150f2b, panel #1d1640, header row #241b52, accent violet #8b5cf6, text #ece8ff. System fonts, no libraries.
Header: H1 "Roles and permissions" and a muted subtitle "Decide who can view, edit, publish and bill".
Table with columns Role, View, Edit, Publish, Billing and five rows (Admin, Editor, Support agent, Finance, Viewer). Each permission cell is a 46x26px toggle switch (off: #3a2f78, on: violet with a white knob that moves 20px). Sensible defaults: Admin all on, Editor all but Billing, Support agent View and Edit, Finance View and Billing, Viewer View only.
Bottom right: a violet "Save changes" button. Bottom left: a green toast "Permissions updated for 2 roles".
Motion (8 second loop): rows rise in with a stagger. The Support agent row and the Editor row get a faint violet highlight. The Support agent Publish toggle animates from off to on (colour and knob), the Editor Publish toggle animates from on to off. The Save button presses (scale .92), then the toast slides up and fades. Everything resets at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```

### 2. Check the toggles

Two toggles should flip with a smooth knob.

### 3. Check the save

The button press should be followed by the toast.

**Done when:** You can see it working in the browser.

### 4. Make it real

Wire the toggles to your role data and a save endpoint.

## Assets

### prompt.md — The full prompt.

~~~~
# Role and permissions matrix

Copy this prompt into Claude, Cursor or Lovable.

```text
Create a single-file HTML roles and permissions matrix, 1280x720, deep violet background #150f2b, panel #1d1640, header row #241b52, accent violet #8b5cf6, text #ece8ff. System fonts, no libraries.
Header: H1 "Roles and permissions" and a muted subtitle "Decide who can view, edit, publish and bill".
Table with columns Role, View, Edit, Publish, Billing and five rows (Admin, Editor, Support agent, Finance, Viewer). Each permission cell is a 46x26px toggle switch (off: #3a2f78, on: violet with a white knob that moves 20px). Sensible defaults: Admin all on, Editor all but Billing, Support agent View and Edit, Finance View and Billing, Viewer View only.
Bottom right: a violet "Save changes" button. Bottom left: a green toast "Permissions updated for 2 roles".
Motion (8 second loop): rows rise in with a stagger. The Support agent row and the Editor row get a faint violet highlight. The Support agent Publish toggle animates from off to on (colour and knob), the Editor Publish toggle animates from on to off. The Save button presses (scale .92), then the toast slides up and fades. Everything resets at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```
~~~~

### index.html.md — Complete code of the result in the video.

~~~~
# index.html

The finished result as one file. Save it as index.html and open it.

```html
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Role and permissions matrix</title><style>*{box-sizing:border-box;margin:0;padding:0}
html,body{width:1280px;height:720px;overflow:hidden}
body{font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;-webkit-font-smoothing:antialiased}
@property --n{syntax:'<integer>';inherits:false;initial-value:0}
.stage{position:absolute;inset:0;animation:cyc 8s linear infinite both}
@keyframes cyc{0%{opacity:0}4%{opacity:1}94%{opacity:1}100%{opacity:0}}
body:not(.go) *,body:not(.go) *::before,body:not(.go) *::after{animation-play-state:paused!important}
.cnt::after{content:counter(n)}.cnt{counter-reset:n var(--n)}
@media (prefers-reduced-motion:reduce){*{animation:none!important}}


body{background:#150f2b;color:#ece8ff}
.w{position:absolute;left:48px;right:48px;top:34px}
h1{font-size:28px;letter-spacing:-.03em}.sub{color:#9b92c9;font-size:14px;margin:6px 0 22px}
table{width:100%;border-collapse:collapse;background:#1d1640;border-radius:20px;overflow:hidden}
th{padding:18px 20px;font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:#a79ee0;text-align:center;background:#241b52}th:first-child{text-align:left}
td{height:68px;border-top:1px solid #2b2260;text-align:center;font-size:15px}td:first-child{text-align:left;padding-left:20px}
tr{opacity:0;animation:tr 8s infinite both}tr:nth-child(2){animation-delay:.08s}tr:nth-child(3){animation-delay:.16s}tr:nth-child(4){animation-delay:.24s}tr:nth-child(5){animation-delay:.32s}tr:nth-child(6){animation-delay:.4s}
@keyframes tr{0%,6%{opacity:0;transform:translateY(10px)}14%,100%{opacity:1;transform:none}}
.tg{display:inline-block;width:46px;height:26px;border-radius:99px;background:#3a2f78;position:relative}.tg::after{content:"";position:absolute;left:3px;top:3px;width:20px;height:20px;border-radius:50%;background:#fff}
.on{background:#8b5cf6}.on::after{left:23px}
.f1{animation:f1 8s infinite both}.f2{animation:f2 8s infinite both}
@keyframes f1{0%,34%{background:#3a2f78}40%,100%{background:#8b5cf6}}
.f1::after{animation:m1 8s infinite both}@keyframes m1{0%,34%{left:3px}40%,100%{left:23px}}
@keyframes f2{0%,52%{background:#8b5cf6}58%,100%{background:#3a2f78}}
.f2::after{animation:m2 8s infinite both}@keyframes m2{0%,52%{left:23px}58%,100%{left:3px}}
.hl td{animation:hl 8s infinite both}@keyframes hl{0%,30%{background:transparent}36%,46%{background:#8b5cf622}52%,60%{background:#8b5cf622}66%,100%{background:transparent}}
.sv{position:absolute;right:48px;bottom:36px;background:#8b5cf6;color:#fff;border-radius:14px;padding:14px 24px;font-weight:700;animation:sv 8s infinite both}
@keyframes sv{0%,66%{transform:none;opacity:1}70%{transform:scale(.92)}74%,100%{transform:none}}
.ts{position:absolute;left:48px;bottom:36px;background:#123f2b;border:1px solid #34d399;color:#6ee7b7;border-radius:14px;padding:14px 20px;font-weight:700;opacity:0;animation:ts 8s infinite both}
@keyframes ts{0%,74%{opacity:0;transform:translateY(12px)}80%,94%{opacity:1;transform:none}100%{opacity:0}}
</style></head><body><div class="stage"><div class="w"><h1>Roles and permissions</h1><div class="sub">Decide who can view, edit, publish and bill</div>
<table><thead><tr><th>Role</th><th>View</th><th>Edit</th><th>Publish</th><th>Billing</th></tr></thead><tbody><tr><td>Admin</td><td><span class="tg on "></span></td><td><span class="tg on "></span></td><td><span class="tg on "></span></td><td><span class="tg on "></span></td></tr><tr class="hl"><td>Editor</td><td><span class="tg on "></span></td><td><span class="tg on "></span></td><td><span class="tg on f2"></span></td><td><span class="tg  "></span></td></tr><tr class="hl"><td>Support agent</td><td><span class="tg on "></span></td><td><span class="tg on "></span></td><td><span class="tg  f1"></span></td><td><span class="tg  "></span></td></tr><tr><td>Finance</td><td><span class="tg on "></span></td><td><span class="tg  "></span></td><td><span class="tg  "></span></td><td><span class="tg on "></span></td></tr><tr><td>Viewer</td><td><span class="tg on "></span></td><td><span class="tg  "></span></td><td><span class="tg  "></span></td><td><span class="tg  "></span></td></tr></tbody></table></div><div class="ts">Permissions updated for 2 roles</div><div class="sv">Save changes</div></div><script>window.start=function(){document.body.classList.add("go")};if(!/[?&]rec/.test(location.search))start();</script></body></html>
```
~~~~


## Build instructions by tool

### Claude Code

Open a terminal in an empty folder, run `claude`, then paste the prompt.

```text
Build the "Role and permissions matrix" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/role-and-permissions-matrix/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the toggles → Check the save → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Claude Code.)
```

### Cursor

Open an empty folder in Cursor, start an Agent chat, then paste the prompt.

```text
Build the "Role and permissions matrix" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/role-and-permissions-matrix/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the toggles → Check the save → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Cursor.)
```

### Lovable

Start a new Lovable project and paste the prompt as your first message.

```text
Build the "Role and permissions matrix" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/role-and-permissions-matrix/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the toggles → Check the save → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Lovable.)
```

## Definition of done

- Every build step is complete and the app runs locally.
- The main user flow works end to end.
- Share your build on OwnlyPlans with a demo link, build time and tool.
