# Galvoro Capsule Specification — Contributor Guide
 
*This document is what you (or your AI coding assistant) need to know to build a valid Galvoro capsule. Place it in your capsule's folder before starting work.*
 
**Version:** 1.0
**Last updated:** May 2026
 
---
 
## 1. What is a capsule?
 
A **capsule** is a small, self-contained HTML mini-app designed for higher education. It teaches or demonstrates a single concept (or a small set of closely related concepts) in an interactive way. Capsules are hosted on the Galvoro platform and can be embedded in lecture slides, course pages, or personal sites.
 
Each capsule is served from its own subdomain (`<slug>.capsules.galvoro.app`) and runs inside a sandboxed browser origin.
 
---
 
## 2. The three rules
 
Every capsule must follow these:
 
1. **Tied to a concept in higher education.** Pointless games, generic puzzles, or content unrelated to learning don't fit the platform.
2. **Short and focused.** Galvoro is not the place for lecture slides, textbooks, or hour-long lessons. Capsules are interactive components designed to fit *between* or *alongside* a lecture — not replace it.
3. **Self-contained at runtime.** Capsules may use approved third-party libraries and fonts (see §5), but cannot call external APIs, services, or analytics. No outbound requests to non-allowed origins. No persistent storage between sessions — each visit starts fresh.
---
 
## 3. File structure
 
A capsule is a folder containing:
 
```
my-capsule/
├── index.html         (required — entry point)
├── capsule.json       (required — metadata manifest)
├── cover.png|webp     (optional — square cover image)
├── style.css          (any name, any number)
├── script.js          (any name, any number)
├── assets/            (any structure)
│   ├── images/
│   ├── fonts/
│   └── data.json
└── ...
```
 
**Rules:**
- `index.html` must be at the root.
- All asset references must be **relative** (e.g. `src="assets/image.png"`, not `src="/assets/image.png"` or absolute URLs).
- No `<base>` tag pointing outside the capsule.
- File and folder names: lowercase, alphanumeric + hyphens + underscores. No spaces.
---
 
## 4. `capsule.json` manifest
 
Every capsule must include a `capsule.json` file at the root. This is how Galvoro knows about the capsule's metadata.
 
### Schema
 
| Field | Required | Description |
|---|---|---|
| `title` | yes | Short display name. |
| `subtitle` | no | One-line tagline. |
| `type` | yes | One of `PLAY_LEARN`, `EXPLAIN`, `EXPLORE`, `TEACH`, `STUDY`, `MISC` (see §7). |
| `level` | yes | One of `lower_undergrad`, `upper_undergrad`, `postgrad`. |
| `domain` | yes | Array of one or more top-level domains. Must come from §8. |
| `field` | no | Array of fields. Optional. Must come from §8 if provided. |
| `subdiscipline` | no | Array of finer-grained tags. Optional. Must come from §8 if provided. |
| `mode` | yes | One of `desktop`, `mobile`, `both`. Must match the capsule's actual layout. |
| `course` | no | Originating course code or name. |
| `keywords` | yes | Array of content keywords for search. 3–10 keywords recommended. |
| `learning_goals` | yes | **Exactly three** short statements of what the capsule teaches. |
| `creator` | yes | Author name (or names). |
| `institution` | yes | Author affiliation. |
| `notes` | no | Free-text creation notes. |
| `external_link` | no | URL to author's institution page or original site. |
| `doi` | no | DOI when available. |
| `license` | yes | SPDX identifier from the allowlist in §9. |
 
### Worked example
 
```json
{
  "title": "Sampling Distributions",
  "subtitle": "How a sample mean varies from sample to sample.",
  "type": "EXPLAIN",
  "level": "lower_undergrad",
  "domain": ["Interdisciplinary"],
  "field": ["Research Methods"],
  "subdiscipline": ["Quantitative methods"],
  "mode": "both",
  "course": "PL2132 Research Methods",
  "keywords": ["sampling", "standard error", "central limit theorem", "mean"],
  "learning_goals": [
    "Define a sampling distribution.",
    "Compute the standard error of the mean.",
    "Distinguish a sample from a population."
  ],
  "creator": "Jane Doe",
  "institution": "National University of Singapore",
  "license": "CC-BY-4.0"
}
```
 
---
 
## 5. Allowed external resources
 
Capsules may load from these origins **only**:
 
### Scripts
- `https://cdnjs.cloudflare.com`
- `https://cdn.jsdelivr.net`
- `https://unpkg.com`
### Stylesheets and fonts
- `https://fonts.googleapis.com`
- `https://fonts.gstatic.com`
- The script CDNs above (for CSS hosted via jsDelivr etc.)
### Media
- Images, video, audio: any HTTPS source is allowed for `<img>`, `<video>`, `<audio>`, etc., but **bundle media in your capsule whenever possible**. External media references can break if the source goes offline.
### Frames
- Capsules may embed `https://www.youtube-nocookie.com` (privacy-preserving YouTube) iframes.
**Bundling is always preferred over CDN-loading.** Smaller, more reliable, no third-party dependency. Use CDNs only when bundling a large library (e.g. GSAP, KaTeX) would bloat the capsule unnecessarily.
 
---
 
## 6. Forbidden patterns
 
Capsules **must not**:
 
- Make `fetch()` or `XMLHttpRequest` calls to any origin not in §5.
- Load analytics scripts (Google Analytics, Plausible, Matomo, Mixpanel, etc.).
- Use `eval()`, `new Function(string)`, or dynamic `<script>` injection from untrusted strings.
- Depend on storage persisting between sessions. `localStorage`, `sessionStorage`, `IndexedDB`, and cookies are available for in-session state — see §11 for the scoping rules — but the capsule must function correctly on a fresh visit with no prior state.
- Submit forms to external endpoints (`<form action="https://...">` to anything outside §5).
- Use `window.parent` or `window.top` to communicate with the embedding page.
- Use `postMessage` to send sensitive data.
- Open WebSocket connections.
- Request geolocation, camera, microphone, USB, serial, Bluetooth, or other restricted device APIs.
- Implement multiplayer or real-time synchronization (the platform doesn't yet support this).
- Implement classroom-mode features that require a separate lecturer view and student view (also not yet supported).
Capsules that violate these will fail automated checks at upload time and will not be published.
 
---
 
## 7. Capsule types
 
The `type` field in `capsule.json` is one of:
 
| Type | Description |
|---|---|
| `PLAY_LEARN` | Pick-up-and-play games built around a concept in higher education. The LEARN module explains the underlying idea, but the capsule is first and foremost a game. |
| `EXPLAIN` | Animated mini-apps that explain a single concept or a few closely related concepts. Mostly non-interactive — the user reads or watches rather than manipulates. |
| `EXPLORE` | Explorable explanations: longer-form interactive lessons combining narrative with manipulable elements. The interaction *is* the lesson. |
| `TEACH` | In-class activities run by a lecturer or tutor — short games, quizzes, or interactive prompts in the spirit of Kahoot. Designed for synchronous group use. |
| `STUDY` | Tools for studying or self-testing — flashcards, practice problems, exam-prep aides. Mostly MCQ-driven. |
| `MISC` | Default for anything that doesn't fit the above. |
 
**Note:** Uploaded capsules are categorized as `MISC` until a Galvoro admin verifies that the requested type fits the capsule. If you submit a capsule as `PLAY_LEARN` but it has no game element, an admin may reclassify it.
 
The boundary between `EXPLAIN` and `EXPLORE` is intentionally fuzzy — length and depth of the lesson are the deciding factors more than the presence of any interactive element.
 
---
 
## 8. Taxonomy
 
Capsules are tagged at one or more levels of a three-level hierarchy: **Domain → Field → Subdiscipline**. Tag at the most specific level you're confident about. Tagging at a deeper level automatically counts as tagging at all parent levels (e.g. tagging "Cognitive psychology" implies "Psychology" implies "Social Sciences").
 
Use the names below **exactly** as written. Names are case-insensitive but consistent casing is preferred.
 
### Social Sciences
 
- **Communication Sciences** — Health communication · Interpersonal communication · Media studies · Organizational communication · Rhetoric
- **Economics** — Behavioral economics · Development economics · Econometrics · Macroeconomics · Microeconomics
- **Education** — Curriculum studies · Educational psychology · Higher education research
- **Geography** — Geographic information science · Human geography · Physical geography
- **Political Science** — Comparative politics · International relations · Political theory · Public policy
- **Psychology** — Biological psychology and cognitive neuroscience · Clinical science and psychopathology · Cognitive psychology · Developmental psychology · Quantitative psychology · Social and personality psychology · Work and organizational psychology
- **Sociology** — Cultural sociology · Demography · Economic sociology · Political sociology · Urban sociology
### Humanities
 
- **History** *(no subdisciplines — use keywords for period and region)*
- **Linguistics** — Historical linguistics · Phonetics · Psycholinguistics · Semantics · Sociolinguistics · Syntax
- **Philosophy** — Epistemology · Ethics · Logic · Metaphysics · Philosophy of mind · Philosophy of science · Political philosophy
### Interdisciplinary
 
- **Complexity Science** — Agent-based modeling · Dynamical systems · Network science · Scaling
- **Research Methods** — Correlational research · Experimental research · Meta-science · Qualitative methods · Quantitative methods
**If your capsule doesn't fit:** tag at the closest available level (just `domain` is fine) and mention the gap in the `notes` field. Admins extend the taxonomy when new content surfaces a need.
 
---
 
## 9. Licenses
 
The `license` field must be one of the following SPDX identifiers:
 
- `CC-BY-4.0` — Creative Commons Attribution 4.0
- `CC-BY-SA-4.0` — Creative Commons Attribution-ShareAlike 4.0
- `CC-BY-ND-4.0` — Creative Commons Attribution-NoDerivatives 4.0
- `CC-BY-NC-4.0` — Creative Commons Attribution-NonCommercial 4.0
- `CC-BY-NC-SA-4.0` — Creative Commons Attribution-NonCommercial-ShareAlike 4.0
- `CC-BY-NC-ND-4.0` — Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
- `CC0-1.0` — Public domain dedication
- `MIT`
- `Apache-2.0`
- `BSD-3-Clause`
- `BSD-2-Clause`
**Choosing a license:**
- For maximum reach and reuse, pick `CC-BY-4.0` (academic content) or `MIT` (code-heavy capsules).
- The `ND` (NoDerivatives) variants will block other educators from forking and adapting your capsule on Galvoro. Consider whether you want to allow that.
- `CC0-1.0` waives all rights and lets anyone do anything. Use sparingly.
The license is declared at submission and cannot be changed retroactively.
 
---
 
## 10. Cover image (optional)
 
You may include a square cover image as `cover.png` or `cover.webp` at the root of your capsule folder.
 
- **Aspect ratio:** 1:1 (square)
- **Recommended size:** 1080×1080 px or larger
- **Format:** PNG or WebP (WebP preferred for smaller file size)
- **Content:** Anything that visually represents the capsule. Can include the title as part of the design.
If no cover image is provided, Galvoro generates a placeholder using the capsule's Type color and title.
 
---
 
## 11. How your capsule will be hosted
 
When your capsule is approved and published:
 
1. The folder contents are uploaded to Cloudflare R2 storage.
2. Galvoro serves the capsule from `https://<your-slug>.capsules.galvoro.app/`.
3. The capsule runs inside a sandboxed browser origin — completely isolated from `galvoro.app` and from other capsules.
4. A strict Content Security Policy (CSP) is applied. The CSP enforces the allowed resources from §5 and blocks the forbidden patterns from §6.
**Per-capsule storage isolation.** Because each capsule runs on its own subdomain, the browser treats it as a distinct origin. This means `localStorage`, `sessionStorage`, `IndexedDB`, and cookies set by your capsule are scoped to your capsule alone — another capsule cannot read or modify them, and your capsule cannot read theirs. You may use these APIs freely for in-session state. Just remember the §6 rule: don't *depend* on prior-session data being present on a return visit.
 
If your capsule depends on resources outside the allowlist, it will silently fail to load them under the CSP. Test your capsule locally first by serving it from a simple HTTP server (e.g. `python3 -m http.server`) and checking the browser console for CSP errors.
 
---
 
## 12. Submission and review
 
When you're ready:
 
1. Create an account on `galvoro.app`.
2. Go to the **Upload a capsule** page.
3. Upload your capsule folder as a `.zip` (or connect a GitHub repo).
4. Your capsule enters the **sandbox** state — visible only to you, awaiting review.
5. A Galvoro admin reviews it for the three rules, capsule.json validity, and type-tag fit.
6. If approved, it's published and appears in the catalog at the URL above.
Reviews typically complete within a few business days. If something needs to change, the admin will leave notes and you can update the capsule before resubmitting.
 
---
 
## 13. Current platform limits (V1)
 
As of May 2026, Galvoro does not yet support:
 
- Multiplayer or real-time synchronization between users
- Persistent storage between sessions (each visit starts fresh)
- Classroom modes with separate lecturer and student views
- In-capsule analytics or user tracking
- Capsule-to-capsule communication
- AI-powered features inside capsules (planned for v2)
These are on the roadmap for later releases.
 
---
 
*Galvoro is a platform for hosting and sharing capsules — small interactive learning experiences for higher education. Learn more at [galvoro.app](https://galvoro.app).*