← ui

span

lib

a stretch of time, from inclusive and to exclusive, whole ms

npx shadcn add @ag/span
Already installed? Preview an update
npx shadcn add @ag/span --dry-run

Your installed source stays unchanged until you update it. How updates work

Latest changes · 2026-11-05
  • New: Span, {from, to} in whole ms, from inclusive, to exclusive, its own item so everything that speaks of a stretch of time imports it without a playable.
Updated 2026-11-05 · release notes

shelf motion

used by video, media-line, telemetry, playable, timebase, playback, timeline, timeline-view, film-mosaic, trace

a loop range, a claim's stretch and a session's second chapter, each from inclusive and to exclusive, whole ms

  • loop 1200–3400 ms
  • said 0–600 ms
  • chapter 2 678–2118 ms

the demo above, verbatim

span.demo.tsx
import { Sample } from "@/app/samples"
import { chapterSpan } from "@/registry/base-nova/lib/playable"
import type { Span } from "@/registry/base-nova/lib/span"
import {
  parseSession,
  sessionTimeline,
} from "@/registry/base-nova/lib/terminal-session"

// #region spans
/** A loop range, a claim's stretch and a chapter, all one shape. */
const LOOP: Span = { from: 1200, to: 3400 }
const SAID: Span = { from: 0, to: 600 }
const SECOND = chapterSpan(
  sessionTimeline(
    parseSession(`$ awake grant
~ macOS asks once, natively

@600 $ awake grant --remove
~ takes it back`),
  ).playable,
  1,
)
// #endregion

/** Every stretch of time in the registry is one shape: `from` inclusive, `to`
 *  exclusive, whole ms. */
export default function SpanDemo() {
  return (
    <Sample
      name="spans"
      title="one shape for every stretch"
      description="a loop range, a claim's stretch and a session's second chapter, each from inclusive and to exclusive, whole ms"
      with="spans"
    >
      <ul className="space-y-1 font-mono text-xs">
        {(
          [
            { name: "loop", span: LOOP },
            { name: "said", span: SAID },
            { name: "chapter 2", span: SECOND },
          ] satisfies { name: string; span: Span }[]
        ).map(({ name, span }) => (
          <li key={name}>
            <span className="text-muted-foreground">{name}</span>{" "}
            <span className="tabular-nums">
              {span.from}–{span.to} ms
            </span>
          </li>
        ))}
      </ul>
    </Sample>
  )
}

the source, every file an install writes

span.ts
// A SPAN: two instants, `from` inclusive, `to` exclusive, whole ms on a media clock;
// geometry and nothing more (swift-utils' WORDS.md). What a scroll stage's act cues
// (ui/playback `cue`), what a timebase loops in, where a division runs, what a claim
// is about, what an effect targets. Framework-free, and its own item so the many
// things that speak of a stretch of time import it without the rest of a playable.

/** A stretch of time, ms: `from` inclusive, `to` exclusive. */
export interface Span {
  from: number
  to: number
}