Portfolio
Online multiplayer quickstart (Supabase Realtime)
Supabase is the fastest option for this GitHub Pages build because it gives you a Postgres database, Row Level Security, and realtime listeners that work directly from the browser. The steps below wire your existing Blue Marble UI to a hosted backend without spinning up custom servers.
-
Create the Supabase project
- Visit Supabase, create a project, and copy the Project URL + anon public key.
- Under Database > Tables add two tables:
rooms(id uuid primary key, code text unique, state jsonb) andplayers(id uuid, room_id uuid, name text, cash int, position int).
-
Enable realtime + Row Level Security
- Turn on RLS for both tables, then add policies such as “Authenticated users can insert/select/update rows where
room_idmatches their session”. For a prototype, enable Authenticated access and sign clients in anonymously usingsupabase.auth.signInWithOtp({ email })orsignInAnonymously(). - In Database > Replication enable Realtime for the
roomsandplayerstables so updates are broadcast to clients.
-- Enable Row Level Security on both tables ALTER TABLE public.rooms ENABLE ROW LEVEL SECURITY; ALTER TABLE public.players ENABLE ROW LEVEL SECURITY; -- (Re)create lobby insert policy DROP POLICY IF EXISTS rooms_insert_authenticated ON public.rooms; CREATE POLICY rooms_insert_authenticated ON public.rooms FOR INSERT TO authenticated WITH CHECK (auth.uid() IS NOT NULL); -- Only users that joined the room may read or update its state blob DROP POLICY IF EXISTS rooms_joined_rw ON public.rooms; CREATE POLICY rooms_joined_rw ON public.rooms FOR SELECT USING (EXISTS ( SELECT 1 FROM public.players WHERE players.room_id = rooms.id AND players.user_id = auth.uid() )) WITH CHECK (EXISTS ( SELECT 1 FROM public.players WHERE players.room_id = rooms.id AND players.user_id = auth.uid() )); -- players table: each user may only read/write their own row DROP POLICY IF EXISTS players_self_access ON public.players; CREATE POLICY players_self_access ON public.players FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid()); - Turn on RLS for both tables, then add policies such as “Authenticated users can insert/select/update rows where
-
Wire your GitHub Pages UI
- Add the Supabase JS SDK to
portfolio.markdown(ES module:<script type="module">import { createClient } from 'https://esm.sh/@supabase/supabase-js';</script>). - Instantiate the client with your project URL + anon key, then create helpers that read/write the shared
stateJSON blob (turn, properties, dice queue) on each move. - Subscribe to realtime changes so remote browsers receive
roomsandplayersupdates instantly.
- Add the Supabase JS SDK to
-
Sample room bootstrap
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); const { data: room } = await supabase.from('rooms') .insert({ code: lobbyCode, state: initialState }) .select() .single(); supabase .channel(`room-${room.id}`) .on( 'postgres_changes', { event: '*', schema: 'public', table: 'rooms', filter: `id=eq.${room.id}` }, (payload) => syncBoard(payload.new.state) ) .subscribe(); async function commitMove(patch) { await supabase.rpc('apply_move', { room_id: room.id, patch }); } -
Optional: Postgres function for authoritative moves
- Create an
apply_moveSQL function that validates turn order, merges player cash/position, and rolls back illegal moves before broadcasting. - Expose lightweight “start game”, “end game”, and “shuffle golden key” RPCs so every client shares the same randomness.
- Create an
Once this Supabase plumbing is in place, deploy your updated
portfolio.markdown to GitHub Pages—no extra servers are required,
and you can later port the same Realtime calls into a Discord Activity.
부루마불 Web
출발 월급 20만 · 2~4인 · 건물 · 무인도 · 우주여행 · 황금열쇠
게임 설정
플레이어 수 (2~4)
선택 규칙
타일 세트
플레이어 1 이름
플레이어 2 이름
플레이어 3 이름
플레이어 4 이름
· 3~4인: 시작 자금 300만 / 2인: 600만
· 건물은 각 차례 시작에 자신의 땅을 클릭해 지을 수 있습니다.
· 출발/무인도 위치만 고정되고, 나머지 타일은 정책에 따라 재배치됩니다.
· 건물은 각 차례 시작에 자신의 땅을 클릭해 지을 수 있습니다.
· 출발/무인도 위치만 고정되고, 나머지 타일은 정책에 따라 재배치됩니다.
온라인 멀티플레이어 (Supabase)
로비 코드
내 이름
· 호스트는 위 설정으로 방을 만든 뒤, 로비 코드를 친구에게 공유합니다.
· 참가자는 같은 코드를 입력하고 참가 버튼을 누르면 동일한 게임 상태를 실시간으로 공유할 수 있습니다.
· Supabase Auth 설정에서 Anonymous Sign-ins를 반드시 활성화해야 브라우저에서 인증이 진행됩니다.
· “new row violates row-level security policy” 오류가 보이면 위 SQL 정책을 적용했는지 다시 확인하세요.
· 참가자는 같은 코드를 입력하고 참가 버튼을 누르면 동일한 게임 상태를 실시간으로 공유할 수 있습니다.
· Supabase Auth 설정에서 Anonymous Sign-ins를 반드시 활성화해야 브라우저에서 인증이 진행됩니다.
· “new row violates row-level security policy” 오류가 보이면 위 SQL 정책을 적용했는지 다시 확인하세요.
자주 발생하는 Supabase 오류:
“rooms 테이블에 INSERT 정책이 없어서 거부되었습니다” 메시지가 뜨면 Supabase 대시보드 > SQL Editor에서 아래 구문을 실행해 RLS를 켠 뒤 다시 시도하세요.
Auth > Providers에서 Anonymous Sign-ins가 꺼져 있어도 같은 오류가 날 수 있으니 함께 확인하세요.
“rooms 테이블에 INSERT 정책이 없어서 거부되었습니다” 메시지가 뜨면 Supabase 대시보드 > SQL Editor에서 아래 구문을 실행해 RLS를 켠 뒤 다시 시도하세요.
ALTER TABLE public.rooms ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS rooms_insert_authenticated ON public.rooms;
CREATE POLICY rooms_insert_authenticated ON public.rooms
FOR INSERT TO authenticated WITH CHECK (auth.uid() IS NOT NULL);
ALTER TABLE public.players ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS players_self_access ON public.players;
CREATE POLICY players_self_access ON public.players
FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid());
이미 같은 이름의 정책이 있다면 SQL Editor에서 DROP POLICY ... 후 다시 생성하거나, 정책 편집기에서
Policy SQL Preview 영역에 위 구문을 붙여 넣고 Update Policy를 눌러 내용을 갱신하면 됩니다.Auth > Providers에서 Anonymous Sign-ins가 꺼져 있어도 같은 오류가 날 수 있으니 함께 확인하세요.