# Lotus Chat — Feature Reference Everything added to Lotus Chat beyond upstream Cinny v4.12.1. Last updated: June 2026. --- ## Table of Contents 1. [Branding & Identity](#branding--identity) 2. [LotusGuild Terminal Design System (TDS) v1.2](#lotusguild-terminal-design-system-tds-v12) 3. [Animated Chat Backgrounds (P5-4)](#animated-chat-backgrounds-p5-4) 4. [Seasonal Theme Overlays (P5-12)](#seasonal-theme-overlays-p5-12) 5. [Avatar Decorations (P5-13/P5-14)](#avatar-decorations-p5-13p5-14) 6. [Glassmorphism Sidebar (P5-3)](#glassmorphism-sidebar-p5-3) 7. [Night Light / Blue Light Filter (P5-5)](#night-light--blue-light-filter-p5-5) 8. [Voice / Video Call Improvements](#voice--video-call-improvements) 9. [Per-Message Read Receipts](#per-message-read-receipts) 10. [Delivery Status Indicators](#delivery-status-indicators) 11. [Messaging Enhancements](#messaging-enhancements) 12. [Presence](#presence) 13. [UX & Composer](#ux--composer) 14. [Room Customization](#room-customization) 15. [Moderation](#moderation) 16. [Notifications](#notifications) 17. [Server Integration](#server-integration) 18. [Infrastructure](#infrastructure) 19. [Desktop App Features](#desktop-app-features) 20. [Key Custom Files](#key-custom-files) --- ## Branding & Identity - Package renamed to `lotus-chat`; description updated in `package.json` - App title set to "Lotus Chat" throughout (window title, meta tags, manifest) - Favicon, PWA icons (all sizes), and Apple touch icons replaced with `Lotus.png` - Lotus logo displayed in the About dialog and Auth page - Auth footer: dynamic version pulled from `package.json`; links to `lotusguild.org`, `chat.lotusguild.org`, and `matrix.lotusguild.org` - Welcome page tagline: "A Matrix client for Lotus Guild" - Encryption key export filename changed to `lotus-keys.txt` - `manifest.json` updated with Lotus name, description, and branding colors --- ## LotusGuild Terminal Design System (TDS) v1.2 ### Dark Mode — `LotusTerminalTheme` A CRT terminal aesthetic applied globally when the TDS theme is active. **Visual effects:** - Scanline overlay via repeating `linear-gradient` pseudo-element - Vignette via radial-gradient overlay - Phosphor glow on text and accents via `text-shadow` / `box-shadow` **Color palette:** | Token | Value | Role | |---|---|---| | `--lt-bg` | `#030508` | Page/panel background | | `--lt-accent-orange` | `#FF6B00` | Primary accent | | `--lt-accent-cyan` | `#00D4FF` | Secondary accent | | `--lt-accent-green` | `#00FF88` | Success / active states | | `--lt-text` | `#c4d9ee` | Body text | **Typography & chrome:** - Monospace font stack applied to all UI elements - Terminal-style scrollbars (thin, accent-colored track) **Decorative patterns:** - Custom hex-grid CSS background pattern - Circuit-board CSS background pattern (switchable) **Boot sequence:** - Matrix-style boot messages on the welcome page; press Escape to skip - Implemented in `src/lotus-boot.ts` **CSS variable family:** all custom tokens use the `--lt-*` prefix, defined in `src/lotus-terminal.css.ts`. ### Light Mode — `LotusTerminalLightTheme` A full light-palette counterpart to the dark TDS theme. **Color palette:** | Token | Light Value | Role | |---|---|---| | `--lt-bg` | `#edf0f5` | Page/panel background | | `--lt-accent-orange` | `#c44e00` | Primary accent | | `--lt-accent-cyan` | `#0062b8` | Secondary accent | | `--lt-accent-green` | `#006d35` | Success / active states | | `--lt-text` | `#111827` | Body text | **Differences from dark mode:** - CRT effects (scanlines, vignette, phosphor glow) are disabled - Scoped to `html[data-theme="light"] body.lotusTerminalBodyClass` to avoid bleed into non-TDS themes - `ThemeManager.tsx` is responsible for setting the `data-theme` attribute on the `` element when theme changes ### Chat Background Patterns (20+ static) A library of CSS-only background patterns for the chat area, all using CSS custom properties so they adapt automatically to both TDS dark and light palettes: - Blueprint grid - Carbon fiber - Starfield - Topographic contours - Herringbone - Crosshatch - Chevron - Polka dots - Triangles - Plaid - (and additional variants) --- ## Animated Chat Backgrounds (P5-4) Five CSS-only animated wallpapers implemented with vanilla-extract keyframes. No `` element is used — all animation is pure CSS. ### Available Animations **Digital Rain** Two-layer vertical stripe scroll with parallax effect. Wide stripes animate at 8s, narrow stripes at 4s, creating depth. **Star Drift** Three-layer radial-gradient dot field drifting diagonally across the viewport. Each layer moves at a distinct speed and angle. **Grid Pulse** Neon grid lines that expand and contract via a `backgroundSize` keyframe. Grid color follows `--lt-accent-cyan` in dark mode. **Aurora Flow** Four radial-gradient ellipses sweeping across a 200% canvas. Colors use the TDS green/cyan/orange palette and blend softly. **Fireflies** Three layers of warm glowing dots that drift slowly. Dot color follows `--lt-accent-orange` for a warm bioluminescent feel. ### API ```ts getChatBg(bg: ChatBg, isDark: boolean, pauseAnimations?: boolean): CSSProperties ``` Strips all `animation` properties from the returned style object when either `pauseAnimations` is `true` or the `prefers-reduced-motion: reduce` media query is active. ### Settings Integration A "Pause Background Animations" toggle is exposed in **Settings → Appearance**. The preference is persisted and read by `getChatBg()` at render time. ### Animation Improvements (June 2026) All five animated backgrounds were rewritten for smoother, more organic motion: - **Digital Rain** — added a phosphor glow flicker (`animRainGlowKeyframe`, 2.1 s) layered on top of the column scroll; stripe opacity increased for better visibility - **Star Drift** — each of the three dot layers now moves by exactly its own tile width/height per cycle (`−130 px`, `−190 px`, `−260 px`), eliminating the visible seam on loop - **Grid Pulse** — independent brightness oscillation (`animGridBrightnessKeyframe`, 3.3 s) runs alongside the size breathe (4 s) at a prime period ratio so they never synchronise - **Aurora Flow** — four gradient layers now have individual `backgroundSize` values (`200%`, `250%`, `300%`, `220%`); the keyframe drives each layer through a distinct 5-stop path, replacing the robotic single back-and-forth - **Fireflies** — glow pulse (`animFirefliesGlowKeyframe`, 2.3 s `filter: brightness`) and opacity blink (`animFirefliesBlinkKeyframe`, 1.7 s) added on top of the position drift; prime periods create unsynchronised bioluminescence ### Files - `src/app/styles/Animations.css.ts` — vanilla-extract keyframe definitions - `src/app/features/lotus/chatBackground.ts` — `getChatBg()` implementation and pattern registry --- ## Seasonal Theme Overlays (P5-12) Decorative CSS-only overlays that activate automatically on holidays and events. Manually overrideable in **Settings → Appearance → Seasonal Theme**. ### Themes | Theme | Window | Effect | | -------------------- | ------------- | -------------------------------------------------------------------------------------------------- | | 🎆 New Year | Dec 31–Jan 2 | Radial firework bursts in gold, red, cyan, purple; gold shimmer sweep | | 🏮 Lunar New Year | Jan 22–Feb 5 | Floating paper lanterns bobbing; silk texture; gold shimmer accent | | 💖 Valentine's Day | Feb 10–15 | ♥ hearts floating upward; soft pink ambient glow | | 🍀 St. Patrick's Day | Mar 15–18 | ☘ clovers drifting down; gold metallic shimmer top border | | 🃏 April Fool's | Apr 1 | Glitch overlay: RGB channel separation, hue-rotate spikes, scanline sweep, "SIGNAL LOST" watermark | | 🌱 Earth Day | Apr 20–23 | 🌿🍃 leaf emoji drift; sage green ambient tint; vine accent on left edge | | 🍂 Autumn | Sep 21–Oct 31 | Warm orange/amber leaf shapes rotating and falling | | 👾 Arcade Day | Sep 12 | CRT scanlines; blinking pixel corner decorations; "INSERT COIN" prompt | | 🚀 Deep Space Week | Oct 4–10 | Warp-speed star streaks radiating from screen centre; nebula purple/blue ambient | | 🎃 Halloween | Oct 15–Nov 1 | Purple and orange glowing particles; SVG spider web in top-left corner; dark purple tint | | ❄️ Christmas | Dec 10–Jan 2 | White dot snowfall in multiple layers at varied speeds | ### Implementation - `SeasonalEffect` component mounted in `App.tsx` at `z-index: 9997` (below night light, above content) - Auto-detection via `getActiveSeason(now: Date)` — themes checked in priority order (New Year > Valentine's > … > Autumn) - `seasonalThemeOverride` setting: `'auto' | 'off' | ` — persisted in `settingsAtom` - All particle animations gated on `prefers-reduced-motion: reduce` — ambient overlays (tints, textures, shimmer) remain active ### Files - `src/app/components/seasonal/SeasonalEffect.tsx` — theme detection, date ranges, all overlay components - `src/app/components/seasonal/Seasonal.css.ts` — vanilla-extract keyframes (fall, leaf, float-up, bob, glitch, burst, warp, scanline, shimmer, etc.) --- ## Avatar Decorations (P5-13/P5-14) Animated APNG overlay frames that float around user avatars, inspired by Discord's Avatar Decorations feature. Each decoration extends 8px beyond the avatar border on all sides, with a transparent center hole that reveals the avatar beneath. Other Lotus Chat users see your selected decoration in real time — stored in the Matrix profile via MSC4133. ### Decoration Library 99 hand-curated, original-IP decorations (no licensed character artwork) organized into 9 categories: | Category | Count | Highlights | | -------- | ----- | ------------------------------------------------------------- | | Gaming | 13 | Slither 'n Snack, Joystick, Space Invaders, Gaming Headsets | | Cyber | 9 | Cybernetic, Glitch, Digital Sunrise, Futuristic UI (3 colors) | | Space | 8 | Black Hole, Constellations, Solar Orbit, Aurora | | Fantasy | 22 | Kitsune, Phoenix, Glowing Runes, D&D dice, Crystal Balls | | Elements | 7 | Fire, Water, Air, Earth, Lightning, Ki Energy | | Japanese | 6 | Kabuto, Oni Mask, Sakura Warrior, Straw Hat | | Nature | 12 | **Lotus Flower**, Koi Pond, Sakura, Fall Leaves, Fireflies | | Spooky | 13 | Candlelight, Witch Hat, Ghosts, Jack-o'-Lantern | | Cozy | 11 | Cozy Cat, Fox Hat (3 colors), Cat Ears, Frog Hat | All decoration files are 256×256 APNGs. They animate natively in all modern browsers via `` elements. ### Architecture **Profile storage — MSC4133:** Decoration preference is stored in the public Matrix profile field `io.lotus.avatar_decoration` (a slug string, e.g. `lotus_flower`). Any Lotus Chat user viewing your profile sees your current decoration. **CDN:** Files are self-hosted on the Lotus Nextcloud instance. Direct access: `https://drive.lotusguild.org/public.php/dav/files/{token}/cinny-decorations/{slug}.png`. `` elements load cross-origin freely — no CORS headers needed. **Module-level cache with in-flight deduplication:** `useAvatarDecoration(userId)` fetches the profile field once per user per session. A `Map` cache prevents redundant requests; a second `pending` waiters map ensures multiple components requesting the same userId simultaneously share one HTTP request rather than firing duplicates. **Wrapping pattern:** `AvatarDecoration` renders a `position: relative; display: inline-flex` wrapper div. The decoration `` is `position: absolute` with `top/left/right/bottom: -8px`, extending equally on all sides while the `z-index: 10` keeps it above the avatar. `onError` hides the image if the CDN file is absent. This wrapper sits outside `PresenceRingAvatar` so the presence ring and decoration layer are fully independent. ### Placement — Where Decorations Render | Location | File | | ----------------------- | -------------------------------------------------------------------- | | Message timeline | `src/app/features/room/message/Message.tsx` | | Members drawer | `src/app/features/room/MembersDrawer.tsx` | | `@mention` autocomplete | `src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx` | | Inbox / notifications | `src/app/pages/client/inbox/Notifications.tsx` | ### Settings — Decoration Picker **Settings → Account → Avatar Decoration** shows a scrollable grid of all decorations, grouped by category. Each cell is a 52×52px button with a live preview of the APNG. The currently selected decoration gets a 2px cyan border. "No Decoration" clears the field. Changes are saved only when the "Save" button is clicked (visible only when a change is pending). After save, `invalidateDecorationCache(userId)` forces other components to re-fetch. ### Catalog Sync Script After deleting decoration files from the Nextcloud share, run: ```bash npm run sync:decorations ``` The script (`scripts/syncDecorations.mjs`) sends HTTP HEAD requests to the CDN URL for every slug in `avatarDecorations.ts` and automatically removes entries for files that returned 404. Empty categories are pruned automatically. Review with `git diff`. ### Files - `src/app/features/lotus/avatarDecorations.ts` — full catalog (`DECORATION_CATEGORIES`, `ALL_DECORATIONS`, `decorationUrl()`, `DECORATION_CDN`) - `src/app/hooks/useAvatarDecoration.ts` — profile fetch, module-level cache, `invalidateDecorationCache()` - `src/app/components/avatar-decoration/AvatarDecoration.tsx` — wrapper component with APNG overlay - `src/app/features/settings/account/ProfileDecoration.tsx` — settings UI (picker grid, save button) - `scripts/syncDecorations.mjs` — CDN sync script to prune deleted decorations from the catalog --- ## Glassmorphism Sidebar (P5-3) An optional frosted-glass sidebar style toggled in **Settings → Appearance**. **Implementation:** - `SidebarGlass` vanilla-extract class applies `background: rgba(3, 5, 8, 0.55)` and `backdropFilter: blur(12px)` to the sidebar element - `SidebarNav.tsx` uses a `useEffect` to mirror the active chat background onto `document.body` when the glassmorphism setting is enabled, so the blur filter has meaningful content to work through - Degrades gracefully on browsers without `backdrop-filter` support (falls back to the semi-transparent background) --- ## Night Light / Blue Light Filter (P5-5) A warm orange overlay rendered over the entire UI to reduce blue light emission. **Implementation:** - `NightLightOverlay` component mounted directly in `App.tsx` - CSS: `position: fixed; inset: 0; pointer-events: none; z-index: 9998` - Orange tint color with configurable opacity - **Controls:** Toggle to enable/disable + intensity slider ranging from 5% to 80% opacity - Settings persisted via the standard Lotus settings store --- ## Font Selector (P5-22) Users can choose the UI font in **Settings → Appearance**: - **System Default** — `system-ui, -apple-system, sans-serif` - **Inter** — `'InterVariable', sans-serif` (current default) - **JetBrains Mono** — `'JetBrains Mono', monospace` (already loaded from Google Fonts) - **Fira Code** — `'Fira Code', monospace` (added to Google Fonts preload in `index.html`) Applied by overriding `--font-secondary` on `document.body` via `AppearanceEffects` in `App.tsx`. The TDS terminal mode font stack is unaffected. --- ## Custom @Mention Highlight Color (P5-21) Users can set a custom background color for `@mention` chips that highlight their own name, in **Settings → Appearance**. - Color picker (native ``) with a **Reset** button to revert to the theme default - Text color (black/white) auto-computed from the chosen background's luminance for readability - Applied via CSS custom properties `--mention-highlight-bg`, `--mention-highlight-text`, `--mention-highlight-border` set on `document.body` - `CustomHtml.css.ts` uses these as CSS `var()` fallbacks over the original folds `Success` token colors --- ## Voice / Video Call Improvements > 🔱 **[EC-FORK] LIVE (2026-06).** Element Call is now our **self-built fork** > (`@lotusguild/element-call-embedded@0.20.1-lotus.1`, source at > `LotusGuild/element-call`), served same-origin — no longer the upstream > pre-built npm bundle. Several in-call behaviors below are now first-class > source changes rather than DOM/widget hacks. Background, plan, and the Phase-2 > work list are in > [`HANDOFF_ELEMENT_CALL_FORK.md`](./HANDOFF_ELEMENT_CALL_FORK.md). ### Element Call — Self-Built Fork (`0.20.1-lotus.1`) The embedded widget was upgraded **0.16.3 → 0.19.4 → 0.20.1**, then **forked**. We self-build `LotusGuild/element-call` and publish it to our private Gitea npm registry as `@lotusguild/element-call-embedded`; cinny consumes that instead of `@element-hq/element-call-embedded`. The iframe prints `Element Call embedded-v0.20.1-lotus.1` in its console (vs. `embedded-v0.20.1` upstream) — the quickest way to confirm a deploy landed the fork. All custom behavior lives in the fork's `src/lotus/` modules and is **additive and dormant by default**, gated by URL flags / widget actions the host opts into, so a stock EC config is byte-for-byte upstream behavior. **Active (cinny drives them today):** | # | Feature | Mechanism | Replaces (old hack) | | --- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | A7 | **Denoise in-source** | ML noise suppression runs inside EC as a LiveKit `TrackProcessor