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.
Design doc for upgrading the room-settings Base tab from the cramped
horizontal two-column rows to a stacked-label layout matching the
sibling Access tab. Also gitignore the .superpowers/ brainstorm dir.
Le bubble custom ereditavano la slice base (centro largo) -> con repeat si
duplicavano, con stretch si allungavano troppo/storte. Ora ogni bubble ha
border-image-slice/width calcolata dalla sua immagine: il taglio cade nella
zona centrale del corpo, sulla colonna piu uniforme (colore pieno), con un
filo stirabile di ~2px e border-image-repeat: stretch. Cosi il corpo si stira
pulito e i cap restano intatti. (Le bubble con decoro su tutto il corpo, senza
una fascia piena, restano un compromesso: limite intrinseco del 9-slice.)
Ereditavano border-image-repeat: repeat dalla regola base, quindi il centro
delle nuove bubble (con grafica) si duplicava invece di allungarsi. Override
border-image-repeat: stretch per le 253-291 cosi il corpo si stira come le
originali (che avevano il centro a tinta unita).
- 39 bubble custom con relativo pointer colorato (colore campionato dal
fondo di ogni bubble) + regole CSS in Chats.css (resa in-stanza border-image
+ anteprima nel selettore)
- selezionabili via chat.styles dell'ui-config (lato server)
- soundboard: paginazione 9/pagina (griglia 3x3) con frecce + indicatore,
cosi la card non cresce a dismisura
The Base tab labels used col-3 and the delete row used
d-flex/justify-content-center — Bootstrap utilities that don't exist
in this Tailwind 4 build, so labels collapsed and wrapped. Swap to
w-1/4 shrink-0 and flex/justify-center/items-center, and drop the
dead col-4 on the Access-tab password inputs. Also fix a missing
break in the tag save-error switch (invalid-tag always showed the
non-choosable message) and a && / || precedence bug in saveTags
that checked the wrong tag field.
Replace the onKeyDown Enter handler + onClick button with a
<form action={submitSearch}>. Enter submits natively; the search
button (a styled div, not a real <button>) triggers form submission
via formRef.requestSubmit(), so both paths run the single
FormData-driven handler. The 300ms debounced filter push is kept.
The hook is the useState/useMessageEvent variant; the leftover
useQueryClient().invalidateQueries call required a QueryClientProvider
the unit test didn't supply (6 failures). The FlatCreatedEvent handler
already re-sends the search composer, so the invalidate was dead code.
Move favourite room ids out of the useBetween navigator store into a
dedicated Zustand store. useNavigatorFavourite(roomId) subscribes only
to s.ids.has(roomId) (a boolean), so a FavouriteChangedEvent for one
room no longer re-renders every favourite-aware view. apply() returns
the same state reference when membership is unchanged.
- Catalogo Hippiehotel responsive su mobile (finestra 96vw/72vh, rail
tappabile, sotto-pannelli ristretti); duckie ripristinato come entita
separata (revert modifiche scrollbar sul suo CSS)
- BC e catalogo normale seguono entrambi il toggle tema; il duckie non
duplica piu il logo nelle pagine info_duckets
- Navigator: highlight della tab segue currentTabCode (era bloccato su
Pubblici mentre il contenuto cambiava)
- Inventario: link inventory/show/<tab> per deep-link a una scheda
- User Profile: avatar visibile e allineato a bg/stand, finestra piu
grande, bordi puliti, Created/Last login mostrano il valore, bottoni
Change Looks/Rooms/Change Badges/Add friends/Achievement funzionanti
- Amici: header non piu sovradimensionati e teste avatar inquadrate
(regole flat: quelle annidate .nitro-friends{&...} non si applicavano)