paces
Turn instructional media into structured, interactive learning material. Put it through its paces.
Take a video of someone teaching something — a dance routine, a kata, a
recipe — plus, optionally, notes and a steering prompt. paces segments it
into named steps, builds a structured step document (an AST for
step-by-step instruction), and renders that into learning material: a
practice page with counts and deep links today, other guides later.
pip install paces
Quick example
from paces import segment, to_document, render_html
seg = segment(
"https://youtu.be/q_TUyxUhoEw",
steps=[
("Mise en place", 2),
("Pas pieds pointe et ronde", 6),
("Soleil avec les bras", 4),
("Déhanchés", 8),
],
grid={"unit": "eight", "subdivisions": 8, "tempoBpm": "129.2", "origin": "51.2"},
)
doc = to_document(
seg,
doc_id="que-calor",
title="Chorégraphie Que Calor",
source="https://youtu.be/q_TUyxUhoEw",
)
open("page.html", "w").write(render_html(doc))
The page lists every step with its counts, links each one back into the video (both the at-tempo run-through and the slow breakdown, when both are known), and — because the document carries a metric grid — includes a count-along transport that paces you through the routine at the measured tempo.
Same thing from the shell:
paces segment VIDEO_URL --steps steps.json --grid grid.json --output seg.json
paces to-document seg.json --source VIDEO_URL --title "My routine" --output document.json
paces suggest-excerpts document.json --output document.json # mark each block's loop window
paces derive document.json --media routine.mp4 # real loop clips + gifs + posters
paces render document.json --output page.html
derive (pip install paces[media]) cuts a loopable mp4, a palette-quality
gif and a poster for every excerpt-bearing span, writes them to media/ next
to the document, and the practice page embeds them as looping clips. Crop
recipes persist in a hand-overridable document.recipes.json sidecar; the
subject_locator= seam (default: no crop) is where pose-based auto-crop
plugs in. Design record: docs/adr/0005-media-derivation.md.
How it thinks
Analysis and rendering are separate phases with a serialisable document between them — like a parser emitting an AST and a backend interpreting it. Renderers depend on the document, never on the analyser.
Segmentation is a seam, not a stage. segment(media, segmenter=...) —
segmenters are registered capabilities, the default follows from what is
present, and "the user typed the boundaries" is a first-class segmenter, not
a fallback. A segmenter that cannot name steps returns honest unnamed
boundaries (flags: ['naming-abstained']) rather than inventing names.
The document keeps what the learner actually counts. A dance step lasts
"4 eights", not "14.86 seconds" — seconds are derived from the metric grid
(tempo + origin), never stored. A step can have several source spans (the
run-through and the breakdown are the same step seen twice). Uncertainty is
content (OpenQuestion), and human edits are protected from regeneration
(Lock).
The pieces
| you want | reach for |
|---|---|
| cut media into steps | segment(media, steps=..., grid=...) → Segmentation |
| explicit/human boundaries | segment(media, boundaries=[...], steps=[names]) |
| use the video's own chapters | segment(media, metadata=<yt-dlp info.json>) |
| measure the grid from the media | segment(local_media, steps=[(name, counts), ...]) — no grid needed; tempo + structure measured, origin estimated and flagged (pip install paces[audio]) |
| protect edits from regeneration | apply_edits(doc, patches, by="user:you") + merge_regenerated(committed, fresh) |
| the committed artifact | to_document(seg, ...) → StepDocument |
| real clips/gifs/posters for the page | derive_document(doc, media=..., doc_path=...) / paces derive (pip install paces[media]) |
| a practice page | render_html(doc) |
| wall-clock times from counts | resolve(doc) |
| sanity checks | validate_document(doc) |
| what segmenters exist | capabilities() / paces list-segmenters |
| add a segmenter | register(Capability(name=..., gives="segmentation", target="mymod:fn", needs={...})) — a new file, nothing edited |
Status
Young and moving. The document schema is validated by round-tripping a real
proof of concept (an interactive dance-practice
page) through it — see
tests/test_roundtrip_poc.py. Media derivation (auto-cropped looping clips),
intrinsic segmenters (scene/beat/speech detection), and the evidence layer
are designed (see docs/) and arrive next.
Metadata
Release files for paces 0.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| paces-0.0.7.tar.gz | 96.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| paces-0.0.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 154.2 kB
Release files / paces-0.0.7.tar.gz
| Download URL | paces-0.0.7.tar.gz |
|---|---|
| Size | 96.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c57293a793d52a4098b3468e9f513ecc636ad91b96b8ebc983b20d3c77f7f493
|
|
BLAKE2b-256 checksum How to use checksums |
b709fd18ae4a23b301cbb832218bd5dbcb8ca06e486ec7af6fa5fd05c570bfe9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / paces-0.0.7-py3-none-any.whl
| Download URL | paces-0.0.7-py3-none-any.whl |
|---|---|
| Size | 58.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7d34d4437d7b48c1e3154da29f62b50908f4bad301e31e5a6425c95ab9eb0617
|
|
BLAKE2b-256 checksum How to use checksums |
ec6d51714613fd13c334e2e42e090ba918fd38bddb6a1c8d376295bfedb6a06e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|