| ~~Join/leave sounds need m.call.member state events~~ | **Use `useCallMembersChange()` hook** at `src/app/hooks/useCall.ts:37-52` — subscribes to `MatrixRTCSessionEvent.MembershipsChanged`, receives old/new membership arrays |
| ~~Glassmorphism needs parent wrapper (translateX blocks filter)~~ | **SAFE to apply directly to sidebar container** — `translateX` only on `SidebarItem` hover, not the sidebar container. Apply backdrop-filter to `Sidebar.css.ts:6-17` |
@@ -74,8 +79,9 @@ DM last-message preview, Media gallery, Knock-to-join full UX
| ~~Animated backgrounds: add to backgroundImage~~ | **backgroundImage can't have @keyframes** — use CSS `::before` pseudo-element on `<Page>` component with `position:absolute, inset:0, z-index:-1` |
#### Confirmed facts (all audits complete as of June 2026)
| `folds AvatarImage` does NOT accept children | Add frame/overlay inside `UserAvatar.tsx` itself — optional `frameName` prop |
| No in-app toast system exists | Task #80: build `ToastProvider` + Jotai queue; insert at `App.tsx:65` after `OverlayContainerProvider`; `portalContainer` in `index.html:101` |
| All room IDs atom | `src/app/state/room-list/roomList.ts` | `allRoomsAtom` |
@@ -169,13 +176,16 @@ Attack these first; most are single-file changes or simple new components.
---
### [ ] P0-1 · Report Room (MSC4151)
**Spec:** MSC4151, merged ~Matrix spec v1.12. Synapse supports it.
**Confirmed:** NOT present in upstream Cinny mainline.
**What:** Add a "Report Room" option in the room header context menu (⋮ or room settings). Opens a modal with a reason text field (required) and a Submit button. Calls:
```
POST /_matrix/client/v3/rooms/{roomId}/report
Body: { "reason": "string" }
```
The homeserver forwards the report to server admins.
**Where:**`src/app/features/room/RoomViewHeader.tsx` (add menu item), new `ReportRoomModal.tsx` component.
**Complexity:** Low — one API call, one modal.
@@ -183,12 +193,16 @@ The homeserver forwards the report to server admins.
---
### [ ] P0-2 · Server support contact display (MSC1929)
**Spec:** MSC1929, stable in Matrix spec.
**What:** On load (or when Settings → Help & About is opened), fetch:
```
GET /.well-known/matrix/support
```
Parse the `contacts` array and `support_page` URL. Display in Settings → Help & About:
Cache the response in component state; no repeated fetches.
@@ -198,9 +212,11 @@ Cache the response in component state; no repeated fetches.
---
### [ ] P0-3 · Server notices distinct rendering (m.server_notice)
**Spec:** CS-API §13.17, stable.
**Audit result:** CONFIRMED MISSING. Only `M_CANNOT_LEAVE_SERVER_NOTICE_ROOM` error code exists in `src/app/cs-errorcode.ts` — no rendering differentiation. Server notices currently arrive as plain DMs.
**What:** The `m.server_notice` room type is set in `m.room.create` content (`type: 'm.server_notice'`). Detect it via `room.getType() === 'm.server_notice'`. Render with:
- A distinct "Server Notice" header badge (server icon + label) in `RoomViewHeader.tsx`
- Slightly different background color (use `color.Warning` or neutral surface)
- Composer hidden/disabled in server notice rooms (check room type in `RoomInput.tsx`)
@@ -210,6 +226,7 @@ Cache the response in component state; no repeated fetches.
**Server check result:**`org.matrix.msc3892` is NOT in the server's unstable_features list — **NOT supported**. Current full-event redaction behavior is correct and should not be changed. This task is BLOCKED until the homeserver adds MSC3892 support. No action needed now.
**Complexity:** N/A — blocked.
@@ -217,6 +234,7 @@ Cache the response in component state; no repeated fetches.
**Server status:** Server reports v1.12 — MSC3765 not formally available. However, the `formatted_body` field on `m.room.topic` state events is part of the generic Matrix content structure and can be stored/read regardless of spec version. The rendering improvement is worthwhile to build now: it will activate whenever any room admin sets a formatted topic.
**What:** Pipe the `formatted_body` of the `m.room.topic` state event through the existing `sanitizeCustomHtml()` + `html-react-parser` pipeline (same as message bodies). Fall back to plain `body` if no `formatted_body` present.
@@ -226,6 +244,7 @@ Cache the response in component state; no repeated fetches.
---
### [ ] P0-6 · Edit history viewer
**Spec:** CS-API §11.8.2 (stable). Edit history is stored as `m.replace` relation events.
**Audit result:** Confirmed NOT in upstream Cinny. The "edited" label shows on messages (Message.tsx:1231) but clicking it does nothing. `getEventEdits()` is used internally but no history modal exists.
**What:** Click the "edited" label → popover/modal lists every prior version with timestamps. Fetch via `GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}/m.replace`. Show each version's body + timestamp. Use folds `Overlay`+`Modal` pattern.
@@ -235,6 +254,7 @@ Cache the response in component state; no repeated fetches.
---
### [BLOCKED] P0-7 · Room preview before joining (MSC3266)
**Spec:** MSC3266, merged Matrix spec v1.15.
**Server check result:**`GET /_matrix/client/v1/rooms/{roomId}/summary` returned **404** on `matrix.lotusguild.org`. Endpoint not available despite Synapse 1.153.0.
**Audit result:** Confirmed NOT in upstream Cinny — no pre-join preview screen exists.
@@ -244,6 +264,7 @@ Cache the response in component state; no repeated fetches.
---
### [ ] P0-8 · Personal room name overrides (MSC4431)
**Spec:** MSC4431, still in review.
**Server check:** Uses standard account data (`PUT /user/{userId}/account_data/`) which is universally supported regardless of MSC status. Safe to implement now; use `io.lotus.room_names` as the account data key until MSC4431 is finalized (may need to rename key when merged).
**What:** Right-click room in sidebar → "Rename for me…" → input dialog → saves to account data. Show a small ✏ icon next to locally-renamed rooms. `useRoomName()` hook in `useRoomMeta.ts:19-35` — override its return value when a local rename exists for that roomId.
@@ -253,17 +274,21 @@ Cache the response in component state; no repeated fetches.
---
### [UPSTREAM — REMOVED] P0-9 · "Back to Latest" button
**Audit result:** CONFIRMED UPSTREAM. `handleJumpToLatest()` + floating "Jump to Latest" Chip already exist in `RoomTimeline.tsx:2180-2192`. Task #104 (unread count + animation improvement) remains in the build queue.
---
### [UPSTREAM — REMOVED] P0-10 · Mark all rooms as read
**Audit result:** CONFIRMED UPSTREAM. Per-section "Mark as Read" exists at `Home.tsx:73-102` (home rooms) and `DirectTab.tsx:29-61` (DMs). No global all-sections version — but that was agreed not needed.
---
### [ ] P0-11 · Spoiler text audit and fix if broken
**What:** The message composer toolbar has a spoiler mark (||spoiler text||). Verify the end-to-end flow:
1. Composer correctly wraps text in `<span data-mx-spoiler>` in `formatted_body`
2. Timeline renderer displays spoiler as blurred/hidden text with a "Reveal" click
3. Mobile touch works for reveal
@@ -274,11 +299,13 @@ If any step is broken, fix it. If all working correctly, close this task with no
**Audit result:**`settings.ts` line 103: `urlPreview: true` (already on by default) · line 104: `encUrlPreview: false` (encrypted rooms OFF by default).
**What:** Change `encUrlPreview` default to `true` in `src/app/state/settings.ts`. Add a one-sentence security note next to the encrypted-room toggle in the settings UI:
> "URL previews in encrypted rooms are fetched by your homeserver, which sees the URL but not the message content."
**Where:** `src/app/state/settings.ts` line 104 (change default), settings UI file for URL preview toggles (find via grep for `encUrlPreview`).
**Complexity:** Very Low — one default value change + one sentence of UI text.
> **Where:** `src/app/state/settings.ts` line 104 (change default), settings UI file for URL preview toggles (find via grep for `encUrlPreview`).
> **Complexity:** Very Low — one default value change + one sentence of UI text.
---
@@ -289,7 +316,9 @@ Core features that meaningfully expand what users can do every day.
**What:** Global keyboard shortcut opens a floating search modal above all content. Features:
- Fuzzy-search across ALL rooms and DMs by display name in real time
- Keyboard navigable: `↑`/`↓` to move, `Enter` to open room, `Esc` to close
- Shows unread badge count inline next to each result
@@ -308,7 +337,9 @@ Core features that meaningfully expand what users can do every day.
---
### [ ] P1-2 · Media Gallery
**What:** A scrollable grid of all shared images, videos, and files in a room. Accessible via a new icon in the room header (picture/grid icon). Features:
- Tab bar: Images | Videos | Files
- Infinite scroll / paginated load via `GET /rooms/{roomId}/messages` filtering for `m.image`, `m.video`, `m.file` msgtypes
@@ -326,8 +357,10 @@ Core features that meaningfully expand what users can do every day.
---
### [ ] P1-3 · Sidebar Room Filter / Search
**What:** A text input at the top of each room list tab (Home, DMs, Spaces) that filters visible rooms in real time by display name. Ephemeral — clears when you switch tabs. No server calls — pure client-side filter over the loaded room list.
**Architecture:**
- Add filter `useState<string>('')` to each tab component
- Filter the room array before rendering: `rooms.filter(id => displayName(id).toLowerCase().includes(filter))`
- Show a small `×` clear button when filter is non-empty
@@ -339,8 +372,10 @@ Core features that meaningfully expand what users can do every day.
**What:** Show the last message text and relative timestamp ("2 min ago", "Yesterday") next to each DM in the sidebar, like iMessage or WhatsApp. Currently only the room name and unread badge are shown.
**Architecture:**
- For each DM room: get `room.getLastActiveTimestamp()` and `room.timeline[room.timeline.length - 1]` for the last event
- Render the event body (truncated to ~60 chars), stripping any HTML
- Format timestamp: "just now" / "X min ago" / "Yesterday" / date
@@ -351,22 +386,27 @@ Core features that meaningfully expand what users can do every day.
---
### [ ] P1-5 · Voice Message Playback Speed Control
**What:** Add a speed toggle to the voice message audio player in the room timeline: `0.75×` → `1×` → `1.5×` → `2×`. Clicking the current speed label cycles to the next. Uses the HTML `<audio>` element's `playbackRate` property.
**Architecture:**
-`const [speed, setSpeed] = useState(1)`
- On click: `audioRef.current.playbackRate = nextSpeed`
- Render a small clickable pill: `1×` etc., next to the audio controls
- Persist speed preference in `settingsAtom` so it carries across messages
**[AUDIT REQUIRED]** — Locate exactly where voice messages render in the timeline. Search for `m.audio` / `MSC3245` / `VoiceMessage` in `src/app/features/room/`. The recorder is in `VoiceMessageRecorder.tsx` but the *player* for received voice messages is elsewhere.
**[AUDIT REQUIRED]** — Locate exactly where voice messages render in the timeline. Search for `m.audio` / `MSC3245` / `VoiceMessage` in `src/app/features/room/`. The recorder is in `VoiceMessageRecorder.tsx` but the _player_ for received voice messages is elsewhere.
**Complexity:** Low-Medium.
---
### [ ] P1-6 · Poll Creation
**What:** Users can create polls from the message composer. Features:
- "Create Poll" toolbar button (poll icon) in `RoomInput.tsx`
- Modal: question field (required) + 2–10 answer options (add/remove dynamically) + single vs. multiple choice toggle
- Sends `m.poll.start` event (Matrix 1.7 stable format — same JSON we already render):
```json
{
"type":"m.poll.start",
@@ -379,6 +419,7 @@ Core features that meaningfully expand what users can do every day.
}
}
```
-`mx.sendEvent(roomId, 'm.poll.start', content)`
**Architecture:**
- New component: `src/app/features/room/PollCreator.tsx`
@@ -388,8 +429,10 @@ Core features that meaningfully expand what users can do every day.
---
### [ ] P1-7 · Code Syntax Highlighting in Messages
**What:** Color-code fenced code blocks in rendered messages. Language auto-detected from the code fence hint (` ```python `, ` ```js `, etc.).
**⚠️ MUST match `/root/code/web_template/base.css` exactly.** The web_template defines the canonical token structure for all Lotus apps:
@@ -409,11 +452,14 @@ See `/root/code/tinker_tickets/assets/js/markdown.js` for the reference tokenize
---
### [ ] P1-8 · Favorite / Starred Rooms
**What:** Star any room from its context menu. Starred rooms appear in a dedicated "Favorites" section at the top of the sidebar room list. Uses Matrix's built-in `m.favourite` room tag (account data), so favorites sync across devices and clients automatically.
```
PUT /_matrix/client/v3/user/{userId}/rooms/{roomId}/tags/m.favourite
Body: { "order": 0.5 }
```
- Right-click room → "Add to Favorites" / "Remove from Favorites"
- Favorites section appears above the regular room list in the Home tab
- Star icon shown on favorited rooms in the list
@@ -423,7 +469,9 @@ Body: { "order": 0.5 }
---
### [ ] P1-9 · Invite Link Generator (with QR code)
**What:** In room settings (or via right-click on room), a "Copy Invite Link" button that:
1. Generates a `matrix.to` URL: `https://matrix.to/#/!roomId:server?via=matrix.lotusguild.org`
2. Copies it to clipboard via `navigator.clipboard.writeText()`
3. Shows a QR code of the link (use a lightweight QR library e.g. `qrcode` npm package)
@@ -435,9 +483,11 @@ Body: { "order": 0.5 }
---
### [ ] P1-10 · Private Read Receipts toggle
**Spec:** CS-API stable — `m.read.private` vs `m.read`.
**What:** Add a toggle in Settings → Privacy: "Send private read receipts" — when enabled, read receipts are sent as `m.read.private` (only you and the server see them) instead of `m.read` (everyone in the room sees when you read). Default: public (current behavior, unchanged).
**Architecture:**
- New `settingsAtom` field: `privateReadReceipts: boolean` (default `false`)
- When sending a read receipt, check the setting and use the appropriate type
- Find `mx.sendReadReceipt(...)` call sites and add the `receiptType` parameter
@@ -447,8 +497,10 @@ Body: { "order": 0.5 }
---
### [ ] P1-11 · Knock-to-join UX (Room version 7)
**Spec:** Room version 7 (stable Matrix spec). Join rule: `knock`.
**What:** Full knock UX for both sides:
- **Knocking:** When a room's join rule is `knock`, show a "Request to Join" button instead of "Join Room". Sends `POST /join` which triggers a knock state event. Show pending state ("Request sent") while waiting.
- **Approving knocks:** Room admins/mods see a notification of pending knocks. In the members drawer or room settings, show a "Pending Requests" section listing knockers with "Approve" (`/invite`) and "Deny" (`/kick`) buttons.
**[SERVER CHECK]** — Verify `matrix.lotusguild.org` Synapse supports room version 7 and the knock join rule.
@@ -462,6 +514,7 @@ Body: { "order": 0.5 }
---
### [ ] P2-1 · Jump to Date
**What:** A calendar date picker accessible from the room header (small calendar icon). Selecting a date navigates the timeline to the first message on or after that date.
- "None" option to disable sound for that category
@@ -488,7 +543,9 @@ Returns `{ event_id, origin_server_ts }`. Then scroll the timeline to that event
---
### [ ] P2-3 · Sort Non-Space Rooms on Home Page
**What:** A sort control on the Home tab for orphan rooms (rooms not in any space). Options:
- **Unread first** — rooms with unread messages appear at top
- **Recent activity** — sort by `room.getLastActiveTimestamp()`
- **Alphabetical** — sort by display name A→Z
@@ -500,7 +557,9 @@ Persisted in `settingsAtom` as `homeRoomSortOrder: 'unread' | 'recent' | 'alpha'
---
### [ ] P2-4 · Export Room History
**What:** Export a room's messages to plain text, JSON, or HTML. Accessible from room settings (gear icon → "Export Room History"). Features:
- Format selector: Plain Text / JSON / HTML
- Date range filter (optional: all time or custom range)
- Only exports messages where E2EE decryption keys are available locally
@@ -514,10 +573,13 @@ Persisted in `settingsAtom` as `homeRoomSortOrder: 'unread' | 'recent' | 'alpha'
---
### [ ] P2-5 · Notification Quiet Hours
**What:** Set a daily time window when browser notifications are suppressed (e.g., 11:00 PM – 8:00 AM). Toggle + start/end time pickers in Settings → Notifications.
**Architecture:**
- New `settingsAtom` field: `quietHours: { enabled: boolean, start: string, end: string }` (times as "HH:MM" 24h strings)
- In `ClientNonUIFeatures.tsx` or `SystemNotification.tsx`, before dispatching a browser `Notification`, check:
```ts
functionisQuietHours(settings):boolean{
if(!settings.quietHours.enabled)returnfalse;
@@ -528,6 +590,7 @@ function isQuietHours(settings): boolean {
...
}
```
- Client-side only — does not touch Synapse push rules
**[AUDIT REQUIRED]** — Find the exact location in the codebase where browser `Notification` objects are created. Confirm no other code paths trigger sounds/notifications that also need to be suppressed.
**Complexity:** Medium.
@@ -535,7 +598,9 @@ function isQuietHours(settings): boolean {
---
### [ ] P2-6 · Room Activity / Moderation Log
**What:** A filterable log of room state changes, accessible from room settings. Shows:
- Member joins, leaves, kicks, bans, unbans
- Power level changes ("@alice promoted to Moderator by @bob")
- Room name / topic / avatar changes
@@ -548,7 +613,9 @@ Fetches via `/rooms/{roomId}/messages?filter={"types":["m.room.member","m.room.p
**[AUDIT REQUIRED — DO THIS FIRST]** — Before any implementation, verify the current behavior:
1. Paste a Giphy URL (e.g. `https://giphy.com/gifs/...`) into the Lotus Chat composer and send it
2. Does it auto-embed as an animated GIF, or render as a plain URL preview card?
3. Repeat for Tenor URLs
@@ -709,6 +798,7 @@ User must explicitly check the box — compression is NEVER automatic.
---
### [ ] P3-6 · Configurable Composer Toolbar
**What:** Let users rearrange or hide individual composer toolbar buttons (GIF, Sticker, Emoji, File, Voice, Location). Changes stored in `settingsAtom`. Access via a small "⚙ Customize toolbar" option in toolbar overflow.
**[AUDIT REQUIRED]** — Audit the current toolbar button rendering in `RoomInput.tsx`. Understand the layout system (is it a fixed array or already mapped from config?). Drag-to-reorder may require a DnD library; consider whether reorder is worth the complexity vs just toggle-visibility.
**Spec:** MSC3771 (stable). Depends on Thread Panel (#P3-8).
**What:** Per-thread notification toggle: "All messages" vs "Mentions only". Accessible from the thread panel header. Tracks unread counts separately per thread.
**[AUDIT REQUIRED]** — Implement after Thread Panel. Requires understanding how the SDK tracks per-thread unread counts.
@@ -776,6 +873,7 @@ Features:
---
### [ ] P4-2 · Thread Subscriptions (MSC4306)
**Spec:** MSC4306 (Synapse experimental). Depends on Thread Panel (#P3-8).
**What:** "Follow thread" button to receive notifications for a thread you haven't posted in. Uses MSC4306 subscription endpoint.
**[SERVER CHECK]** — Verify `matrix.lotusguild.org` supports MSC4306. It is Synapse-experimental and may not be enabled.
@@ -784,6 +882,7 @@ Features:
---
### [ ] P4-3 · Knock-to-join Notifications for Admins
**Note:** The basic knock-to-join UX is covered in P1-11. This task adds the admin notification side.
**What:** Space/room admins see a notification badge when there are pending knock requests. A "Pending Join Requests" section in the members drawer or room settings. Approve (invite) or deny (kick) each knock.
**Complexity:** Medium.
@@ -791,6 +890,7 @@ Features:
---
### [ ] P4-4 · Math / LaTeX Rendering in Messages (LOW PRIORITY)
**Spec:** CS-API §11.5 (stable) — `formatted_body` can contain LaTeX.
**What:** Render `$...$` or `$$...$$` LaTeX expressions in message bodies. Use KaTeX (lightweight, ~100KB, renders server-side-compatible CSS). Must gracefully fall back to raw LaTeX text if KaTeX fails.
**Note:** This is LOW PRIORITY — only useful for academic/technical communities. Implement last.
@@ -800,6 +900,7 @@ Features:
---
### [ ] P4-5 · Live Location Sharing (MSC3489 + MSC3672) (LOW PRIORITY, HIGH COMPLEXITY)
**Spec:** MSC3489 + MSC3672. Implemented in Element Web.
**Note:** Static location sharing is already implemented. This adds live/real-time GPS beacons. Very low priority per user preference.
**What:** Start sharing live location → creates `m.beacon_info` state event → client posts `m.beacon` events on a timer → other users see your position update live on a map.
**Context:** ~80% of homeserver users have LLDAP/Authelia/SSO accounts. SSO is currently enabled on `matrix.lotusguild.org` but accounts are not yet linked. This would allow users to log in via their SSO credentials.
**Confirmed bug** — drag a file over the window without dropping: the drop overlay persists.
**Fix:** Ensure `dragleave` fires correctly at the window/document level. Child element boundaries can cause spurious `dragleave` — use a counter or `relatedTarget` check.
**[AUDIT REQUIRED]** Find the drag-and-drop overlay component in `RoomInput.tsx` or the room view. Confirm the exact event listener structure.
**What:** A hex/HSL color picker in Settings → Appearance. Chosen color replaces the primary accent throughout the UI: buttons, badges, active states, highlights, presence dot, links. Applied via a CSS custom property override injected into `<head>`.
**IMPORTANT:** This feature is completely inactive when TDS is enabled — TDS has its own fixed palette. Add this setting under a "Non-TDS Themes" section that is hidden when TDS is active.
**[AUDIT REQUIRED]** Identify all CSS custom properties that constitute the "accent color" in non-TDS mode. Map them to the folds/vanilla-extract token names.
@@ -839,8 +943,10 @@ Features:
---
### [ ] P5-2 · Additional Color Theme Presets
**What:** 5 new one-click theme presets alongside TDS. Each must be a complete, polished system with proper contrast ratios (WCAG AA). All implemented as vanilla-extract themes matching the existing TDS pattern.
Themes:
1.**Cyberpunk** — deep navy bg (`#0a0015`), electric purple (`#bf5fff`) + hot pink (`#ff2d9b`) accents, neon glow
2.**Ocean** — deep sea blue bg (`#020b18`), teal (`#00c9b1`) + aqua (`#0096d6`) accents, soft feel
3.**Blood Red** — near-black bg (`#0d0203`), deep crimson (`#7a0010`) + bright red (`#ff2233`) accents
@@ -852,6 +958,7 @@ Themes:
---
### [ ] P5-3 · Glassmorphism Sidebar Toggle
**What:** Semi-transparent sidebar + panels with `backdrop-filter: blur(12px)`. Toggled in Settings → Appearance. Off by default. Best combined with animated wallpapers.
**[AUDIT REQUIRED]** Check whether `backdrop-filter` works on sidebar elements given the current z-index stack and CSS transforms. Some browsers require `will-change` or specific stacking context to allow blur through.
@@ -872,12 +981,14 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
---
### [ ] P5-5 · Night Light / Blue Light Filter
**What:** Warm orange overlay `rgba(255, 140, 0, 0.12)` on the full UI. `position:fixed; inset:0; pointer-events:none; z-index:9999`. Intensity slider (0–30%) in Settings → Appearance. Optional: auto-activate after a set hour. Stored in `settingsAtom`.
**What:** Render a leading emoji in a room name slightly larger in the sidebar for visual impact (e.g. 🎮 general). Optional: right-click room → "Set channel emoji" shortcut for admins.
**Note:** Matrix room names already support Unicode — this is purely a rendering enhancement.
**[AUDIT REQUIRED]** Confirm upstream Cinny doesn't strip or truncate leading emoji in sidebar room name display. Also confirm emoji in room names works end-to-end on `matrix.lotusguild.org`.
@@ -886,6 +997,7 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
**What:** Slim dark card sliding in from bottom-right: user avatar, display name (orange), truncated message preview, room name (dim), × dismiss. 4-second auto-dismiss. TDS variables only — non-TDS keeps existing behavior.
**[AUDIT REQUIRED]** Find where in-app notification toasts are currently rendered in `src/app/`. May be in `ClientNonUIFeatures.tsx`.
**Complexity:** Medium.
@@ -893,6 +1005,7 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
---
### [ ] P5-8 · Mention Highlight Animation
**What:** Brief pulse/glow animation (0.4–0.6s ease-out) on incoming @mention messages. CSS keyframe: scale 1.0 → 1.005 → 1.0 + background glow pulse. Only fires on new incoming messages, not on page load. Respects `prefers-reduced-motion`.
**[AUDIT REQUIRED]** Find where mentioned messages receive their highlight class in the timeline. Verify animation doesn't affect scroll position.
**Complexity:** Low.
@@ -900,6 +1013,7 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
**What:**`/lfg` generates a formatted LFG post visible on ALL Matrix clients using standard `m.room.message` HTML. Fields: Game, Players Needed, Platform, Skill Level, Description, DM link. Other clients see clean formatted HTML; Lotus Chat renders an enhanced styled card.
**[AUDIT REQUIRED]** Test which HTML tags survive Matrix HTML sanitization on Element/FluffyChat before designing the card structure. Test with minimal HTML.
**Complexity:** Medium.
@@ -907,6 +1021,7 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
---
### [ ] P5-10 · Voice Channel User Limit
**What:** Admins set max participants via custom state event `io.lotus.voice_limit: { max_users: N }`. Show "Channel Full (5/5)" to users over the limit. Local enforcement only.
**[AUDIT REQUIRED]** Check if Element Call has its own participant limit that should be integrated with rather than duplicated.
**Complexity:** Medium.
@@ -914,6 +1029,7 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
---
### [ ] P5-11 · AFK / Idle Auto-Mute in Voice
**What:** Auto-mute mic after X minutes of silence (detected via Web Audio AnalyserNode). Show "You were auto-muted due to inactivity" toast with click-to-unmute. Admin-configurable via `io.lotus.afk_timeout` state event. Disableable in Settings → Calls.
**[AUDIT REQUIRED]** Verify auto-mute must go through the same CallControl bridge as manual mute.
**Complexity:** Medium.
@@ -921,7 +1037,9 @@ All pure CSS animations (keyframes + transforms) — no canvas, GPU-accelerated.
---
### [ ] P5-12 · Seasonal / Event Themes
**What:** Automatic + manually toggleable seasonal overlays with CSS particle effects and accent color variants:
**What:** Animated WebM/GIF overlays that float around avatars (transparent center showing avatar). Curated built-in set OR user-uploaded mxc:// overlay. Stored in account data. Only Lotus Chat users see them.
**[AUDIT REQUIRED]** See #P5-13 audit. Also decide: curated set only vs user-uploadable.
**Complexity:** Medium.
@@ -947,6 +1067,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-15 · In-Call Soundboard
**What:** Grid of short audio clips playable into the call audio stream via Web Audio API (AudioBufferSourceNode → MediaStreamDestinationNode → mixed with mic). Built-in clips + user-uploadable custom clips (stored as mxc://). Accessible from call controls bar.
**[AUDIT REQUIRED]** Verify the Element Call integration exposes the mic MediaStream for mixing. This is the highest-risk part of this feature.
**Complexity:** High.
@@ -954,6 +1075,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-16 · Custom Join / Leave Sound Effects
**What:** Local-only sounds when participants join/leave a call you're in. Built-in options + per-user settable. Detect via Element Call participant list change events.
**[AUDIT REQUIRED]** Find how Element Call exposes join/leave participant events to the parent window via postMessage bridge.
**Complexity:** Medium.
@@ -961,6 +1083,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
**What:** Floating mini-bar of 5 most recent reactions above the hover toolbar. One-click react. 6th button opens full emoji board.
**[AUDIT REQUIRED]** Find the message hover toolbar in `Message.tsx` and confirm how to inject an additional row without breaking layout. Confirm recent emoji tracking mechanism in EmojiBoard.
**Complexity:** Medium.
@@ -968,6 +1091,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-18 · Status-Based Avatar Border Color
**What:** Colored ring on avatars matching presence: green (online), yellow (idle), red (DND), grey (offline). Subtle 2px CSS box-shadow/border. Applied across all avatar sizes.
**[AUDIT REQUIRED]** Check existing `PresenceBadge` component — this extends that concept to the avatar border. Verify folds Avatar allows border/shadow styling.
**Complexity:** Low-Medium.
@@ -975,6 +1099,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-19 · Collapsible Long Messages ('Read more')
**What:** Messages >~20 lines auto-collapsed with "Read more ↓" button. Click to expand inline. Collapse threshold configurable in settings.
**[AUDIT REQUIRED]** Determine whether CSS `max-height` + `overflow:hidden` or a line-count approach is more appropriate for the current message renderer. Check edge cases with code blocks and media embeds.
**Complexity:** Medium.
@@ -982,6 +1107,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-20 · Quick Reply from Browser Notification
**What:** Inline reply field in browser notification toasts via Notification Actions API. Reply sends as threaded reply to the triggering message.
**[AUDIT REQUIRED]** (1) Verify browser Notification Actions API support in target browsers. (2) This requires a Service Worker to handle the reply event — confirm if Lotus Chat has one or needs one.
**Complexity:** Medium-High.
@@ -989,12 +1115,14 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-21 · Custom @Mention Highlight Color
**What:** Each user sets their own mention highlight color in Settings → Appearance. Applied as `--user-mention-color` CSS property override on mention-highlighted message rows.
**Complexity:** Low.
---
### [ ] P5-22 · Font Selector for the UI
**What:** Font picker in Settings → Appearance. Options: JetBrains Mono, Inter, Geist, Fira Code, OpenDyslexic, System Default. Applied via CSS custom property overrides.
**[AUDIT REQUIRED]** Check if any fonts are already globally loaded to avoid double-loading.
**Complexity:** Low-Medium.
@@ -1002,12 +1130,14 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-23 · Message Send Animation
**What:** Own sent messages fade+scale into the timeline (0.15s ease-out: scale 0.97→1.0, opacity 0.4→1.0). Incoming messages unaffected. Respects `prefers-reduced-motion`.
**Complexity:** Low.
---
### [ ] P5-24 · Hotkey Push-to-Deafen
**What:** Configurable hotkey (default Ctrl+Shift+D) to toggle deafen. Shows "DEAFENED" badge in call bar. Configurable in Settings → Calls alongside PTT keybind.
**[AUDIT REQUIRED]** Confirm Element Call widget bridge exposes speaker/audio-output control separately from microphone control.
**Complexity:** Medium.
@@ -1015,12 +1145,14 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
---
### [ ] P5-25 · Message Length Counter in Composer
**What:** Character counter near send button. Hidden <500 chars. Shows at 500+ (neutral), orange at 2000+, red at 3500+. TDS mono font styling.
**Complexity:** Low.
---
### [ ] P5-26 · Right-Click Room Context Menu Improvements
**What:** Consolidated right-click menu: Mute with duration submenu (15min/1hr/8hr/24hr/Indefinite), Copy room link, Mark as read, Leave room, Room settings.
**[AUDIT REQUIRED]** Audit current right-click menu to avoid duplicating existing actions.
**Complexity:** Low-Medium.
@@ -1028,6 +1160,7 @@ All toggleable manually in Settings → Appearance regardless of date. Respects
**What:** Saved presets that change all notification settings atomically. Gaming (mentions only), Work (DMs + mentions), Sleep (all off). Quick-switch from sidebar or settings.
**Complexity:** Medium.
@@ -1039,27 +1172,32 @@ These features are confirmed desirable but cannot be built until the listed depe
Check back after each Synapse upgrade — re-run `/matrix/client/versions` and `unstable_features` to see if they've become available.
### [BLOCKED] · Live Location Sharing (MSC3489 + MSC3672)
**Blocked by:**`org.matrix.msc3489 = false` AND `org.matrix.msc3672 = false` on `matrix.lotusguild.org` (confirmed from unstable_features).
**What it would do:** Real-time GPS beacon streaming upgrading the existing static location share.
**Action when unblocked:** Both MSCs must be enabled on the homeserver before any client work.
Research whether Matrix spec or MSC4133 (v1.16) defines a standard profile banner field. `uk.tcpip.msc4133.stable = true` on our server — check if a `banner_url` or similar field is defined. If no cross-client standard exists, do not implement.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.