01 · Punkt wyjścia
Zacząć obok stołu, a potem zasłużyć na miejsce w jego centrum.
Grupa RPG śledzi karty postaci, kości, zasady, ekwipunek, rany, notatki i pozycję. Większość virtual tabletopów zaczynała od mapy. My pytaliśmy, co aplikacja może przejąć, nie odbierając kontroli graczom ani prowadzącemu.
Zaczęliśmy od telefonu wspierającego grę przy fizycznym stole, ale ta sama sesja musiała działać zdalnie. Powstało jedno założenie: responsywna aplikacja użyteczna zarówno obok stołu, jak i zamiast niego.
VTT od mapy
Przenieś fizyczny stół na ekran; zasady niech każda drużyna przyniesie własne.
MapaPionkiCzatKości
Zasady zostają w głowach graczy; oprogramowanie zostaje uniwersalne.
Rolling Dices
Najpierw scyfryzuj drużynę i zasady; po stół sięgnij, gdy aplikacja rozumie, czym jest tura.
PostacieSesjeKościZasadyŚwiatPlansza
Mapa pojawiła się na końcu — wtedy aplikacja rozumiała już toczącą się na niej grę.
Rolling Dices rozwijało się odwrotnie niż VTT zaczynające od mapy: najpierw cyfryzowało zasady i sesję, a stół na końcu.
Moja rola
- Założyłem produkt i zdefiniowałem propozycję dla początkujących.
- Prowadziłem 25+ sesji badawczych i testów z ponad 100 użytkownikami.
- Projektowałem kluczowe flow i system interfejsu w Figmie.
- Prowadziłem architekturę i współtworzyłem aplikację w React i Supabase; odpowiadałem za zakres i kolejność prac trzyosobowego zespołu inżynierskiego.
- Podjąłem decyzję o zamknięciu, gdy dane nie uzasadniały dalszej inwestycji.
02 · Co badania przesunęły do centrum
Produkt zmieniał się razem z naszym rozumieniem gry.
Pierwsze wydanie organizowało konta, postacie i zaproszenia, ale ledwie dotykało gry. Testy ujawniły ważniejsze pytania: co widzi każda rola, kto rozpoczyna akcję i które elementy sesji muszą być trwałe?
Wspólna sesja zastąpiła konto w centrum produktu. Jej dziennik połączył rozmowę, rzuty, zdarzenia i zmiany stanu; każda wydana pętla ujawniała kolejną odpowiedzialność — od kontekstu postaci po zasoby i wspólną przestrzeń.
- 25+sesji badawczych i usability
- 100+zaangażowanych graczy i prowadzących
- 2konwenty i kilkanaście mniejszych wydarzeń
Cztery sposoby patrzenia na ten sam stół.
Moderowane playtesty na Discordzie
Co zmieniłoGrupy wracały do dziennika, żeby rozstrzygać spory — dlatego dziennik sesji stał się kręgosłupem produktu, a nie oknem czatu.
Demo dla przechodniów na konwentach i spotkaniach
Co zmieniłoPierwsze dwie minuty rozstrzygały wszystko. Tworzenie postaci zamieniło rozdawanie punktów na wybór kart historii, bo nikt przy stoisku nie chciał liczyć.
Testy użyteczności na zadaniach
Co zmieniłoRzut wywołany musiał zaczynać prowadzący. Gracze prosili o możliwość rzucania samodzielnie, a potem nie wiedzieli po co — prośba o rzut stała się akcją MG z dołączonym kontekstem.
Wywiady z MG i ankiety społeczności
Co zmieniłoMG nie chcieli automatyzacji fikcji — chcieli pozbyć się księgowości. Ta granica pojawia się w sekcji o ewolucji i nigdy się nie przesunęła.
- 01
Przeprowadź sesję
Przeszkolony MG gra, jedno z nas patrzy i zapisuje wyłącznie to, co się wydarzyło.
notatki z czasem + nagranie - 02
Zapytaj, jak to było
Kwadrans ze stołem, dłuższa rozmowa z prowadzącym.
notatki z wywiadów - 03
Uporządkuj dowody
Momenty grupowane według tego, co mówią o produkcie, nie kto je zgłosił.
tablica wniosków - 04
Wybierz jedną odpowiedzialność
Jedna kolejna rzecz, którą aplikacja ma przejąć, skonfrontowana z granicą produktu.
flow w Figmie + notatka o zakresie - 05
Wydaj i umów kolejny stół
Build na tyle mały, żeby przetestować go z tymi samymi MG w ciągu dwóch tygodni.
wydanie + następna sesja
Trzech inżynierów, jeden na pełny etat — i ludzie wokół stołu.
Zespół techniczny był mały i częściowo dorywczy. Produkt działał dzięki drugiemu kręgowi — współzałożycielowi z branży wydawniczej, zaprzyjaźnionym mistrzom gry i wolontariuszom ze społeczności — który dawał to, czego trzech inżynierów nie mogło: prawdziwe stoły do obserwacji i ręce do ich prowadzenia.
Zespół techniczny
- Lead — produkt, badania, UX, architekturapełny etat
Ja. Prowadziłem badania, projektowałem flow i współtworzyłem aplikację od początku do końca.
- Fullstack, nacisk na frontend20–30 h / mies.
Prace nad interfejsem i funkcjami, w wymiarze zależnym od bieżącego obciążenia.
- Fullstack, nacisk na backendodszedł w 2023
Odpowiadał za pierwotny własny serwer. Zrezygnował w 2023 roku, co przebudowało architekturę.
Zespół wspierający
- Współzałożyciel — podręczniki i społecznośćwydawnictwo
Redagował i przygotowywał do druku podręczniki TTRPG w polskim wydawnictwie; napisał nasz skrót zasad, prowadził media społecznościowe i organizował każdy playtest z lokalnymi społecznościami.
- Zaprzyjaźnieni mistrzowie grykilkoro
Przeszkoleni z aplikacji; prowadzili sesje testowe na konwentach, w pubach, klubach, online i przy fizycznych stołach.
- Wolontariusze ze społecznościdoraźnie
Grafik, autorzy treści i ambasadorzy społeczności, którzy pomagali przy ulotkach, lore, postach w mediach społecznościowych i przyprowadzali własne grupy na playtesty.
- Społeczność na Discordziegracze
Serwer playtestów: wracające drużyny, zgłoszenia błędów, ankiety o tym, co budować dalej.
Gdy w 2023 roku odszedł backend developer, nie zastąpiliśmy własnego serwera. Iterowanie wyłącznie na froncie, z Supabase RPC jako prowizorycznym backendem, utrzymało rytm badań — i stało się zakładem architektonicznym opisanym dalej.
Jak badania wyglądały z zewnątrz.
Testowaliśmy tam, gdzie gracze już się spotykali: online, na konwentach i w lokalnych klubach.
03 · Rozszerzająca się granica
Każde wydanie przesuwało granicę tego, co liczyło się jako gra.
Produkt przeszedł od przechowywania informacji przez koordynację ludzi, wspólny stan i zasady aż po reprezentację przestrzeni. Kolejność wyznaczały badania, nie sztywny roadmap.
Koniec 2022
Asystent RPG
Przechowywała informacje
- konta
- postacie
- sesje
- znajomi
Konta, postacie i launcher organizowały grupę przed grą. Najważniejszym obiektem wciąż było konto.
Wiosna 2023
Wspólna sesja
Koordynowała ludzi
- drużyna
- rzuty wywołane
- dziennik sesji
- zaproszenia
Dziennik sesji, drużyna, fabuła i rzuty wywołane stworzyły pierwszą pełną pętlę multiplayer.
Maj — sie 2023
Asystent realtime
Pamiętała wspólny stan
- obecność
- zdrowie
- ekwipunek
- lokacje
- zapisy
Migracja do Supabase zmieniła sesje we wspólne obiekty live z oczekującymi akcjami, obecnością i ekwipunkiem.
Wrz — gru 2023
Silnik zasad i świat
Liczyła zasady
- atrybuty
- statystyki pochodne
- trudność
- energia i XP
- ekonomia drużyny
Atrybuty, umiejętności, wyposażenie i zasoby zmieniły karty postaci w aktywne obiekty gry; Story stało się Exploration.
Sty — lut 2024
Virtual tabletop
Reprezentowała przestrzeń
- siatka
- inicjatywa
- wysokość
- widoczność
- skradanie
Siatka walki, jednostki, inicjatywa, teren, wysokość i widzenie domknęły ewolucję w taktyczny workspace.
w rękach ludzi przy stole w aplikacji
Jedno nie przesunęło się nigdy: fikcja i prawo prowadzącego do rozstrzygania o niej. Każdy szczebel zdejmował ze stołu księgowość — nigdy decyzję należącą do ludzi wokół niego.
Więcej zasad usuwało więcej księgowości, ale odbierało produktowi uniwersalność. Odpowiedzią był konfigurowalny system motywów — najambitniejszy zakład projektu.
04 · Co aplikacja rozumiała
Nie plansza z tokenami. VTT, które rozumiało grę.
W early access Rolling Dices było połączonym zestawem systemów rozgrywki. Wartość nie leżała w jednym ekranie, lecz w tym, że reguły postaci, zasoby drużyny, postęp fabuły i walka przestrzenna zmieniały ten sam stan sesji.
LOGPamięć sesji
Dopisywana historia, w której dialog, rzuty, przedmioty, zdrowie, zasoby i lokacje dzielą jedną oś czasu.
- wiadomości
- zapisy rzutów
- zdarzenia fabularne
- zmiany stanu
CHARSilnik postaci
Atrybuty i umiejętności zasilały statystyki pochodne; ekwipunek, perki i efekty pasywne zmieniały możliwości postaci.
- zdrowie i energia
- XP i poziomy
- udźwig / skok / rzut
- ruch i widzenie
ACTNAkcje świadome zasad
Rzut wywołany niósł aktora, atrybut, trudność i kontekst ataku lub obrony; silnik budował kości i liczył konsekwencje.
- difficulty_roll
- action_roll
- premia za RP
- efekty pasywne
PARTYEkonomia kampanii
Pieniądze, prowiant, materiały i lekarstwa należały do drużyny, więc odpoczynek, leczenie i naprawa czerpały z jednej puli.
- odpoczynek
- leczenie ran
- naprawa
- level-up
WORLDEksploracja
Model Location → Area → Place ze story cards i położeniem graczy, dający prowadzącemu inny widok niż drużynie.
- hierarchia lokacji
- whereabouts
- story cards
- widok GM / gracza
BOARDWalka taktyczna
Wspólna siatka z jednostkami, inicjatywą i rundami, na której teren, wysokość, ściany i powierzchnie nadawały pozycji znaczenie.
- kolejka inicjatywy
- rundy i tury
- dystans
- wysokość
Jeden cykl sesji
Gra narracyjna i taktyczna były jedną pętlą: eksploracja wywoływała zdarzenia, zdarzenia prowadziły do spotkań i akcji, akcje zmieniały postacie i zasoby, a zapisana historia wpływała na dalszy bieg gry.
- 01
Wejście do świata
GM aktywuje lokację; każdy gracz zajmuje obszar i miejsce.
db_Session + whereabouts - 02
Ujawnienie zdarzenia
Karta powiązana z lokacją wprowadza spotkanie, zagrożenie lub skarb.
instance_StoryCard - 03
Budowa spotkania
GM tworzy jednostki, umieszcza je na planszy i ustala inicjatywę.
instance_Entity + Board - 04
Rozstrzyganie akcji
Tury i rzuty wywołane łączą zasady postaci, pozycję i modyfikatory.
turn_order + PendingAction - 05
Zapis konsekwencji
Zdrowie, energia, sprzęt, zasoby i historia odzwierciedlają wynik.
SessionPlayer + SessionRecord - 06
Przygotowanie od nowa
Odpoczynek, lekarstwa i materiały zamieniają zapasy w gotowość.
db_Session resources
Każdy desktopowy zrzut na tej stronie to aplikacja React z marca 2024 uruchomiona z oryginalnego kodu na reprezentatywnych danych sesji. Nic nie zostało przerysowane.
01 Silnik postaci
Karta postaci była wejściem do silnika zasad.
THEMEZdefiniuj język
Atrybuty, umiejętności i wzory żyją w jednej konfiguracji.
engine/themesConfigBUILDZbuduj postać
Rozdziel atrybuty i umiejętności w ramach motywu.
character_schemaDERIVEWylicz możliwości
Wartości bazowe i ważone umiejętności dają ruch, widzenie i więcej.
engine/derivedStatisticsEQUIPZastosuj wyposażenie
Waga, trwałość i modyfikatory walki wchodzą do kontekstu.
instance_PlayerItemACTRozstrzygnij w kontekście
Wywołana akcja używa postaci, sprzętu i bieżącego stanu.
action_roll
02 Ekonomia drużyny
Regeneracja zmieniała umiejętność postaci we wspólną decyzję ekonomiczną.
TARGETWybierz odbiorcę
Lecz siebie albo innego członka drużyny.
target SessionPlayerCALCULATEWyceń akcję
Mental i Medicine modyfikują koszt za punkt zdrowia.
calculateTreatWounds()PREVIEWPokaż konsekwencję
Wyświetl zdrowie po leczeniu i pozostałe lekarstwa.
derived client stateCOMMIT APrzywróć zdrowie
Zapisz nowy current_state wybranego gracza.
instance_SessionPlayerCOMMIT BWydaj lekarstwa
Odejmij koszt od wspólnych zapasów.
db_Session.meds
03 Model świata
Sesja poruszała się po świecie, nie po drzewie folderów.
AUTHORSpakuj setting
Location packs grupują lokacje i ich pule kart.
resource_LocationPackSTRUCTUREZbuduj miejsce
Lokacje zawierają typowane obszary, a obszary — miejsca.
resource_Location + AreaLOCATEPrzenieś drużynę
Każdy gracz ma jawną lokację, obszar i miejsce.
SessionPlayer.whereaboutsACTIVATEWprowadź do gry
Karta zasobu staje się kartą należącą do sesji.
instance_StoryCardREMEMBERRozstrzygnij i zapisz
Przejściowe zdarzenie znika, konsekwencja zostaje.
db_SessionRecord
04 Spotkania i walka
Spotkanie przechodziło z talii treści do stanu taktycznego.
SELECTWybierz szablon
Przeglądaj przeciwników i NPC przypisanych do lokacji.
resource_EntitySPAWNUtwórz stan runtime
Nadaj jednostce własność sesji i własne HP.
instance_EntityPLACEZapisz pozycję
Przeciągnij instancję z puli na współrzędną.
board_state[x:y]ORDERUstal inicjatywę
Połącz graczy i jednostki w kolejkę tur.
turn_order + current_roundRESOLVEProwadź walkę
Ruch, zasięg, widzenie i wyniki zmieniają wspólny stan.
Board + Player + Entity
Mechaniki w szczegółach
Cztery miejsca, w których aplikacja zdjęła zasady z głów graczy.
01 Plansza jako stan świata
Każde pole było stosem faktów o przestrzeni.
- Adres
- wiersz.kolumna → „6.8”
- Wysokość
- 15 poziomów · −14 m do +14 m
- Pole
- siatka 2 m · 4 m² na pole
- Trwałość
- board_
state JSON w instance_ Board
KEY6.8Stały adres wiersz.kolumna w board_state.
SPACEelevation: 7Poziom neutralny; mapuje się na 0 m.
CONTENTobject_type Opcjonalna powierzchnia, gaz, ściana lub obiekt eksploracji.
ACTORentity_id Opcjonalny gracz albo jednostka zajmująca pole.
RULEfield_disabled Blokuje umieszczanie; oznacza teren jako niedostępny.
- Eksploracja
- curio
- poi
- passage
- door
- treasure
- Powierzchnie
- fire
- ice
- oil
- water
- poison
- Gazy
- smoke
- steam
- poison_gas
- explosive_gas
- Przeszkody
- wall_small
- wall_medium
- wall_big
- disabled
Jedno pole, pięć niezależnych wymiarów. UI składało je wizualnie; dokument planszy synchronizował je jako jeden snapshot.
02 Ruch i pomiar
Ruch negocjowało się jako trasę, zamiast zgadywać go z pikseli.
- Skala
- 2 m na krawędź siatki
- Przekątna
- √2 × 2 m
- Trasa
- uporządkowany start + waypointy
- Wejście
- drag myszą · drag dotykiem
STARTpole 6.4Wybierz pole poruszanej figurki.
LEG 018,00 mCztery poziome krawędzie do pierwszego waypointu.
VIApole 6.8Skręć wokół terenu bez zastępowania początku.
LEG 024,00 mDwie pionowe krawędzie do celu.
TOTAL12,00 mPorównaj trasę z ruchem walczącej postaci.
- Możliwość postaci
- Physical
- Dexterity
- combatMovement
- Możliwość jednostki
- base_movement_range
- initiative
- Blokady upuszczenia
- occupied
- wall
- disabled field
Linijka mierzyła geometrię, silnik dawał możliwości, GM zachowywał ostateczną decyzję.
03 Zdrowie w strefach ciała
Figurka czyniła miejsce obrażenia i stan pancerza czytelnym.
- Strefy
- głowa · tułów · ramiona · nogi
- Miejsce trafienia
- D12
- Absorpcja
- najpierw trwałość pancerza strefy
- Konsekwencja
- reszta → globalne HP
HITD12 → torsoKontekst obrony wskazuje jedną z czterech stref.
LOOKUParmour: torsoZnajdź założony przedmiot z tym samym subtype.
ABSORBmin(9, 11) = 9Odejmij pochłonięte obrażenia od trwałości.
APPLY9 − 9 = 0 HPTylko niepochłonięte obrażenia zmieniają zdrowie.
EFFECThealth multiplierPozostałe zdrowie modyfikuje następne rzuty.
- Wcześniejszy koncept
- zone HP
- minor / moderate / critical
- overall condition
- Early access
- global health
- zone target
- zoned armour
- durability
- Kod figurki
- czerwony = wybór
- jasny = mocny pancerz
- ciemny = zużyty
- czarny = zniszczony
Strefy ciała jako kontekst taktyczny wokół prostszego rdzenia zdrowia.
04 Ekwipunek jako wejście reguł
Przedmiot był jednocześnie treścią, stanem runtime i kontekstem akcji.
- Definicja
- resource_
Item - Własność
- instance_
PlayerItem - Ograniczenia
- waga · sloty · strefa ciała
- Cykl życia
- załóż · użyj · uszkodź · napraw · zapisz
DEFINEresource_Item Typ, waga, sloty, bazowa trwałość, modyfikatory.
OWNinstance_PlayerItem Gracz, ilość, flaga założenia, bieżąca trwałość.
EQUIPloadout guardsLimit dwóch slotów; unikalna strefa pancerza.
USEaction contextZastosuj atak lub obronę; zużyj trwałość.
REPAIRrepair + recordWydaj materiały; dopisz zmianę do historii.
- Definicja wspólna
- type
- subtype
- rarity
- weight
- price
- base_durability
- Instancja gracza
- quantity
- is_equipped
- durability
- session_player_id
- Konsumenci reguł
- carry capacity
- attack
- defence
- body armour
- repair
Rozdział resource/instance zachowywał treść do ponownego użycia, a każda sesja uszkadzała i zakładała własną kopię.
05 · Jedna akcja od początku do końca
Mechaniką stała się akcja, nie sama kość.
Rzut wywołany mieści naraz pomysł produktowy i architekturę. Prowadzący wybierał gracza, atrybut i trudność; silnik wyliczał kości i utrwalał oczekującą akcję; gracz rzucał, a zdrowie, energia i wyposażenie kształtowały wynik, który trafiał do wspólnego dziennika. Kości pozostawały widocznym momentem rozstrzygnięcia, ale aplikacja rozumiała dość kontekstu, by ocenić akcję i zachować jej konsekwencje.
- 01Prowadzący
Wywołanie akcji
Wybór gracza, kategorii, atrybutu i trudności.
- 02Silnik w przeglądarce
Wyliczenie kości
Dobór schematów z motywu i kontekstu postaci.
difficulty_roll - 03Postgres + Realtime
Utrwalenie oczekującej akcji
Żądanie przetrwa opóźnienie i reconnect; Realtime powiadamia gracza.
instance_PendingAction - 04Gracz
Rzut
Rozstrzygnięcie akcji kontekstowej, nie dowolnej kości.
action_roll - 05Silnik w przeglądarce
Wyliczenie konsekwencji
Modyfikatory, energia, zdrowie, sprzęt i XP.
- 06Postgres + Realtime
Zapis i broadcast
Aktualizacja gracza, dopisanie rekordu, usunięcie oczekującej akcji; każdy klient pobiera świeży stan.
SessionPlayer + SessionRecord
Plansza reprezentowała stan bieżący; dziennik wyjaśniał, jak drużyna do niego dotarła. Baza była jednocześnie trwałym stanem, transportem multiplayer i lekką kolejką workflow.
06 · Dwa konteksty, jeden model
Jeden model gry, dwa konteksty użycia.
Na telefonie Rolling Dices działało jak pas z narzędziami: jeden skupiony kontekst naraz, więc telefon wspierał grę przy fizycznym stole, zamiast z nią konkurować. Nasze pierwsze założenie było odwrotne — wczesna wersja blokowała małe ekrany. Potem telefon stał się wymogiem podstawowym, łącznie z dotykowym drag-and-dropem na planszy walki.
Desktop przestał być większym telefonem i stał się przestrzenią pracy: drużyna, dziennik sesji, kości, eksploracja i plansza widoczne razem, a rzadsze operacje otwierane jako zadania modalne. Model domeny nie zmieniał się nigdy; zmieniała się tylko kompozycja.
Desktop · przestrzeń pracy
Cztery powierzchnie otwarte naraz, żeby prowadzący widział drużynę, historię, świat i walkę bez przełączania widoków.
Drużyna
Postacie, zdrowie, energia, ekwipunek
Dziennik sesji + kości
Wspólna historia i trwający rzut
Plansza
Siatka, figurki, inicjatywa, teren
Eksploracja
Lokacja, miejsca, aktywne karty fabuły
Zadania modalne
- wywołaj rzut
- zarządzaj zasobami
- odpoczynek
- dodaj jednostkę
- zmień lokację
- dobierz kartę
Mobile · jeden kontekst
Sześć kontekstów, dokładnie jeden na ekranie naraz, każdy pod kciuk.
Dziennik sesjiDrużynaKościEksploracjaPlanszaZasoby
Telefon zmienił się ze zbioru ekranów w system operacyjny sesji.
Koncepcje z 2023 roku wprowadzały osobne narzędzia. W marcu 2024 były one projekcjami jednego modelu multiplayer, z tymi samymi postaciami, akcjami, światem i stanem walki na mobile i desktopie.
Base MVP · Figma, 2023
Niezmodyfikowane projekty pre-alpha z 2023 roku, pokazane osobno od późniejszych zrzutów produktu.
- Tworzenie postaci→Stan postaci live i ekwipunek
- Osobne formularze rzutu→Workflow zasad GM → gracz
- Statyczna lista fabuły→Stan lokacji, miejsc i zdarzeń
- Nawigacja asystenta→Pas narzędzi całej sesji
- Brak warstwy taktycznej→Jednostki, plansza i tury
Early access · marzec 2024
Widoki mobilne wyrenderowane z oryginalnej aplikacji na tej samej reprezentatywnej kampanii co zrzuty desktopowe.
07 · Kształt systemu
VTT oparty na bazie realtime, z silnikiem gry w przeglądarce.
Rolling Dices było aplikacją SPA w React i TypeScript połączoną bezpośrednio z Supabase. Redux trzymał tożsamość i nawigację, React Query — projekcje serwerowe, a interakcje o wysokiej częstotliwości — kości, przeciąganie, zaznaczenia — zostawały lokalne aż do zapisu. Osobna warstwa engine liczyła kości, statystyki pochodne, XP, energię i inicjatywę. Supabase zastąpiło naraz serwer aplikacji, uwierzytelnianie i websockety: wyjątkowo lekka architektura multiplayer jak na trzech inżynierów, z których tylko jeden pracował w pełnym wymiarze.
Model spójności brzmiał: zdarzenie, invalidacja, ponowne pobranie. Przeglądarka zapisywała zmianę w Postgresie, Supabase emitowało zdarzenie, pozostałe klienty unieważniały projekcję i pobierały świeży stan. Realtime nie był dodatkiem — był modelem spójności. Postgres pełnił też rolę backend-for-frontend, składając funkcjami SQL projekcje gotowe dla UI, podczas gdy zapisy nadal trafiały do kilku tabel wprost z przeglądarki.
Przeglądarka · zainstalowane PWA
- Widoki React
- Stan UI w Redux
- Projekcje React Query
- Silnik gry w TypeScript
Supabase
- Auth
- PostgREST
- SQL RPC
- Realtime
- Storage
PostgreSQL
- Trwałe rekordy
- Instancje runtime
- Treści zasad
- Funkcje modeli odczytu
Pętla spójności
- 01Klient zapisuje do Postgresa
- 02Realtime emituje zmianę
- 03Klienty unieważniają projekcję
- 04Klienty pobierają autorytatywny stan
Czterech właścicieli, cztery rytmy aktualizacji
Dane trafiały tam, gdzie pasował ich czas życia i częstotliwość zmian; ciekawy problem leżał na granicach między właścicielami.
Redux Toolkit
Tożsamość, obudowa sesji, przejściowy kontekst workflow
- aktualny użytkownik
- aktywna sesja
- nawigacja
- kontekst modala
TanStack Query
Projekcje serwerowe i invalidacja cache’u
- gracze
- rekordy
- lokacje
- jednostki
Stan komponentów
Interakcje wymagające natychmiastowej reakcji
- stół do kości
- pozycja drag
- wybrane pola
engine/*
Czyste transformacje między stanami gry
- zestawy kości
- statystyki pochodne
- XP / energia
- inicjatywa / widzenie
Nazwa schematu mówiła, w jakim czasie żyje obiekt.
Każdy prefiks sugerował ownership, częstotliwość zmian i sposób konsumowania przez UI.
resource_*Definicje zasad i treści
Stabilne, wielokrotnego użytku, niezależne od sesji
- resource_CharacterClass
- resource_Entity
- resource_Item
- resource_StoryCard
db_*Trwałe rekordy domenowe
Długo żyjąca tożsamość i historia
- db_Session
- db_PlayerCharacter
- db_SessionRecord
- db_Profile
instance_*Instancje aktywnej sesji
Zmieniane podczas gry, rozgłaszane przez Realtime
- instance_SessionPlayer
- instance_PendingAction
- instance_Entity
- instance_Board
engine/*Transformacje domenowe
Bezstanowy TypeScript między wejściem a następnym stanem
- kości
- statystyki postaci
- efekty
- walka
- ruch
Postgres jako builder modeli odczytu
RPC get_players_for_session składało gotowy dla UI model gracza z sześciu źródeł, trzymając wiedzę o joinach poza Reactem.
instance_SessionPlayer
↳ db_PlayerCharacter
↳ db_Profile
↳ resource_CharacterClass
↳ get_player_perks()
↳ get_player_items()Jeden kanał, osiem żywych agregatów
Kanał sesji nasłuchiwał zmian tabel. Większość zdarzeń unieważniała projekcję i pobierała ją ponownie; dopisywane rekordy trafiały wprost do cache’u. Zapytania nie starzały się same — kontraktem odświeżania było Realtime, nie polling.
- db_SessionRecord
- db_Session
- instance_SessionPlayer
- instance_PlayerItem
- instance_PendingAction
- instance_Entity
- instance_LocationState
- instance_Board
08 · Czym zapłaciliśmy
Zapłaciliśmy odpornością, żeby kupić tempo iteracji.
Migracja do Supabase w maju 2023 była kluczowym zakładem, zrobionym z otwartymi oczami. Funkcja szła z interfejsu przez mutację i Postgresa do Realtime bez serwera aplikacyjnego po drodze. Dla częściowo dorywczego zespołu goniącego produkt, który wciąż musiał się obronić, ta dźwignia była warta więcej niż odporna infrastruktura. Rachunek przyszedł w konkretnych miejscach.
- 01
Tempo kontra autorytet
Liczenie zasad w TypeScript przyspieszało iteracje; oznaczało też, że zmodyfikowany klient mógł wybierać sobie wyniki. RLS chronił wiersze, ale nie potrafił wyrazić reguły gry.
- 02
Proste zapisy kontra transakcje
Rozstrzygnięcie akcji aktualizowało gracza, tworzyło rekord i usuwało oczekującą akcję w osobnych requestach. Częściowa awaria zostawiała wspólny stan niespójny.
- 03
Jeden dokument planszy kontra współbieżność
Plansza jako jeden dokument JSON upraszczała hydrację i broadcasting — i pozwalała dwóm równoległym edycjom nadpisywać niezależne pola, last write wins.
09 · Rezultat
Grywalny produkt, świadome zakończenie, trwałe lekcje.
Na początku 2024 roku Rolling Dices miało pełny zarys przeglądarkowego VTT — postacie, wspólne sesje, kontekstowe rzuty, trwały dziennik, ekwipunek, zdrowie, zasoby drużyny, eksplorację, planszę walki z inicjatywą, terenem i widzeniem. Mogło leżeć na telefonach wokół fizycznego stołu albo samo być stołem.
Zakres był realny; walidacja nie. Dowiedzieliśmy się dużo o tym, jak ludzie grają, ale zbyt mało z nich zmieniało utrwalone zachowania w sposób uzasadniający dalszą inwestycję. W kwietniu 2024 zamknąłem produkt, zamiast pomylić tempo techniczne z dowodem rynkowym. Założenie produktu oznacza odpowiedzialność za kryteria zatrzymania tak samo jak za wizję.
Co zabrałem do kolejnych produktów
- 01
Waliduj zachowanie, nie entuzjazm
Ciepłe rozmowy i angażujące testy to nie powtarzalne użycie, gotowość do zmiany narzędzia ani do płacenia.
- 02
Sekwencjonuj ambicję
Każdy nowy system zwiększał możliwości produktu — i odsuwał ostrzejszy test głównej propozycji.
- 03
Zatrzymanie projektu to praca produktowa
Zamknięcie produktu, którego nie bronią dane, oszczędza czas, uwagę i zaufanie dla następnego.
Wczesna aplikacja żyła obok gry. Finalna próbowała zmieścić grę w sobie.