This is the active planning board: things still to do. Site architecture,
design patterns, the chat-to-PR workflow, and history of shipped work
live in CLAUDE.md at the repo root.
When work is shipped or new items are identified, both files should be
updated in the same PR.
Re-enable local development against the live API
Dev experienceThe single-server consolidation replaced full URLs (https://data.orcsgirls.org/api/...) with relative paths (/api/...). This is correct for production but breaks local development — running the static frontend on localhost:8000 makes fetch('/api/...') hit localhost:8000/api/... which 404s.
Fix: introduce /api-base.js at the repo root that sets window.API_BASE based on hostname detection.
// /api-base.js
window.API_BASE = (function () {
var h = location.hostname;
return (h === 'localhost' || h === '127.0.0.1' || h === '' || h.endsWith('.local'))
? 'https://play.orcsgirls.org'
: '';
}());
Production hostname → empty string (relative paths preserved, no behaviour change). Localhost / 127.0.0.1 / .local → full URL to live API.
Then each fetch('/api/...') becomes fetch(API_BASE + '/api/...'). Touch points (about 10 files):
access.jsadmin/_admin-common.js (in apiGet / apiPost helpers)admin/submissions.htmlquiz/index.htmlquiz/host.htmlquiz/js/quiz-client.jsweb/showcase.htmlweb/editor.htmlweb/js/unicode-names.jsscience/js/Fourdem.jsAdd <script src="/api-base.js"></script> in <head> of every page that makes API calls — load it next to theme-init.js for consistency.
PHP side: no changes needed. api/_db.php already includes http://localhost, http://localhost:80, http://localhost:8000, and http://127.0.0.1 in its CORS allowlist (lines 18–24). The previous CORS audit during single-server consolidation kept these in deliberately.
Note: this work will eventually fold into the planned shared/api.js module (Code Reuse Step 4 in CLAUDE.md). The minimal api-base.js version is a faster path to unblock local dev now; the full module can absorb it cleanly when that refactor happens.
Quiz — Scoring Enhancements
IdeasCurrent scoring: 500 + round(500 × time_remaining / time_limit). Two natural extensions:
quiz_responses.answered_at — no schema change needed, just a COUNT(*) of prior correct responses at submit time in answer.php.streak column on quiz_players (or computed per-player from quiz_responses at answer time). Rewards consistency; good as an opt-in mode since it changes the feel of the game significantly.Quiz — Additional Question Types
Ideasquestion_type flag for the display layer.quiz_answers (not just quiz_questions).Quiz — Image Annotation Tools
IdeasThe crop modal canvas is a natural foundation for lightweight annotation. After cropping, teacher could switch to an "annotate" mode to add:
Annotations would be rendered onto the canvas and baked into the JPEG at confirm time — no additional storage schema needed. The canvas-based architecture already supports this; it's purely a UI addition to the crop modal.
Quiz — Analytics & Results Export
Ideasquiz_responses — it's a display feature.quiz_responses across sessions by question_id.Quiz — Content & Workflow Improvements
IdeasLogic Gate Simulator — Extension Ideas
IdeasSite-wide — Code Organisation & Layout Review
Low PriorityTwo layout patterns exist. Pages still needing migration to the sidebar (.tool-split) pattern: data/terminal.html, data/plotter.html, cyber/logic-gates.html. Leave as-is: cyber/binary.html (intentional full-screen), fun/dice.html (acceptable for simplicity).
nav.js injection would reduce maintenance surface..toolbar-purple, .toolbar-btn, .ctrl-label, .ctrl-sel etc. duplicated across 5+ tools — consolidate into style.css._admin-common.js — good model to follow for future admin pages.cyber/binary.html (~625 lines) → cyber/js/binary.jscyber/logic-gates.html (~820 lines) → cyber/js/logic-gates.jsfun/button-maker.html (~820 lines) → fun/js/button-maker.jsfun/element-name.html (~760 lines) → fun/js/element-name.jsButton Maker — Remaining Ideas
IdeasCyber — Password Crack Time Visual Simulator
PendingStandalone companion to the existing Password Strength Checker. Visual timeline of crack times at multiple attack speeds; adjustable inputs (length, character pool, entropy bits). Link from cyber/password.html.
Science — Fourier Camera Improvements
PendingDrawing Pad — Stamps & Mobile Testing
Pendingfun/stamps/ with paired red/cyan PNGs + manifest.json; loadStamps() fetches manifest — no base64 in source.Separator Generator — Extension Ideas
Ideasbackground-repeat:repeat-x)Web Showcase — Future Improvements
IdeasInternet of Things — Particle IoT Tools
Low PriorityMigrate existing Particle IoT tools into the site. Suggested location: new iot/ section with hub page + nav item. Owner will provide files when ready.
The items below are open. Completed bugs from earlier sessions are recorded in CLAUDE.md's history section. Lettering gaps (a–c, e–h) are intentional — those items are closed and the letters are kept stable so commit history and earlier conversations still resolve.
(d) quiz/index.html does not load access.js — by design
None of quiz/index.html, quiz/play.html, or quiz/host.html include access.js. This is intentional: students should be able to scan the lobby QR code and join a quiz from any device without first holding a class code that day. Documented here so the next person doesn't add the gate by mistake. The other security layers (per-session PIN, host-token auth, rate-limited join.php, content scanner on nicknames) cover the quiz path independently.
(i) Quiz pages do not honour ?mode=standalone
standalone.js is not loaded on any quiz page. The player view is already chrome-light by design, so this may be intentional, but worth a note in the patterns section so the next person doesn't try to embed a quiz in standalone mode and wonder why the nav is still there. (The host page has a nav-like bar that standalone.js would not currently target either.)
| Item | File | Status | Notes |
|---|---|---|---|
science.css consolidation |
science/science.css |
⚠️ Pending | Some Fourier Camera styles still inline in fourier-camera.html |
| Quiz image storage in DB column | quiz_questions.image_data |
Minor | Base64 JPEG stored as MEDIUMTEXT (~1 MB limit). Works well for current use. If larger images or better performance become needed, move to file system storage (UUID filename, serve via separate endpoint, store URL in DB instead). Would require an upload endpoint, file permissions, and cleanup logic for orphaned files. |
| Server-side question timer | api/quiz/advance.php |
Minor | Timer only auto-advances when the host screen is open and polling. If the teacher closes the browser mid-question, the question never auto-advances — players are stuck. Fix: a server-side cron job or a lazy check in state.php that auto-advances if question_started_at + time_limit < NOW(). |
| Quiz session cleanup | quiz_sessions table |
Minor | Ended and abandoned sessions accumulate indefinitely. Add a scheduled cleanup (cron or lazy in start.php) to archive sessions older than 30 days. quiz_responses and quiz_players cascade-delete, so only the session rows need pruning. |
admin/quiz.html size |
admin/quiz.html |
Minor | ~550 lines including the full crop modal JS. Consider extracting to admin/js/quiz-builder.js and admin/js/crop-modal.js when the file is next substantially modified. |