- New Year: replace flashing animBurst rays with gentle falling confetti - Lunar New Year: reduce 9 lanterns to 4, halve sizes, dim silk/shimmer - April Fools: remove all glitch/scanline/watermark effects; replace with a subtle rainbow stripe and falling punctuation symbols - Add SeasonalPreview export (position:absolute, reduced-motion) for use inside contained card elements - Replace SettingsSelect dropdown for Seasonal Theme with SeasonalBgGrid, a visual card grid (matches ChatBgGrid pattern) showing ambient previews Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
26 KiB
Lotus Chat — Work Backlog
Repo: lotus branch at https://code.lotusguild.org/LotusGuild/cinny
Deploy: push to lotus → CI → auto-deploy to chat.lotusguild.org (~11 min)
⚠️ TDS DESIGN LAW — READ BEFORE TOUCHING ANY UI
ALL Lotus Terminal Design System (TDS) styling — colors, animations, glows, borders, fonts, spacing — MUST come exclusively from
/root/code/web_template/base.cssCSS variables. Do NOT hardcode hex values. Do NOT invent new variable names. Do NOT deviate from the design tokens defined in that file. The canonical variable reference:--lt-accent-orange,--lt-accent-cyan,--lt-accent-green,--lt-glow-orange,--lt-box-glow-*,--lt-border-color, etc. Reference implementation for code patterns:/root/code/tinker_tickets/(markdown.js, base.js, ticket.css) This rule applies to EVERY task in this file without exception.
Completed features are documented in LOTUS_FEATURES.md.
Legend:
[AUDIT REQUIRED]— at least one assumption needs code/server verification before implementing[SERVER CHECK]— depends on a Synapse feature or MSC; verify onmatrix.lotusguild.org[LOW PRIORITY]— implement after all higher-priority items[EXTREME COMPLEXITY]— multi-sprint, plan separately before touching[BLOCKED]— cannot build until a server upgrade, upstream MSC, or dependency resolves[IMPROVE]— feature exists in upstream Cinny; this task enhances it for Lotus Chat
Status: [ ] pending · [~] in progress · [x] completed
Server Capabilities (as of June 2026)
- Homeserver:
matrix.lotusguild.org - Synapse version:
1.153.0(2026-05-19) — fully up to date - Matrix spec: up to
v1.12formally; newer MSC features viaunstable_features
Confirmed facts
| Finding | Impact |
|---|---|
MSC flags ON: msc4140 · msc3771 · msc3440.stable · msc4133.stable · simplified_msc3575 |
All safe to use now |
MSC flags OFF: msc4306 (thread subscriptions) · msc3882 · msc3912 · msc4155 |
These features are BLOCKED |
| MSC3266 room summary: returns 404 | Room Preview feature BLOCKED |
| MSC3892 relation redaction: not in flags | Reaction Redaction feature BLOCKED |
| MSC4260 report user: server at v1.12, endpoint may not exist | Report User feature BLOCKED |
| MSC4151 report room: HTTP 405 on GET = endpoint exists (POST only) | Report Room live ✅ |
folds AvatarImage does NOT accept children |
Add frame/overlay inside UserAvatar.tsx itself — optional frameName prop |
| No in-app toast system exists (was) | Built ToastProvider + Jotai queue; at App.tsx:65 |
useUnverifiedDeviceCount() hook exists |
src/app/hooks/useDeviceVerificationStatus.ts:65-106 |
Voice player: AudioContent.tsx:44-223 |
Playback rate on hidden <audio> at line 217 |
CallControl.setMicrophone(bool) at CallControl.ts:206-212 |
For AFK auto-mute |
CallControl.toggleSound() at CallControl.ts:230-251 |
Push-to-deafen — just wire a hotkey to this |
| matrix-js-sdk has NO arbitrary profile field methods | Use mx.http.authedRequest() for MSC4133 |
Sanitizer (sanitize.ts) allows table, div, span, a, code, hr |
LFG HTML card is safe locally; test on Element/FluffyChat |
Sanitizer STRIPS <math>/MathML tags |
Math/LaTeX task must also modify sanitizer |
Service worker EXISTS at src/sw.ts |
Quick-reply task: add notificationclick handler |
knockSupported() utility exists at matrix.ts:376-391 |
Knock UX: only need "Request to Join" in RoomIntro.tsx |
KeywordMessages.tsx already has custom keyword push rules |
Full push rule editor: only non-keyword rule types need new UI |
getMatrixToRoom() in matrix-to.ts generates invite URLs |
Invite link: just add QR code to room settings |
| Cindy CANNOT inject audio into EC call stream | In-call soundboard must be redesigned as local-only |
| Folds uses vanilla-extract in non-TDS, NOT CSS custom properties | Custom accent color: must create new vanilla-extract theme variant dynamically |
| Theme presets need ~50 CSS custom properties each | Significant design work before coding |
useCallSpeakers.ts CSS MutationObserver polling |
Visual speaking indicator: TDS ring animation on top of existing data |
| MSC3489/3672 live location: BOTH false on server | Live Location BLOCKED |
Key File Reference
| What you need | File | Lines |
|---|---|---|
| Global keydown hook | src/app/hooks/useKeyDown.ts |
whole file |
| Room navigation | src/app/hooks/useRoomNavigate.ts |
19-72 |
| All room IDs atom | src/app/state/room-list/roomList.ts |
allRoomsAtom |
| Room unread counts | src/app/state/room/roomToUnread.ts |
roomToUnreadAtom |
| Overlay portal provider | src/app/pages/App.tsx |
65 |
| Portal container div | index.html |
101 |
| Room settings tabs | src/app/features/room-settings/RoomSettings.tsx |
27-56 |
| State event read/write pattern | src/app/features/common-settings/general/RoomEncryption.tsx |
42-52 |
| Power level checker | src/app/hooks/usePowerLevels.ts |
whole file |
| Slash command registration | src/app/hooks/useCommands.ts |
140-537 |
| Chat background picker | src/app/features/settings/general/General.tsx |
945-981 |
| Chat backgrounds definition | src/app/features/lotus/chatBackground.ts |
whole file |
| Matrix.to URL builder | src/app/plugins/matrix-to.ts |
getMatrixToRoom() |
| Media event content types | src/app/types/matrix/common.ts |
46-91 |
| Media URL conversion | src/app/utils/matrix.ts |
mxcUrlToHttp() |
| Message pagination (search) | src/app/features/message-search/useMessageSearch.ts |
74-121 |
| Infinite pagination pattern | src/app/features/message-search/MessageSearch.tsx |
234-365 |
| Poll event format | src/app/components/message/content/PollContent.tsx |
1-320 |
| Theme class application | src/app/hooks/useTheme.ts |
25-60 |
| Animations file | src/app/styles/Animations.css.ts |
whole file |
| Message status (EventStatus) | src/app/features/room/message/Message.tsx |
84-142 |
| Call member change events | src/app/hooks/useCall.ts |
37-52 |
| Mic control in calls | src/app/plugins/call/CallControl.ts |
206-212 |
| Device verification hook | src/app/hooks/useDeviceVerificationStatus.ts |
65-106 |
| Knock room support check | src/app/utils/matrix.ts |
376-391 |
| Room join button location | src/app/components/room-intro/RoomIntro.tsx |
25-119 |
| Notification mute via push rules | src/app/hooks/useRoomsNotificationPreferences.ts |
110-150 |
| Message text body CSS | src/app/components/message/layout/layout.css.ts |
182-205 |
Priority 3 — Higher complexity / lower daily frequency
[ ] P3-4 · Accessibility Improvements (WCAG 2.1 AA)
What: Comprehensive audit and fix pass targeting the critical user paths:
- Room list navigation (keyboard-only)
- Reading messages in the timeline (screen reader announces new messages)
- Composing and sending a reply
- Opening and closing modals (focus trap, return focus)
- ARIA labels on all icon-only buttons
Scope: Do NOT attempt to make every corner of the app AA-compliant in one pass — focus on the golden path (open app → find room → read → reply → send).
[AUDIT REQUIRED] — Run an automated audit first:npx axe-coreor browser DevTools accessibility tree. Document every violation before writing a single line of code. Prioritize by severity (critical > serious > moderate).
Complexity: Medium-High (audit is the main work).
[ ] P3-8 · Thread Panel (full side drawer)
⚠️ LARGEST FEATURE — requires its own planning session before implementation.
What: A right-side drawer for threaded conversations. Currently "Reply in Thread" exists but there is no panel to read or write thread replies.
Features:
- Click "Reply in Thread" → opens thread drawer on the right
- Thread root event shown at the top of the panel
- Full message rendering for all in-thread replies (reuse timeline components)
- Reply input at the bottom (full composer with formatting, emoji, etc.)
- Unread count badge on the thread button in the main timeline
- Keyboard shortcut to close thread panel
Architecture: - New Jotai atom:
activeThreadEventId: string | null - New component:
src/app/features/room/thread/ThreadPanel.tsx - Rendered alongside
RoomViewas a conditional right panel (mirror the members drawer pattern) - Filter events in timeline to
m.threadrelation for the active root event ID - Shares the same
mxclient and room reference as the main timeline
[AUDIT REQUIRED] — Deeply audit howm.threadrelation events are currently stored and retrieved in the matrix-js-sdk. Understand the thread aggregation API:GET /rooms/{roomId}/relations/{eventId}/m.thread. Check ifRoomTimeline.tsxcurrently filters out thread replies from the main timeline (it should — confirm).
Complexity: High.
Priority 4 — Specialized, high complexity, or low priority
[ ] P4-1 · Thread Notification Mode Per-Thread (MSC3771)
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.
Complexity: Medium (after thread panel exists).
[ ] P4-2 · Thread Subscriptions (MSC4306) [BLOCKED]
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] — org.matrix.msc4306 = false on matrix.lotusguild.org — BLOCKED until server enables it.
Complexity: Medium (after thread panel exists).
[ ] 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.
[AUDIT REQUIRED] — Confirm KaTeX bundle size impact on the Vite bundle. Check if matrix-js-sdk's HTML sanitizer strips LaTeX before it reaches the renderer. The formatted_body sanitization pipeline is the main risk here.
Complexity: Low-Medium.
[ ] P4-5 · Live Location Sharing (MSC3489 + MSC3672) (LOW PRIORITY, HIGH COMPLEXITY) [BLOCKED]
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.
[SERVER CHECK] — org.matrix.msc3489 = false AND org.matrix.msc3672 = false on matrix.lotusguild.org — BLOCKED.
Complexity: High. Requires background geolocation API + live map rendering.
[ ] P4-6 · OIDC / SSO Next-Gen Auth (MSC3861) (EXTREME COMPLEXITY, LOW PRIORITY)
Spec: MSC3861, merged Matrix spec v1.15. Uses Matrix Authentication Service (MAS).
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.
What: OAuth 2.0 / OIDC login flow, token refresh, account management page linking Matrix identity to SSO identity.
EXTREME COMPLEXITY — requires: MAS deployment/configuration on the homeserver, significant auth flow changes in the client, token refresh handling, session management overhaul.
[SERVER CHECK] — Before any client work, audit whether MAS is already deployed on compute-storage-01. Check: pct exec 151 -- systemctl status matrix-authentication-service or similar.
Complexity: Extreme. Multi-sprint project. Plan separately.
Priority 5 — Gamer / Aesthetic / Customization
[ ] P5-1 · Custom Accent Color Picker (non-TDS mode only)
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.
Complexity: Medium.
[ ] 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:
- Cyberpunk — deep navy bg (
#0a0015), electric purple (#bf5fff) + hot pink (#ff2d9b) accents, neon glow - Ocean — deep sea blue bg (
#020b18), teal (#00c9b1) + aqua (#0096d6) accents, soft feel - Blood Red — near-black bg (
#0d0203), deep crimson (#7a0010) + bright red (#ff2233) accents - Classic Matrix — pure black bg (
#000000), phosphor green (#00ff41) text + accents - Midnight — dark charcoal (
#111827), cool blue-grey (#6b7ca8) accents, clean minimal
[AUDIT REQUIRED] Studysrc/lotus-terminal.css.tsfor the full token list before designing themes. All tokens must be covered.
Complexity: Medium (design effort is the main cost).
[MOVED] P5-9 · LFG (Looking for Group) Command → LotusBot
Decision: Implemented as !lfg in LotusBot rather than a client slash command. Bot-side rendering works consistently across all Matrix clients; client-side enhanced cards would only be visible to Lotus Chat users and require sanitizer auditing. The bot can also support richer flows (list active LFGs, DM interested players, auto-expire posts).
[ ] 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.
[ ] 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.
[ ] P5-30 · Advanced ML Noise Suppression (Krisp-style)
What: High-end background noise cancellation using a pre-trained ML model (e.g. RNNoise) running in the browser. Removes dogs, fans, and keyboard clicks from the mic stream.
Note: This is a top-tier feature request and an EXTREME COMPLEXITY project.
[AUDIT REQUIRED] Must verify if mixing a processed stream into Element Call's WebRTC implementation causes latency or AEC (Echo Cancellation) issues.
Complexity: Extreme.
[ ] P5-31 · Granular Voice & Screenshare Quality Controls (Discord-style)
What: Let users (or room admins via room settings) adjust audio bitrates (e.g., 64kbps to 512kbps) and screenshare quality (resolution: 720p/1080p/Source, framerate: 15/30/60fps).
Note: Requires tight integration with the LiveKit SFU and custom state events for per-room quality caps.
[AUDIT REQUIRED] Must verify if current lk-jwt-service can be extended with custom bitrate/resolution claims or if a new sidecar (similar to voice-limit-guard) is needed for server-side enforcement.
Complexity: Extreme.
[ ] P5-35 · Desktop — Notification Click Opens Room (DEFERRED)
What: Clicking a system tray notification navigates to the relevant room. Quick-reply from the notification toast would send the reply without opening the window.
Status: Deferred — tauri-plugin-notification has no Rust click/action callback API. Quick-reply would need a custom WinRT toast activator + COM registration, which can't be compile-tested without a Windows build environment.
Note: Tray icon and matrix: deep links already bring the window forward on most interactions. Revisit when tauri-plugin-notification gains click handler support upstream.
Complexity: High (platform-specific native code required).
[ ] P5-36 · Desktop — Windows Jump List (DEFERRED)
What: Right-clicking the taskbar icon shows a jump list with recent/favorite rooms for quick navigation.
Status: Deferred — implementing the Windows COM jump list API in Tauri requires iterating on C++/COM code that can only be compile-checked on Windows, making blind CI iteration impractical.
Action when unblocked: Revisit when a Tauri plugin abstracts the Windows Shell ICustomDestinationList interface, or when a Windows build environment is available for local iteration.
Complexity: High (Windows-only native COM).
[ ] P5-40 · Desktop — Proactive Update Notifications (Tauri)
What: Automatically check for app updates on launch and periodically during long sessions. If an update is available, show an in-app toast or badge (e.g. on the Settings icon) to alert the user without requiring them to manual check in settings.
Mechanism: Use the useTauriUpdater hook in a global component like ClientNonUIFeatures.tsx.
Note: Ensure the check is throttled (e.g. once every 12 hours) to avoid redundant Tauri commands.
Complexity: Low-Medium.
Blocked Features
These features are confirmed desirable but cannot be built until the listed dependency is resolved.
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.
[BLOCKED] · Reaction / Relation Redaction (MSC3892)
Blocked by: org.matrix.msc3892 = false on matrix.lotusguild.org
What it would do: Cleanly remove a reaction without redacting the parent message.
Current behavior: Full event redaction — acceptable fallback, no user-facing issue.
Action when unblocked: Find onReactionToggle redaction call site; swap in MSC3892 endpoint with fallback.
[BLOCKED] · Room Preview Before Joining (MSC3266)
Blocked by: GET /v1/rooms/{id}/summary returns 404 — endpoint not available on this server
What it would do: Show room name, topic, avatar, member count before joining.
Action when unblocked: Build pre-join preview card; trigger on unjoined room navigation.
[BLOCKED] · Thread Subscriptions (MSC4306)
Blocked by: org.matrix.msc4306 = false on matrix.lotusguild.org
What it would do: Follow a thread without posting; get notifications for replies.
Action when unblocked: Add "Follow thread" button in the thread panel header (depends on #P3-8 Thread Panel).
[BLOCKED] · Report User (MSC4260)
Blocked by: Server declares only spec v1.12; MSC4260 merged in v1.14 — endpoint may not exist
What it would do: Report a specific user to homeserver admins (separate from reporting a message).
Note: Report Message already exists in upstream Cinny. This would add Report User to the profile panel.
Action when unblocked: Test POST /_matrix/client/v3/users/{userId}/report; if 200, add button to user profile.
Pending Audits
[ ] Audit-3 · Profile banner image — Matrix protocol support
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.
Implementation Notes
⚠️ TDS DESIGN LAW (repeated here for emphasis)
Every TDS color, animation, glow, border, shadow, and font value MUST come from
/root/code/web_template/base.css.
Never hardcode hex values. Never invent CSS variable names.
Key variables:--lt-accent-orange·--lt-accent-cyan·--lt-accent-green·--lt-glow-*·--lt-box-glow-*·--lt-border-color·--lt-font-mono
Reference implementation:/root/code/tinker_tickets/(markdown.js, base.js, ticket.css)
This applies without exception to every task marked[IMPROVE],[Build], or any UI change.
Design Rules
- All new components must respect both TDS dark (
LotusTerminalTheme) and TDS light (LotusTerminalLightTheme) modes - Non-TDS theme work (custom accent color, theme presets) uses vanilla-extract theme files — match the pattern in
src/lotus-terminal.css.ts - Code syntax highlighting token classes:
.tok-kw .tok-str .tok-num .tok-cmt .tok-fn(defined inweb_template/base.css) folds AvatarImagedoes NOT accept children — wrap Avatar components externally for overlays/frames/borders
CI/CD Pipeline
edit → commit → git push origin lotus
→ Gitea Actions: tsc --noEmit, eslint, prettier (~3 min)
→ Webhook: lotus_deploy.sh on LXC 106 polls CI, then npm ci && npm run build → rsync
→ Live at chat.lotusguild.org (~11 min total)
Per-Feature Checklist (before marking complete)
npx tsc --noEmit— zero TypeScript errorsnpx eslint src/— zero new errors (warnings OK if pre-existing)npx prettier --check src/— formatting passesREADME.mdupdated (Lotus-custom features only — not upstream Cinny features)landing/index.htmlupdated if the feature appears in the comparison table- Visually tested at
chat.lotusguild.orgafter CI deploys
Homeserver Access (for server audits)
- Synapse (Matrix): LXC 151 on
compute-storage-01—pct exec 151 -- bash - Config:
/etc/matrix-synapse/homeserver.yaml - Version check:
curl -s https://matrix.lotusguild.org/_matrix/client/versions