Skip to main content

timeskeleton

TimeSkeleton is the versioned JSON Schema for the structural serialization of musical timelines, with golden fixtures emitted by timetoalign and validation and migration packages for Python and TypeScript. It carries timeline structure, not event data.

Status: alpha. Version 0.2.0 offers the schema (0.2.0, with 0.1.0 kept validatable), validators in Python and TypeScript that locate a violation under one shared path rule, the migration from 0.1.0 to 0.2.0 in both packages, and the golden, rejection, and migration fixtures. The format may still change incompatibly in a later 0.x version; every such change ships with a migration.

The document

A TimeSkeleton document is a JSON object with meta and manifest. meta.schema_version selects the schema and meta.generator is optional. manifest.timelines maps timeline ids to manifests matching timetoalign's Timeline.to_dict(events=False) output: axis (class, unit, number_type, length), child timelines at exact offsets, conversion maps, regions, flow control, measure map, and metric hierarchy. Event tables travel separately, typically as Arrow or Parquet data, and are referenced rather than embedded.

Every coordinate-valued member is an object with unit, number_type, and value. Its number type selects the value representation: an integer is a JSON integer, a float is a JSON number, and a fraction is a [numerator, denominator] pair of JSON integers with a strictly positive denominator, mirroring BOPP.

Version 0.2.0 specifies conversion maps, regions, flow control, and measure maps in addition to the envelope, timeline manifests, and typed coordinates. metric_hierarchy remains opaque. Version 0.1.0 retains its original opaque members. The 0.2.0 schema identifier is https://timetoalign.github.io/timeskeleton/0.2.0/timeskeleton.schema.json.

In 0.2.0, a measure map is the Measure Map standard's compressed row array: entries equal to the preceding entry's default successor are omitted. A row is the standard's Measure plus two extensions: the integer volta, and offset_within_measure, where the row begins inside its nominal measure in quarter notes (an anacrusis, or one constituent of a split measure; absent means 0). Lengths are strictly positive and qstamp is non-negative; exact Fraction pairs are permitted wherever the standard uses JSON numbers. A measure map is anchored in quarter notes, so only a timeline whose unit is quarters may carry one.

The schema is the source of truth for timetoalign, the TimeLineEditor browser application, and its server. timetoalign's hand-written serialization is tested for schema conformance and fixture round trips. TypeScript types are generated in this repository, never by downstream consumers.

Install

pip install timeskeleton
pnpm add @timetoalign/timeskeleton
# or
npm install @timetoalign/timeskeleton

Usage

Python validation raises SchemaValidationError with a tuple path to the offending value. migrate() returns a deep-copied document at the latest supported version.

import json

from timeskeleton import SchemaValidationError, fixture_paths, migrate, validate

document = json.loads(fixture_paths()[0].read_text())
try:
    validate(document)
except SchemaValidationError as error:
    print(error.path)
else:
    latest = migrate(document)

In TypeScript, validate() narrows an unknown value to TimeSkeletonDocument; migrate() returns the latest document version.

import {
  migrate,
  SchemaValidationError,
  type TimeSkeletonDocument,
  validate,
} from "@timetoalign/timeskeleton";

function load(document: unknown): TimeSkeletonDocument {
  try {
    validate(document);
    const typed: TimeSkeletonDocument = document;
    return migrate(typed);
  } catch (error) {
    if (error instanceof SchemaValidationError) {
      console.error(error.path);
    }
    throw error;
  }
}

Versioning and migrations

meta.schema_version identifies a document's contract. Every published schema version remains validatable. Both packages provide migrate() as an ordered sequence of pure migration functions from earlier versions to the latest, with each migration pinned by a before-and-after fixture pair.

The first migration, 0.1.0 to 0.2.0, rewrites the shapes timetoalign wrote at 0.1.0 that 0.2.0 specifies differently: a tagged-measure measure map becomes compressed rows, and a MetricalPositionMap keeps its meter map once and names its derived beat map by beat_map_id. A member whose shape the migration does not know raises MigrationError with the member's path; a migrated document satisfies 0.2.0.

A timeskeleton release is a schema-version event: one vX.Y.Z tag publishes both packages through trusted publishing without stored registry tokens. scripts/check_versions.py verifies that all version declarations agree before release.

Fixtures

The golden fixtures are emitted only by scripts/emit_fixtures.py using timetoalign and ship in both packages. Each records the timetoalign version and commit in meta.generator; do not edit golden fixture JSON by hand. The rejection cases and migration pairs beside them are authored by hand.

Development

Clone the repository, then run the package commands in their indicated directories.

git clone https://github.com/TimeToAlign/timeskeleton.git
cd timeskeleton/python
uv sync
uv run pytest
cd js
pnpm install
pnpm test
pnpm generate
pnpm build

To re-emit fixtures, use an interpreter whose environment contains the timetoalign revision being represented:

python scripts/emit_fixtures.py --timetoalign-commit "$(git -C /path/to/timetoalign rev-parse --short HEAD)"

From the repository root, check that all version declarations agree:

python3 scripts/check_versions.py

Releasing

See CONTRIBUTING.md for the required version updates, checks, tag, and trusted-publishing configuration.

License

MIT.

Metadata

Release files for timeskeleton 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for timeskeleton 0.2.0
File Size Uploaded
timeskeleton-0.2.0.tar.gz 60.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for timeskeleton 0.2.0
File Interpreter ABI Platform
timeskeleton-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 143.4 kB

Release files / timeskeleton-0.2.0.tar.gz

Download URL timeskeleton-0.2.0.tar.gz
Size 60.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f33fc024b7c532bb3d82ce0ebfde61877e17dc4740d383c8fc84abae375b8c7f
BLAKE2b-256 checksum
How to use checksums
2f10c417e865d953a3b9fa66adc4b67bb582b74de7b16707227adc03d2b099d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.4

Release files / timeskeleton-0.2.0-py3-none-any.whl

Download URL timeskeleton-0.2.0-py3-none-any.whl
Size 82.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa882eb19fcaa51d61534b5d1ffcfecd97e8cfca7f5d6ef254b726861be10b47
BLAKE2b-256 checksum
How to use checksums
6f6b83b6a70c2e41ae928cc134f43c7b7c6eb421b2d1f28ce46bd477e903993f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.4

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page