GeoGazette

The packages

Five packages on npm. One reads and writes stories, one draws them, and the rest matter only if you are building a host that executes them.

This website uses the same published packages you would — nothing here runs against a private build.

@openverb/geostorystart here

The geographic profile. Parse, validate, serialise, compile.

@openverb/motionnew

Draws a document. Frames, video, and a linter.

@openverb/format

The .ov document format itself, and the bridge to the runtime.

@openverb/runtime

Executes verbs. Handlers and adapters.

@openverb/sdk

Client for calling a runtime from a browser or a server.

@openverb/geostory

The one most people want. It reads and writes .ov files in the geostory profile, validates them against the JSON Schema, and compiles scenes into verb actions.

npm install @openverb/geostory
import {
  parseGeoStory,
  validateGeoStory,
  serializeGeoStory,
  compileTimeline,
} from "@openverb/geostory"

const doc = parseGeoStory(await fs.readFile("story.ov", "utf8"))

const { valid, errors } = validateGeoStory(doc)
if (!valid) throw new Error(errors.join("\n"))

// What a renderer actually plays
const timeline = compileTimeline(doc)

// Back out again, unknown fields intact
await fs.writeFile("story.ov", serializeGeoStory(doc))
ExportWhat it does
parseGeoStory(text)YAML or JSON to a typed GeoStoryDocument. Throws GeoStoryParseError.
parseGeoStoryRaw(text)The same, without profile validation.
serializeGeoStory(doc)Back to YAML, preserving unknown fields.
serializeGeoStoryToYAML(doc)Explicit YAML.
serializeGeoStoryToJSON(doc)Explicit JSON.
validateGeoStory(doc){ valid, errors } against the JSON Schema.
isGeoStoryDocument(value)Type guard.
compileToOVDocument(doc)Scenes to a full OVDocument of verb actions.
compileTimeline(doc)Just the flattened action timeline.
compileScene(scene, doc)One scene's actions.
GEOSTORY_SCHEMAThe JSON Schema object.
verbLibraryThe verb definitions this profile emits.
VERB_CATEGORIESVerb category names.
GeoStoryParseErrorThrown by the parsers.

Types are exported for every part of a document — GeoStoryDocument, GeoStoryScene, GeoStoryPlace, GeoStoryCamera, GeoStoryTiming and the rest.

One thing to know if you are writing a tool: the serializer preserves fields it does not recognise, and that is a guarantee you can rely on. Do not round-trip a document through JSON.parse / JSON.stringify of your own model — you will silently drop whatever your model does not represent, which is the one thing the format promises never happens.

@openverb/motion

The other half of the pair. geostory tells you whether a document is well-formed; this one puts it on a canvas. Nothing in it parses, which is the point — a host can adopt the format without adopting a renderer, or write its own and still read everybody's documents.

npm install @openverb/motion
ExportWhat it does
renderFrameA document and a time in, a drawn canvas out. The one most hosts want.
exportVideoA run of frames into an MP4. Needs WebCodecs and the optional mediabunny peer.
canExportWhether this browser can encode, so you can decide before offering the button.
totalDurationHow long the document runs, including audio that outlasts the last scene.
sceneWindowsEvery scene with its absolute start and end.
drawAnnotations / drawFlow / drawChartThe drawing layer, for a host that owns its own frame loop.
canvasProjector / canvasBoxPercentages of the frame, and the 16:9 box they are read against.
lintGeoStoryFaults a document can have while parsing and validating perfectly.

The timing, geometry and linting halves are pure and run under Node, so a document can be checked in CI without a display. renderFrame needs a canvas and exportVideo needs WebCodecs.

Motion is not a second format. A document whose annotations are addressed in canvas space, with no basemap, is still a GeoStory document and still says profile: geostory. Motion is what you get when the geography is absent: the same renderer and the same primitives, pointed at a frame instead of at the ground.

@openverb/format

The .ov format underneath the profile. You need this directly only if you are working with OpenVerb documents that are not geostories.

npm install @openverb/format
ExportWhat it does
parseOV(yaml)Parses any .ov document into an OVScript.
bridgeToRuntime(script, options)Turns a script into ExecuteRequests for a runtime.

Note for browser work: this package reaches Node’s fs, so it cannot be bundled into client code — importing it from a React component fails the build with Can’t resolve 'fs'. Types are fine, since they are erased before bundling. Anything that is a value at runtime has to stay on the server. This site parses and serialises through API routes for exactly that reason.

@openverb/runtime

Executes verbs. Three concepts: verbs are the vocabulary, handlers are the functions that carry them out, and adapters connect the runtime to whatever is doing the work.

npm install @openverb/runtime
ExportWhat it does
createRuntime(config)Builds a runtime.
loadVerbs(directory)Loads verb definitions from disk.
runtime.execute(request)Runs one request.

@openverb/sdk

Calls a runtime from a client. Ships an OpenVerbClient plus React hooks — useVerb and useVerbMutation.

npm install @openverb/sdk

You may not need any of this

A story is a text file. If all you want is to read one, you can parse the YAML with any library and walk the registries — the document is designed to be legible. The packages matter when you want validation, the unknown-field guarantee, and the compiled action timeline without writing them yourself.