A realtime web game built with websockets, Preact, and Astro.
- / serves as the main menu, allowing to start a new game and to join an existing game with a shared code.
- /connect creates a websocket connection between the browser and the "lobby".
- /world/:worldName supports shareable links to automatically join a game.
- 🪄 @starting-style for animating microinteractions.
- 🖌️ OKLCH for visually consistent color palettes.
- 🗄️ IndexedDB for saving player details and selected theme.
- 📡 Service workers to prevent flash of "unthemed" content.
- 🎨 Emotion for styling, astro-emotion to generate all classes at build time.
- 🔌 astro-node-websocket to add websocket support to Astro.
- 🧮 @preact/signals for state management.
- 🎊 canvas-confetti for victory celebrations.
- 🧮 clsx for composing CSS classes.
Using a GitHub Actions workflow and a bash script, changes are automatically deployed to the VPS running sillystring.party
.
- The project is configured to build into a self-contained static bundle, not dependent on
node_modules
. - .github/workflows/deploy.yml builds the project, uploads the bundle as an artifact, and informs the server of the artifact id.
- The server script downloads the artifact and restarts the node server.
- The GitHub Actions workflow knows a deploy token, which is required by the server when requesting a redeploy.
- The server knows a GitHub access token, which is required by github.com when downloading artifacts.
- Clone the repository:
git clone https://github.com/lilnasy/tic-tac-toe
cd tic-tac-toe
- Install dependencies:
pnpm install
To start the development server:
pnpm dev
The application will be available at http://localhost:4321
- 🎮 /game: Game logic and state management.
- 📚 /lib: Polyfills, state management helpers, IndexedDB persistence helpers, vite plugins.
- 🎞️ /assets: Sound effects and favicons.
- 📃 /pages: Astro file-based router.
- 🧩 /components: UI and interaction logic.
- 🛠️ /patches: fixes to known issues in the libraries being used, and revert of preact's mangled code.
To create a production build:
pnpm build
Start the node server:
node --enable-source-maps dist/server/entry.mjs
Start caddy to create TLS certificates, manage cache, and serve the application:
caddy run --config ./Caddyfile
Autorestart the server on failure, manage logs, and start the server on every boot by creating an OpenRC service.
Create the OpenRC service file in /etc/init.d/tictactoe
:
#!/sbin/openrc-run
supervisor="supervise-daemon"
name="Tic Tac Toe"
description="Run a node server hosting the game."
command="node"
# adjust as necessary
command_args="--enable-source-maps /app/dist/server/entry.mjs"
command_background=true
pidfile="/run/tictactoe.pid"
output_log="/var/log/tictactoe.log"
error_log="/var/log/tictactoe.err"
Start the service:
service tictactoe start
Check uptime:
rc-status