Meet Tina, the robot host who makes sure everyone at the table gets their moment.

Inspiration

Every friend group knows the pattern: two people talk, one person goes quiet, and phones come out. Most icebreaker apps put the game on a screen, which makes that worse, because now everyone is looking down at the same app instead of at each other.

We wanted the game to live on the table. Tina drives around, makes faces, and hands out challenges, so the thing everyone is watching is a small robot in the middle of the group. Phones come out for a few seconds to join and to read a challenge, then go back in pockets.

We also didn't want an AI deciding who gets put on the spot. A model can notice that someone hasn't talked in a while, but a friend should decide what to do about it. That's why one person at the table is always the Game Master, and Tina only makes suggestions.

What it does

Destina is a tabletop party game for a group of friends, hosted by Tina.

  1. Tina shows a QR code on her face. Each player scans it, types a name, and links Instagram or pastes a few lines about themselves. Muse Spark turns that into interest cards, and each card shows the exact excerpt it came from, so you can see why it thinks you like rock climbing. You keep the cards you agree with, delete the rest, and add your own.
  2. Tina listens as the night goes on and keeps track of who has been left out and what the group has in common.
  3. When it's time for a round, Muse Spark looks at everyone's approved interests, who has had fewer turns, and what's already been played, then suggests three challenges. Each one names the players involved and gives a one-line reason, like two people who both said they love bad horror movies.
  4. One friend wears the Vision Pro as Game Master. They see Tina's camera feed next to her three picks and her reasoning. They choose one, can rewrite the prompt, and can ignore Tina completely if they have a better idea. The headset goes to someone new each round.
  5. The Game Master drives Tina across the table to the chosen player, and her 3D-printed dropper leaves a star in front of them.
  6. Every star carries the same NFC tag. Tapping it opens whatever challenge the Game Master approved. If the challenge has a secret part, only the target's phone shows it, and everyone else sees the public half.
  7. Players earn TABLE coin on Solana devnet, level up a badge that can't be traded, send each other kudos, and take home 1-of-1 keepsake NFTs from the night.

There are six kinds of star:

  • Duel: two players each get a made-up position to argue, and the table picks a winner. The AI never assumes people actually disagree.
  • Bounty: a secret mission to get a specific story out of another player before the round ends. Only the person on the mission can see it.
  • Hot Seat: the table guesses how one player will answer a question built from their interests, then that player gives their real answer.
  • Jinx: everyone says a one-word answer on the count of three, then tries again to match.
  • Forge: two players take turns adding to one imaginary invention.
  • Golden: a rare bonus round.

How we built it

Destina architecture diagram

Tina's body

Tina runs on a Raspberry Pi. Two brushless DC motors move her around the table through a motor controller wired on a breadboard, and a 3D-printed dropper holds the NFC stars. A Python client on the Pi connects to our relay, streams the USB webcam at about 12 frames a second (640 px wide, JPEG quality 60), and sends telemetry ten times a second. A small motor server on the Pi takes drive commands, and it stops the motors if 300 ms pass without a new one, so a dropped connection can't send Tina off the edge of the table.

Tina's face

Her face is a Hack the North badge (an ESP32-C3 with a 320x240 ST7789 screen) running C++ firmware we wrote with PlatformIO. It's black eyes and a mouth on a white screen. She blinks every two to five and a half seconds, with a one-in-five chance of a double blink. Every few seconds her eyes pick a new spot to look at and ease toward it instead of snapping. Every 4 to 9 seconds she switches expression on her own. The choice is weighted, so friendly faces come up most and sad, angry, or sleepy ones only once in a while. Pressing the A button swaps the face for the join QR, and it switches back after 10 seconds. The badge needs nothing but USB power.

The relay

Everything that moves in real time goes through one Node websocket relay on Render. The Pi, the Vision Pro, the game hub, and any dashboard join a room with a role. JSON messages go to everyone else in the room, or only to the roles named in a "to" field. Camera frames only go to clients that asked for video. If a client falls behind, the relay drops video frames for that client but never drops JSON, so a slow headset still gets every command.

The Vision Pro app

The Game Master app is a visionOS app in Swift. It shows Tina's live feed and her suggestions, and it drives her by sending motor commands 20 times a second while you hold forward. That resend rate is what keeps the Pi's 300 ms safety stop from kicking in during normal driving.

The player web app and server

The player app is React and Vite, and it talks to an Express server in TypeScript. The trickiest part was the stars. Every NFC tag holds the same URL, so a tag can't say which room or player it belongs to. When you join through Tina's QR, the server gives your browser an HTTP-only cookie tied to your room. Tapping any star sends you to that one URL, and the server uses the cookie to show your room's current challenge, with the secret half included only if you're the target. Just opening the page never changes the game, so tapping a star twice is harmless.

Player credentials are stored hashed, the cookies are SameSite and Secure over HTTPS, and requests that change data are rejected if they come from another origin. The Game Master's control API uses a separate server-side key that never reaches a browser or a tag. Game data lives in TigerDB, and the player app keeps rooms and profiles in SQLite.

Muse Spark

We call Muse Spark through Meta's OpenAI-compatible API in two steps. The first pulls interest suggestions out of profile text and ties each one to a source excerpt. The second writes three challenges from approved interests, past rounds, how many turns each player has had, and an optional target the Game Master picked.

Most of the prompt work went into making the challenges sound like a friend wrote them. The model is told that profile text is untrusted data and never instructions. It isn't allowed to guess sensitive traits or assume two people disagree, and challenges can't need equipment or embarrass anyone. We also ban the words AI writing leans on, so a Hot Seat question reads like something you'd actually ask at dinner.

Every response is checked with Zod: the structure, that each cited interest really exists, that Duels have two players, that a Bounty's secret is kept out of the public text, and that titles don't repeat. Bad output gets one repair attempt, and calls time out after 18 seconds. The server then scores the candidates. Each prior turn a player has had costs 8 points, interests the players share add 15, and reusing a star type already played costs 5. That pushes quiet players and new kinds of rounds to the top.

If Muse is down or we hit our request cap, the Game Master gets clearly labeled template challenges instead, so the game keeps going. A request ledger on disk counts every call, including repairs and failures, so we couldn't burn through our credits by accident.

Instagram

Instagram import uses Instagram Login with only the basic profile permission. It reads the bio and up to 12 recent captions, and asks for each optional field separately so one missing field doesn't fail the whole import. Login state expires after ten minutes and works only once. Access tokens are encrypted with AES-256-GCM and thrown away after the import. You can also skip Instagram and paste text instead.

Solana

We wrote our own Anchor program on Token-2022, without Metaplex.

  • TABLE coin is a Token-2022 mint whose mint authority and permanent delegate both belong to the program, so coins are only created, moved, or burned under program rules.
  • Each player gets a badge NFT that can't be transferred. Its level, XP, connections, kudos, and achievements are rewritten on chain as they play, and the level is 1 + floor(sqrt(xp / 10)).
  • After each round the server stores a hash of the round's event log on chain. That account can only be created once. Payouts are capped per round, limited to the number of players in the round, and blocked from paying the same wallet twice.
  • A table goal turns the night into a group effort: every award fills a shared pot, and when it fills up, everyone who played can claim a bonus.
  • Players can send each other 1 to 10 TABLE as kudos, with a 60-second cooldown per pair. The first kudos between two people adds a connection for both.
  • A shop burns TABLE to redeem game-night perks and writes a numbered receipt.
  • Achievements like icebreaker, social butterfly, and quiet hero unlock from stats or are granted by the server.
  • Keepsakes are 1-of-1 NFTs whose on-chain fields record the challenge, session, and round.

No transcripts, names, or camera data ever go on chain, and it's devnet only, with nothing to buy or cash out. The program is deployed at DqqLyrxUPAiJ2m3Fu4uLL6GirTH2cSXXS9wJHmGngaZX.

Challenges we ran into

Our first plan was a claw machine with an XY gantry that would pick a capsule and drop it in front of a player. After the pitch we cut it for a driving robot. The gantry was too much to build reliably in a weekend, and a robot rolling up to someone is more fun to watch anyway.

NFC took more thought than we expected. Identical tags can't tell a phone who tapped them, and we didn't want to program a different tag for every round. Moving identity into the browser cookie let every star be the same. On the hardware side we learned that stacked tags detune each other and fall outside the badge reader's roughly one-centimeter range, so we had to program them one at a time. The firmware now refuses to write when more than one tag answers.

Getting the AI to write challenges that didn't sound like a corporate team-building worksheet took a lot of prompt revisions. The validation layer came out of the same work: a model that cites an interest ID that doesn't exist, or slips a Bounty's secret into the public text, gets caught before the Game Master ever sees it.

Deploying the Solana program ran into rate limits. The public devnet RPC returned 429s during deploys, and our RPC provider blocked requests from Render's IPs, so we deploy through one and serve the live chain service through the other.

Accomplishments that we're proud of

The AI only recommends. Nothing reaches a player's phone until a person approves it, and the Game Master can always throw Tina's picks out.

Every interest card shows the text it came from, players approve cards before the game uses them, and deleting your profile removes your source text.

Tina is a real robot. She has motors, a webcam, a printed dropper, and a face that runs on our own firmware with a personality of its own.

We wrote the on-chain economy from scratch in Anchor, with tests for payout caps, double-pay protection, keepsakes, and badges that can't be transferred.

What we learned

Getting the AI to write a challenge was the quick part. Most of the weekend went into making challenges fit real people, keeping the secret parts secret, and putting a human in charge of what gets played.

Agreeing on one websocket message format early also paid off. With the format settled, we built the robot, headset, phones, and chain code in parallel and they fit together.

What's next for Destina

  • Tina drives herself to the chosen player using the webcam
  • Checking Bounty and Jinx results from what Tina hears
  • Hand-tracked driving from the Vision Pro for the Golden star
  • Muse Image art for Forge keepsakes, so the thing two players invented becomes the NFT they keep

Code: github.com/Dhivyeshp/hacktx_26

Built With

+ 5 more
Share this project:

Updates

Submission history