An interactive web-based learning platform that supports multiple types of educational activities. Intended to bring mobile activities to the web experience. Built with vanilla JavaScript and Node.js, this platform provides engaging ways to practice and assess knowledge through different interactive formats.
- π― Swipe Left or Right: Tinder-style interface for categorizing statements or concepts
- π Fill in the Blanks: Interactive forms for completing educational content
- π¦ Sort into Boxes: Drag-and-drop interface for organizing items into categories
- β¦ Matrix: Table of row labels with one radio choice per row across defined columns (see
data/examples/matrix.mdandmatrix.md)
- Clone the repository:
git clone <repository-url>
cd learn_cosmo-activities-web- Install dependencies:
npm install- Start the server:
npm start- Open your browser and navigate to:
http://localhost:3000
To quickly try every file under data/examples/ without manually copying each one into data/question.md, start the server with --examples (or use npm run examples):
npm run examples
# equivalent: node server.js --examplesThen open http://localhost:3000/. You get a split layout: a searchable list of example markdown files on the left, and the main activity app in an iframe on the right (loaded from /play). When you pick an example, the server copies that file to data/question.md and the iframe reloads so /api/activity reflects the new content.
This mode is intended for local development and QA only. The same static assets and activity APIs apply as in normal mode; only the root route and the extra example APIs are added (see API Endpoints below).
Any activity can render side content in a split layout by adding a __Content__ section. The activity UI appears on the right and the side content on the left, with a draggable divider between them. __Content__ accepts three forms:
| Form | First line of __Content__ |
Use case |
|---|---|---|
| External URL | https://example.com/docs |
Embed external documentation, datasets, web tools, etc. |
| Inline markdown | Any markdown block (no URL on the first line) | Reference tables, formulas, hints, glossaries β rendered inline. |
| Site-relative URL | /sim/ (or any path starting with /) |
Embed a simulation hosted by this server (split-screen mode β see below). |
Optional modifiers on the same line / block:
[contentWidth: 50%]or[contentWidth: 320px]β initial width of the left pane (defaults to 40%).[openInNewTab]β adds a toolbar button to open the URL in a new tab (URL forms only).
Examples are in data/examples/:
mcq-with-url-content.md,text-input-with-url-content.mdβ external URLtext-input-with-markdown-content.md,side-content-markdown-table.mdβ inline markdown
A site-relative URL form (/sim/...) lets you embed a simulation-as-content that runs as a separate process alongside the activity server. The activity server reverse-proxies the simulation under /sim/ so the iframe can load it with a relative URL
Enable the proxy by setting SIM_ORIGIN to the simulation's HTTP origin and starting the activity server normally:
# 1. Start your simulation on a different port (example: 3001)
PORT=3001 ./run-your-sim.sh &
# 2. Start the activity server with the proxy enabled
SIM_ORIGIN=http://127.0.0.1:3001 npm startIn your activity's __Content__ section, reference the simulation with a site-relative path under the mount point:
__Type__
Multiple Choice
__Content__
/sim/ [contentWidth: 50%]
__Practice Question__
...The iframe loads from https://<preview-host>/sim/, which the activity server forwards to SIM_ORIGIN. Static assets and APIs the simulation requests at root paths (/assets/*, /configs/*, /api/logs) are forwarded too β these defaults match common simulation layouts but can be overridden.
| Variable | Default | Purpose |
|---|---|---|
SIM_ORIGIN |
(unset β proxy disabled) | HTTP(S) origin of the simulation backend, e.g. http://127.0.0.1:3001. When unset, the activity server behaves exactly as before (no proxy). |
SIM_ROOT_PROXY_PATHS |
/assets/,/configs/,/api/logs |
Comma-separated list of root-absolute paths the simulation expects to serve directly. Override when integrating a simulation that uses a different layout. Avoid listing paths that collide with the activity server's own routes (/api/activity, /api/results, /design-system/*, etc.). |
The proxy supports HTTP and HTTPS upstreams (transport is chosen automatically from SIM_ORIGIN's scheme) and forwards query strings, request methods, and bodies.
SIM_ORIGIN is opt-in. If it is not set, the activity server serves only its own routes and no requests are forwarded β the runtime behaves identically to previous versions.
learn_cosmo-activities-web/
βββ data/ # Activity content and results
β βββ question.md # Current activity definition
β βββ answer.md # Stored activity results
β βββ examples/ # Example activity formats
β βββ fill-in-the-blanks.md
β βββ matrix.md
β βββ sort-into-boxes.md
β βββ swipe-left-right.md
βββ public/ # Frontend assets
β βββ index.html # Main HTML file
β βββ examples-mode.html # Examples picker shell (served at / when using --examples)
β βββ app.js # Main application logic
β βββ styles.css # Application styles
β βββ modules/ # Activity-specific modules
β βββ fib.js # Fill-in-the-blanks functionality
β βββ sort.js # Sort-into-boxes functionality
β βββ swipe.js # Swipe functionality
βββ server.js # Node.js server
βββ package.json # Dependencies and scripts
βββ README.md # This file
Activities are defined using Markdown files with a specific format. Place your activity definition in data/question.md.
GET /api/activity- Retrieves the current activity fromdata/question.mdPOST /api/results- Saves activity results todata/answer.md
When the server is started with --examples:
GET /api/examples/list- Returns{ "examples": [ "file.md", ... ] }(sorted basenames ofdata/examples/*.md)POST /api/examples/select- Body:{ "filename": "mcq.md" }. Copies that file fromdata/examples/todata/question.md(basename must match a safe pattern). Response:{ "success": true, "filename": "..." }or an error object.
When SIM_ORIGIN is set (split-screen mode):
ANY /sim/*- Reverse-proxied toSIM_ORIGINwith the/simprefix stripped (e.g./sim/foo?x=1βSIM_ORIGIN/foo?x=1).ANY <path>where<path>matchesSIM_ROOT_PROXY_PATHS- Reverse-proxied toSIM_ORIGINunchanged. Used for simulation static assets and APIs that live at root paths.
The application uses vanilla JavaScript with ES6 modules. The server automatically serves files from the public directory and provides API endpoints for activity management.
- app.js: Main application orchestrator
- modules/swipe.js: Handles swipe-based interactions
- modules/fib.js: Manages fill-in-the-blank activities
- modules/sort.js: Implements sorting functionality
- server.js: Express-like HTTP server with markdown parsing
- marked: Markdown parsing library for activity content