Sign in

Reference

The hub

hub.md

Status: Plan — the build, the site, the generic skill, the deploy and reels are written; listing levels and votes are not

How this repository is published at motionhub.dev: the catalogue, the files a tool or an agent fetches, reels and the levels a motion is listed at. This is the hub's policy and distribution, not the motion format: the format is SPEC.md, and nothing here changes it.

Where things are

Path What it is
motions/@<scope>/<slug>/ One motion in the format, published by the GitHub account <scope>, id @<scope>/<slug>. Every motion on the hub has a scope; there are no unscoped, official ones. The newest version of each is the one in the main branch
tools/check.mjs The checker every pull request runs, with no dependencies: the one place the rules are written as code
bin/motionhub.mjs, tools/hub.mjs, package.json The npm package @motionhub/cli (command motionhub): check (the checker, for tools and people outside this repository), search and get (the index, and a package checked against its SHA-256 and unpacked into ./motion). A tag v<version> stages it on npm (.github/workflows/publish.yaml, trusted publishing, no token) and a maintainer approves it with npm stage approve
packages/runtime/, packages/remotion/, packages/hyperframes/ The npm packages @motionhub/runtime (what a motion's components draw with, in any engine) and its bindings for Remotion and HyperFrames. A tag <package>-v<version> stages one the same way
tools/build.mjs Builds the files below into dist/ from motions/ and the skill, refusing while any motion has an issue
brand/, tools/brand.mjs The brand: tokens (colours for both themes, type, sizes), the logo, icons, favicons and default share card, and the rules for using them (brand/BRAND.md). node tools/brand.mjs writes brand/tokens.css from the tokens
site/ The site's pages, an Astro project with its own package.json: the gallery, a page per motion and the 404 page, in the brand's tokens and self-hosted fonts. npm run build there runs tools/build.mjs into dist/, builds the pages over it and adds them, never replacing a served file
docs/, tools/docs.mjs The guides only the docs have (overview, using a motion, the command line), and the list of every docs page with the document it is. A docs page is a document where it already lives in the repository, never a copy
tools/site.mjs What the pages share with the build, with no dependencies: the Markdown a motion's documents use, its colours and faces, and _headers, robots.txt and sitemap.xml
site/player/ The reel player and its build: one page and one script per motion with a reel, under /play/<id>/
site/worker.mjs, wrangler.jsonc The Cloudflare Worker: it serves the build as static assets and the packages from the R2 bucket motionhub
.github/workflows/deploy.yml Builds, publishes each new package to R2 and deploys, on every push to the main branch and every six hours. It refuses to replace a published package
skills/motionhub/SKILL.md The generic skill: how any agent chooses a motion, fetches it and makes a film in it. /llms.txt is the same text, followed by the index of the docs

The repository keeps text, code and posters only: no video.

What motionhub.dev serves

A static site, rebuilt from the main branch whenever it changes and every six hours.

Path What it is
/ and /m/<id> The gallery and a page per motion: poster, reel, colours, faces, MOTION.md
/creators/ and /creators/<login>/ Everyone who is an author of a motion, by GitHub login in lowercase: their motions, the motions of others built on them (basedOn), and their downloads and likes
/api/motions.json The index: spec, and motions, one row per motion ordered by id, with slug (the motion's id, <slug> or @<scope>/<slug>, so a client that only knows motion/0.1 never takes one motion for another), scope (when it has one), spec (its motion's), version, name, line, lang, tags, authors, basedOn (when it has one), license, poster, tools (the directories it has for tools), package (url, sha256, bytes) and, when it has a reel, reel (the path of its player). Paths are relative to the site
/api/stats.json Each motion's downloads and likes: motions, by id, with downloads.total, downloads.last30 and likes, and generated. Kept for five minutes; see Counts below
/auth/login, /auth/callback, /auth/logout, /api/me, /api/likes/<id> Signing in with GitHub, who is signed in and what they like, and giving (POST) or taking back (DELETE) a like. DELETE /api/me forgets the person. See Likes below
/m/<id>/MOTION.md, /m/<id>/tokens.json, /m/<id>/motion.json The newest version's files, to read directly
/m/<id>/<version>.tgz The whole motion at that version, its paths under <id>/, with its SHA-256 in the index. The same files always give the same bytes
/play/<id>/ The motion's reel, playing live: its react/reel.tsx, its components, React and @motionhub/runtime in one script, with its faces. Served under a policy that lets it load nothing from anywhere else
/llms.txt For agents: what a motion is, how to choose one from the index and how to use it, then every docs page's Markdown twin
/docs/<page>/, /docs/<page>.md, /llms-full.txt The docs: the repository's own documents (SPEC.md, CONTRIBUTING.md, this file, the skill, the packages' READMEs, brand/BRAND.md) and the guides in docs/, each as a page and as Markdown, and all of them in one file. The list is tools/docs.mjs

A tool needs the index to search and one package to use a motion; it never downloads the repository. Every published package stays at its URL: the build knows only the newest versions, so the deploy adds packages and never replaces or removes one.

Reels

A motion's page plays the motion live, from its reel: react/reel.tsx, a React component that composes the motion's components and animates them by useTime() for at most 30 seconds (export const reel = {seconds} and a default export; hub.reel). It shows how the motion moves, at a brisk pace, with no narration and no story of a film. The site's build bundles each reel with its components, React and @motionhub/runtime into /play/<id>/ (site/player/build.mjs), and the page shows it in a frame sandboxed to scripts alone, with no origin of its own; /play/* is served under a content security policy that loads nothing from anywhere else and connects nowhere. A component's <Video> draws a quiet stand-in there, since the catalogue holds no footage. Its sound is synthesised in the page by @motionhub/runtime/sound from the motion's react/sound.json (hub.sound) and the reel's export const cues, off until the viewer turns it on. Its faces are the motion's own (react/fonts/) and, for the rest, Google Fonts' Latin files, copied in at build: the player fetches nothing. The player stops drawing while it is scrolled out of sight, and a reel that draws in 3D waits for a tap on a device with few cores, little memory or a touch screen. A card in the gallery shows the poster.

Listing levels

Level Means
research The text and tokens are there; no film has been made in it yet
sample One film has been made in it, by a tool whose directory it has, and its sample is published
verified Films on clearly different subjects have been made in it, and someone who did not make them has reviewed them

The hub records the level, not the motion: it can change without a new version.

Counts

motionhub counts two things, to show which motions people use: a download of a package, and a person opening a motion's page. Each is one event of what happened (download or view), the motion's id, the version (for a download) and the country Cloudflare saw the request from. Nothing else is kept: no cookie, no address, no browser, nothing that names a person, and nothing is counted on any other page. Crawlers and link previews are not counted; a command line or an agent fetching a package is.

Downloads are public at /api/stats.json and on the site. Views are not published: they are for the maintainers, to see what people look at. The events are kept by Cloudflare Workers Analytics Engine for three months; what lasts longer is each motion's number of downloads, added up once a day.

Likes

Anyone with a GitHub account can sign in and like a motion, once. Signing in asks GitHub for no permission: motionhub learns the account's public id, login, name and avatar, and does not keep GitHub's token. A session lasts 30 days in an HttpOnly cookie, and the database keeps only a hash of it. A like is public as a count; who liked what is not published. Taking a like back removes it; Forget me, in the account menu, removes the person's likes, sessions and record. Likes are kept in Cloudflare D1; the schema is site/migrations/.

Votes

A 👍 on a motion's pull request or issue counts as a vote. Votes order the gallery; they never decide what is merged.

This page is HUB.md in the repository, rendered. Suggest a change