Video metadata (schema.org · IIIF · provenance)
ecmanim knows a video’s structure at render time — duration, dimensions, and
the scene’s nextSection() boundaries — so it can emit the web’s video metadata
standards directly, without reverse-engineering them from a file.
- schema.org
VideoObject(JSON-LD) — discovery: “what is this video?” - IIIF Presentation 3.0 Manifest — presentation/navigation, with chapters
derived from
nextSection(): “how do I view and move through it?” - provenance sliver — “generated by ecmanim” + the IPTC digital-source-type for algorithmic media.
These are export adapters that read from the render result (and scene
sections); there is no second normalized model. resolveIIIFVideo is the one
importer, used by VideoMobject to ingest an IIIF-described clip. All of it is
isomorphic (no Node/DOM at import) and exported from ecmanim.
The input
Section titled “The input”Every function takes a VideoMetaInput — supply what you have; unknown fields
are omitted. A Node render() result carries most of it:
import { render, toVideoObject, toIIIFManifest } from "ecmanim/node";
const r = await render(MyScene, { output: "demo.mp4", fps: 30 });// r = { output, frames, fps, pixelWidth, pixelHeight, sections, ... }
const input = { frames: r.frames, fps: r.fps, width: r.pixelWidth, height: r.pixelHeight, sections: r.sections, // -> chapters (from nextSection()) id: "https://example.org/demo", // canonical IRI contentUrl: "https://example.org/demo.mp4", name: "Demo", description: "…", uploadDate: "2026-07-02", encodingFormat: "video/mp4", provenance: true, // adds the ecmanim creator + IPTC term};durationSeconds may be given directly instead of frames/fps. Chapters come
from sections (a SceneSection[]), or pass explicit chapters to override.
schema.org VideoObject
Section titled “schema.org VideoObject”const jsonld = toVideoObject(input);// { "@context":"https://schema.org", "@type":"VideoObject", name, duration:"PT…",// contentUrl, width, height, hasPart:[{ "@type":"Clip", … }], creator:{…}, … }
// or a ready-to-embed <script> tag:import { toVideoObjectScript } from "ecmanim";page.head += toVideoObjectScript(input);Chapters become hasPart Clips (Google understands these as key moments).
provenance adds a creator SoftwareApplication and an additionalProperty
carrying the IPTC digital-source-type.
<manim-player> auto-injection
Section titled “<manim-player> auto-injection”The Web Component injects the JSON-LD for you when you set metadata (off
otherwise):
const player = document.querySelector("manim-player");player.metadata = { name: "Demo", contentUrl: "demo.mp4", provenance: true };// -> one <script type="application/ld+json"> child; width/height/fps/duration are// filled from the player automatically. Also: player.getVideoObject().IIIF Presentation 3.0 Manifest
Section titled “IIIF Presentation 3.0 Manifest”const manifest = toIIIFManifest(input);Produces a v3 Manifest → Canvas (duration, width/height) → painting Annotation
whose body is a Video resource. nextSection() boundaries become
structures Ranges targeting temporal fragments (…/canvas/1#t=0,2), i.e.
real chapters a IIIF viewer can navigate. provenance adds a metadata block.
IIIF ingest → VideoMobject
Section titled “IIIF ingest → VideoMobject”loadVideo (Node and browser) accepts a IIIF manifest — an already-parsed
object, or a URL with { iiif: true } — resolves the video body URL, and
attaches the manifest’s chapters to the returned mobject:
import { loadVideo } from "ecmanim/node"; // or "ecmanim/browser"
const clip = await loadVideo(manifest, { fps: 30 }); // object formconst clip2 = await loadVideo(manifestUrl, { iiif: true }); // fetch + parseclip.chapters; // [{ label, start, end }, …] from the manifest's structuresNode reads the resolved URL through ffmpeg (local paths or remote http); remote
URLs are cached by URL (no mtime). resolveIIIFVideo(manifest) is exported if
you want the parsed { url, width, height, duration, chapters } directly.
Scope (honest limits)
Section titled “Scope (honest limits)”- Export-first. VideoObject + IIIF are generated from the render/scene; there
is no round-trip metadata compiler in core.
resolveIIIFVideois the only importer (for ingestion). - IPTC Video Metadata Hub is represented only by the provenance sliver (generator + digital-source-type); the full VMH property set is out of scope.
- Getting manifests validator-clean for a specific viewer may need viewer-specific
tweaks (thumbnails,
rendering, rights) — extend the returned object as needed.