- Chat input @ autocomplete: typing @ shows online users (room users +
online friends + room aliases) with avatars; arrows/Tab/Enter to pick.
- Any valid @nick token is highlighted blue in chat bubbles (like @all),
giving visual feedback that it is a recognised mention.
- Side notification toast on a received mention: sender avatar (from the
new senderFigure wire field) + message + dismiss; dismiss marks it read
so the toolbar unread badge updates. Auto-hides after 8s.
- IMentionEntry/parsers carry senderFigure end to end.
On catalog open, re-fetch the custom furnidata chunk (custom/imported.json5) via
SessionDataManager.mergeFurnitureDataFromUrl() and feed the new entries to
RoomContentLoader.processFurnitureData(), so furniture imported from the admin
panel appears without a full client reload.
setTab updated currentTabCode/currentFilter but never reset isCreatorOpen, so after opening the room creator, clicking another navigator tab changed the active tab code while the creator view stayed rendered (NavigatorView renders the search and creator views mutually exclusively based on isCreatorOpen). This left users stuck in the creator unable to switch tabs. Reset isCreatorOpen to false in setTab so selecting any tab also closes the creator.
The slice/rim/divider/hub colors are now read from --wheel-* CSS variables
with the current values as fallbacks, so the stock look is unchanged while a
runtime theme can recolor the wheel without rebuilding.
Runtime-loaded visual re-skin system (no client rebuild, real themes never
hit git). A theme = a folder on the server (theme.base.url) with a manifest +
CSS "pieces"; each piece is toggled from Settings > Themes (checkboxes). A
broken/404 piece auto-falls back to the default (per piece). Hotel-wide default
via ui-config theme.default (+ theme.default.pieces), per-user override in
localStorage (same pattern as the catalog style toggle).
- api/theme/ThemeManager: fetch index/manifest + inject/remove <link> + fallback
- hooks/theme/useThemes: state + persist + default-from-config + live apply
- components/theme/ThemeApplier: applies on boot (mounted in MainView)
- UserSettings: General/Themes tabs with theme selector + per-piece checkboxes
- custom-themes/: reference template (demo theme "Neon Viola" + README)
- .gitignore: public/custom-themes/ (real themes are never committed)
Player experience:
- Tiered win celebration overlay (WheelWinReveal): quiet message for the
"nothing" slice, lighter reveal for common prizes, full confetti +
jackpot glow for rare ones. Rarity classified client-side by type +
amount (wheelPrizeTier), shared icon rendering (wheelPrizeIcon).
- Three-phase spin motion (wind-back -> overshoot -> settle) with a
reduced-motion fast path; responsive wheel scaling via ResizeObserver.
Reveal-timing fix:
- The server pushes the refreshed winners list (which already contains the
just-won prize) the instant it answers the spin, ~5s before the wheel
stops. useFortuneWheel now buffers that update mid-spin and flushes it in
finishSpin so the prize is no longer spoiled in the winners panel.
- handleTransitionEnd only reacts to the wheel's own transform transition,
so a child icon's bubbling transitionend can't advance the spin phase
machine early.
Prize editor (admin):
- Add/Remove prize buttons in FortuneWheelSettingsView. New rows carry a
negative temp id collapsed to 0 on the wire (server inserts); removed rows
are simply omitted (server soft-disables). Requires the matching emulator
change to WheelManager.savePrize / WheelAdminSavePrizesEvent.
i18n: wheel.win.* and rarevalues.editor.add/remove in en/it/nl.
Move the radio on/off switch out of renderer-config (where it sat next
to asset/data URLs) into ui-config, alongside the other UI feature
toggles (game.center.enabled, guides.enabled, …) — the natural home for
a widget switch — and rename it to the dotted convention `radio_ui.enabled`.
The MainView gate now defaults to `false`, so the radio is opt-in: an
absent key keeps it hidden; set `"radio_ui.enabled": true` in ui-config
to show it. The radio.url data source stays in renderer-config.
Introduce a reusable NavigatorRoomSettingsSectionView card (rounded
bg-gray-100 panel with a bold-small title) and apply it across the
Access, VIP/Chat, Moderation and Rights tabs so every room-settings
screen matches the Base and Misc tab styling. Pure visual restyle —
handleChange wiring, events, composers and validations are unchanged.
The previous fix put 'flex' on the Text component, but Text forces
display:inline as its base class, so the flex never applied and the X
icon dropped onto its own line. Use a Flex container with the icon and
a Text child instead, so icon + label sit on one centered row.
Replace the cramped horizontal label/control rows with a vertical
stacked-label layout (bold label above each full-width control),
matching the sibling Access tab. Fixes multi-word labels wrapping in
the narrow panel. Tags share one label with the two inputs side-by-side.
Drops the now-unused Base spacer elements. Layout-only: no change to
handleChange, validation thresholds, save-on-blur, or field order.