Tidigar embed story specification

Watch the animated story example to see timed changes play on an embedded roadmap, alongside its story script.

Status: public pre-release specification, version 1. It defines how a page that embeds a Tidigar roadmap can play a short story on it: timed changes to the plan, with captions, that the reader sees animate in the embedded views. A tutorial can show a plan changing step by step, and a product page can show what a dependency does.

License: published by Hamacher Software AB under CC BY 4.0. Anyone may implement the formats it describes, in any software, without asking.

The keywords MUST, MUST NOT, SHOULD and MAY are normative. Roadmaps, their records and fields are defined in the Tidigar Roadmap Interoperability Specification; embeds open a share link.

Embedding a story

A story is a script block next to an ordinary embed. Its type is text/tidigar-story, so the browser never runs it, and data-for names the ids of the iframes it plays in. The embed script delivers it.

<iframe
  id="vacation"
  src="https://embed.tidigar.com/#s=1.…"
  title="Vacation plan"
  width="100%"
  height="480"
  style="border:0"
></iframe>
<script type="text/tidigar-story" data-for="vacation">
  0:01 caption("The plan counts only weekdays")
  0:04 add("period", {"title": "Summer vacation", "start": "2026-07-06", "end": "2026-08-02"})
       caption("Work that spans the vacation moves past it")
  0:08 applyView("Timeline by team")
  0:10 compactRoadmap()
  0:14 restore()
       caption()
  0:16 loop()
</script>
<script async src="https://embed.tidigar.com/embed.js"></script>

Screens

A Tidigar Business plan's screen can carry a story that the plan's editors wrote for it, in this syntax. It plays wherever the screen is shown (https://embed.tidigar.com/#screen=…): in a full window, as on a wall screen, and in a frame on a page, as a story block would, and every rule on this page applies. A story block on the publishing page names the frame as usual and wins over the screen's story. When the plan changes while a story plays, the screen takes the new version when the story starts again.

Syntax

A story is plain text, one call per line:

[m:ss[.s]] name(arguments)

All calls at one moment change the plan together, and the views animate them as one change: bars glide, cards move, arrows draw. With reduced motion the changes appear at once.

The calls at 0:00 that change the plan set it up instead: every frame of the story runs them at once, without animation, before the reader sees the plan, as it runs shiftToToday. A story can so open on an earlier state of the plan than the one stored, and play forward from there. caption and focus at 0:00 show as the story starts.

Primitives

CallDoes
changeDates("Title", {"start", "end"})Moves an activity's start, end or both, as a drag does; what waits for it follows. A date is absolute or relative to the activity's own: "+3d", "-2d".
update("Title", {…})Sets fields of an activity (start, end, progress, title, description, and dimension values by name: "Status": "Done", or null to clear), a milestone (date, title) or a period (start, end, title, color, vacation).
add("kind", {…})Adds a record of a kind, "activity", "milestone" or "period", with a title and its dates (start and end, or date for a milestone), and the same optional fields as update. A period is a vacation unless "vacation": false.
remove("Title")Removes an activity, milestone or period. Nothing waits for a removed activity any more.
connectActivities("Child", "Parent", 50)The child, an activity or a milestone, now waits for the parent activity and moves after it if needed. The optional share, 0, 25, 50, 75 or 100 (the default), is how much of the parent’s planned duration passes first, independent of reported progress: with 50 an activity may start halfway through another activity. A milestone, and anything waiting for a milestone, waits for the end.
changeDependency("Child", "Parent", 50)Changes how much of the parent passes before the child may start, as above; 100 waits for its end again. The child moves to the new start if needed.
removeDependency("Child", "Parent")The child no longer waits for the parent.
compactRoadmap()Every activity that waits for another starts as soon as it can, and milestones follow what they wait for.
applyView("Saved view name")Switches the playing frame to one of the plan's saved views.
caption("Text")Shows a caption at the bottom of the playing frame until the next caption; caption() clears it.
focus("Title")Selects an activity or milestone, as a tap does, in every frame of the roadmap on the page: its chain stands out, and the flow straightens the critical line through it. focus() selects nothing.
hide("Title")Takes an activity, milestone or period out of the plan until show, as if it were not there yet: nothing waits for it meanwhile, and calls that name it are skipped.
show("Title")Puts a hidden record back where it stood, with its fields as they were. It waits again for what it waited for, and what waited for it waits again, wherever both are shown; what waits moves after it if needed.
today("2026-03-14")Shows the today line on that date, as on the day of a status meeting, even where the view hides it; the plan does not move. today() returns the line to the real day and the view's own setting.
shiftToToday("Title", 2)Setup: moves the whole plan so that today is two days into that activity or at that milestone, without animation. Every frame of the story runs it at once.
restore()Returns the plan, the view, the hidden records and the today line to how they were when the story started, after its setup, with nothing selected.
loop()Starts the story over from 0:00. A story without it stops after its last call.

Records are named by their title, exactly as the reader sees it. Every change works as the same edit in Tidigar does: what waits for a moved activity follows, milestones keep their place after what they wait for, and in a plan planned in work days, adding or moving a vacation moves the work around it.

A plan's history

A story can show how a plan changed over time, such as the versions of a schedule shown at a series of status meetings. The plan holds the latest version, so it stays the plan people work in, and the story opens on the first version and plays the changes up to the latest:

# Setup at 0:00: the plan as it was at the first meeting.
0:00 hide("Pilot")
     hide("Go-live")
     update("Design", {"end": "2026-02-27", "progress": 25})
     update("Build", {"start": "2026-03-02", "end": "2026-04-24"})
     today("2026-02-02")
     caption("2 February: the plan at kickoff")
0:04 update("Design", {"end": "2026-03-13", "progress": 75})
     changeDates("Build", {"start": "2026-03-16", "end": "2026-05-15"})
     show("Pilot")
     today("2026-03-02")
     caption("2 March: design takes two weeks more, and a pilot is added")
0:08 update("Design", {"progress": 100})
     update("Build", {"end": "2026-05-29"})
     show("Go-live")
     today("2026-04-06")
     caption("6 April: the stored plan")
0:13 loop()

Errors

A story never stops at a bad call. A line that cannot be read, and a call that names a missing or ambiguous title, an unknown field, a dimension value that does not exist or a change the roadmap rules forbid, such as a dependency cycle, is skipped with a warning in the browser console that gives its line number. The plan stays as it was before that call, and the story goes on.

The reader stays in control