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.

  1. 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) and players (id uuid, room_id uuid, name text, cash int, position int).
  2. 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_id matches their session”. For a prototype, enable Authenticated access and sign clients in anonymously using supabase.auth.signInWithOtp({ email }) or signInAnonymously().
    • In Database > Replication enable Realtime for the rooms and players tables 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());
  3. 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 state JSON blob (turn, properties, dice queue) on each move.
    • Subscribe to realtime changes so remote browsers receive rooms and players updates instantly.
  4. 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 });
    }
    
  5. Optional: Postgres function for authoritative moves
    • Create an apply_move SQL 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.

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 오류:
“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가 꺼져 있어도 같은 오류가 날 수 있으니 함께 확인하세요.