Files
cinny/LOTUS_TODO.md
T
jared 2a545b8b3e
CI / Build & Quality Checks (push) Successful in 10m36s
Trigger Desktop Build / trigger (push) Successful in 5s
feat: avatar decorations follow-up — Nextcloud CDN, sync script, docs
- Point DECORATION_CDN at Lotus Nextcloud WebDAV share instead of external
  avatardecoration.com; all 99 APNG files are self-hosted and served via
  direct DAV URL (no CORS issue for <img> elements)
- Add onError handler to AvatarDecoration.tsx to silently hide the overlay
  if a file is missing or the CDN is unreachable
- Rewrite scripts/syncDecorations.mjs: now sends HTTP HEAD requests to the
  live Nextcloud CDN (batches of 16 in parallel) and removes catalog entries
  for files that return non-2xx; empty categories are pruned automatically.
  Workflow: delete files from Nextcloud → run `npm run sync:decorations` →
  commit the updated avatarDecorations.ts. No local files needed.
- Add public/decorations/ to .gitignore; delete the 85 MB local APNG cache
  that was downloaded during development (files live on Nextcloud now)
- Add sync:decorations script to package.json
- Update LOTUS_FEATURES.md, LOTUS_TODO.md (P5-13 + P5-14 ✓), README.md
  with avatar decoration documentation and catalog sync workflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 12:02:50 -04:00

30 KiB
Raw Blame History

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.css CSS 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 on matrix.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.12 formally; newer MSC features via unstable_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-core or 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).

[x] 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.
Complexity: Medium-High (drag reorder adds significant complexity).


[ ] 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 RoomView as a conditional right panel (mirror the members drawer pattern)
  • Filter events in timeline to m.thread relation for the active root event ID
  • Shares the same mx client and room reference as the main timeline
    [AUDIT REQUIRED] — Deeply audit how m.thread relation events are currently stored and retrieved in the matrix-js-sdk. Understand the thread aggregation API: GET /rooms/{roomId}/relations/{eventId}/m.thread. Check if RoomTimeline.tsx currently 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).


[x] P4-3 · Knock-to-join Notifications for Admins

Note: The basic knock-to-join UX is covered in P1-11 (completed). 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.


[ ] 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:

  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
  4. Classic Matrix — pure black bg (#000000), phosphor green (#00ff41) text + accents
  5. Midnight — dark charcoal (#111827), cool blue-grey (#6b7ca8) accents, clean minimal
    [AUDIT REQUIRED] Study src/lotus-terminal.css.ts for 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).


[x] 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.
Done: RoomVoiceLimit admin control in Room Settings → General → Voice; CallPrescreen disables Join + shows "Channel Full (N/N)" when at capacity (rejoiners exempt). State event StateEvent.LotusVoiceLimit. Hard enforcement is server-side for ALL clients via voice-limit-guard (matrix repo livekit/voice-limit-guard.py) — a fail-open sidecar fronting lk-jwt-service (guard :8070, lk-jwt :8071) that refuses the LiveKit JWT (403) when the room is at capacity. The client check is UX-only. EC has only a global max_participants (50), so per-room limits were not duplicating an EC feature.


[x] 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.


[x] P5-12 · Seasonal / Event Themes

What: Automatic + manually toggleable seasonal overlays with CSS particle effects and accent color variants:

  • Halloween (Oct 15Nov 1): purple particles, orange accents, spider web pattern
  • Christmas (Dec 10Jan 2): snow fall, red/green accents, snowflake pattern
  • New Year (Dec 31Jan 1): firework burst animation, gold accents
  • Pride (June): rainbow gradient accent cycle
    All toggleable manually in Settings → Appearance regardless of date. Respects prefers-reduced-motion.
    [AUDIT REQUIRED] Design against existing CSS animation system in lotus-terminal.css.ts.
    Complexity: Medium.

[x] P5-13 · Avatar Frame / Border Decorations

What: Decorative CSS rings/frames rendered around user avatars. Built-in options: TDS Glow (animated orange pulsing), Cyberpunk (rotating gradient), Minimal (thin ring), Gold (supporter cosmetic). Stored in Matrix account data io.lotus.avatar_frame. Only visible in Lotus Chat.
[AUDIT REQUIRED] Verify folds Avatar component allows overlay decoration without breaking child-type constraints (see previous white-circle avatar bug).
Complexity: Medium.


[x] P5-14 · Animated Avatar Overlay Decorations (Discord-style)

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.


[ ] 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.


[x] 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.
Done: Detected via MatrixRTCSession membership changes (useCallMembersChange) rather than the EC postMessage bridge — more reliable, identity tracked by sender|deviceId. Sounds synthesized with Web Audio (no assets). Styles Off/Chime/Soft/Retro in Settings → Calls. Hook useCallJoinLeaveSounds, util callSounds.ts.


[ ] 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.


[x] 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.


[x] 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.


[x] P5-27 · Notification Profile Presets (Gaming / Work / Sleep)

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.


[ ] 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.


[x] P5-34 · User-to-User Private Notes

What: A private "Notes" field on user profiles visible only to you. Syncs across all your devices.
Matrix Tech: Store in io.lotus.user_notes account data. Must be keyed by userId.
Complexity: 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 in web_template/base.css)
  • folds AvatarImage does 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 errors
  • npx eslint src/ — zero new errors (warnings OK if pre-existing)
  • npx prettier --check src/ — formatting passes
  • README.md updated (Lotus-custom features only — not upstream Cinny features)
  • landing/index.html updated if the feature appears in the comparison table
  • Visually tested at chat.lotusguild.org after CI deploys

Homeserver Access (for server audits)

  • Synapse (Matrix): LXC 151 on compute-storage-01pct exec 151 -- bash
  • Config: /etc/matrix-synapse/homeserver.yaml
  • Version check: curl -s https://matrix.lotusguild.org/_matrix/client/versions