Futuristic 5×5 letter grid word game. Drag to connect letters, race the 60-second clock, forge rare words for bonus points.
Deploy to GitHub Pages (frontend-only) or Vercel + Railway (full-stack).
- 5×5 drag-to-connect grid — touch/mouse drag, diagonal connections, no cell reuse
- Keyboard typing fallback — type letters, auto-highlights valid grid path
- 60-second timed runs with circular countdown ring
- Trie-based dictionary — 4000+ words, instant validation, prefix pruning
- Daily rotating puzzles — seeded by date, same puzzle for all players
- Scoring — length × rarity multiplier (1×/2×/5×) + speed bonus
- Grade A–F — based on % of target words found
- Achievements — 8 unlockable badges persisted in localStorage
- Personal stats — streak counter, best score, grade history
- Leaderboard API — global daily scores (requires backend)
- Dark/light mode + colorblind palette toggle
- PWA-ready — installable, offline-capable
- Particle effects — laser path trace, confetti, screen shake
wordforge/
├── frontend/
│ ├── index.html ← SPA entry point
│ ├── manifest.json ← PWA manifest
│ ├── css/
│ │ └── style.css ← Full design system (CSS vars)
│ └── js/
│ ├── puzzle.js ← Trie, word validation, puzzle generation
│ ├── renderer.js ← Canvas renderer (grid, laser, particles)
│ ├── game.js ← Core game logic, input, scoring
│ └── main.js ← UI orchestrator, modals, stats
├── backend/
│ ├── server.js ← Express API
│ └── package.json
└── README.md
No backend needed to play. Just open frontend/index.html in a browser, or deploy to GitHub Pages:
# 1. Create GitHub repo, push the /frontend folder as root
# 2. Settings → Pages → Branch: main → Folder: / (root)
# 3. Visit https://yourusername.github.io/wordforge/cd backend
npm install
npm start
# → Running on http://localhost:3001In frontend/js/main.js, set:
window.WF_API = 'http://localhost:3001';Or set it globally in index.html before the scripts:
<script>window.WF_API = 'https://your-backend.railway.app';</script>- Push
wordforge/frontend/to a GitHub repo root - Settings → Pages → main branch → root
- Done ✓
Frontend on Vercel:
npx vercel --prod
# Point root directory to: wordforge/frontendBackend on Railway:
# Push backend/ to Railway
# Set PORT env var if needed
railway upSet window.WF_API in index.html to your Railway URL.
FROM node:20-alpine
WORKDIR /app
COPY backend/ ./backend/
COPY frontend/ ./frontend/
WORKDIR /app/backend
RUN npm ci --production
EXPOSE 3001
CMD ["node", "server.js"]:root {
--bg: #050810;
--surface: #0D1520;
--text: #E0F4FF;
--cyan: #00FFDD;
--pink: #FF00AA;
}Edit WORD_LIST_RAW in puzzle.js — it's a space-separated string of all valid words.
In game.js:
const GAME_DURATION = 90; // secondsReplace the in-memory scores Map in server.js with a Supabase client:
const { createClient } = require('@supabase/supabase-js');
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY);CREATE TABLE puzzles (
date DATE PRIMARY KEY,
seed INTEGER NOT NULL,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE TABLE scores (
id SERIAL PRIMARY KEY,
user_id TEXT NOT NULL,
puzzle_date DATE NOT NULL REFERENCES puzzles(date),
score INTEGER NOT NULL DEFAULT 0,
grade CHAR(1),
words_found INTEGER DEFAULT 0,
time_left INTEGER DEFAULT 0,
submitted_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(user_id, puzzle_date)
);
CREATE INDEX idx_scores_date_score ON scores(puzzle_date, score DESC);
CREATE INDEX idx_scores_user ON scores(user_id);| Method | Endpoint | Description |
|---|---|---|
| GET | /api/puzzle/:date |
Get puzzle seed for date |
| POST | /api/score |
Submit score |
| GET | /api/leaderboard/:date |
Top 100 for date |
| GET | /api/user/:id/stats |
User stats & history |
MIT — use freely, attribution appreciated.