Skip to content

jgerardoma/OpenWodTimer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenWodTimer

A single URL query parameter to encode any workout timer.

?openwodtimer=emom(01:00,10)
?openwodtimer=tabata(00:20,00:10,8)
?openwodtimer=mix(emom(01:00,5),rest(02:00),tabata(00:20,00:10,8))

OpenWodTimer is an open standard that defines a compact, human-readable, composable syntax for encoding workout timer configurations in URLs. It covers For Time, AMRAP, EMOM, TABATA, RSA (Round Start At), rest periods, and mixed/composite workouts — all in a single openwodtimer query parameter.

This is a timer-only standard. It does not encode movements, exercises, or descriptions. Its sole purpose is to configure time structures that any fitness timer app can parse and run.

The formal versioned specification lives in spec/openwodtimer-v1.md. This README stays as the project overview plus a concise copy of the key rules and examples.

Quick Examples

Workout URL
20-min For Time ?openwodtimer=ft(20:00)
5-round For Time ?openwodtimer=ft(20:00,5)
15-min AMRAP ?openwodtimer=amrap(15:00)
10-min EMOM ?openwodtimer=emom(01:00,10)
Classic Tabata ?openwodtimer=tabata(00:20,00:10,8)
Wave starts ?openwodtimer=rsa(00:00,02:00,04:00,06:00)
Competition format ?openwodtimer=mix(ft(12:00),rest(05:00),amrap(10:00))

Specification

For the full normative text, see spec/openwodtimer-v1.md.

Syntax

Every OpenWodTimer URL contains exactly one query parameter:

?openwodtimer=<expression>

Where <expression> is a function call: type(arg1,arg2,...). Arguments are time values (MM:SS), integers, or nested expressions.

Time Format

All times use MM:SS format, zero-padded. Minutes can exceed 59 for long workouts (e.g., 90:00).

Formal Grammar (BNF)

expression  = workout
workout     = ft | amrap | emom | tabata | rsa | mix | rest

ft          = "ft(" time [ "," int ] ")"
amrap       = "amrap(" time ")"
emom        = "emom(" time "," int ")"
tabata      = "tabata(" time "," time "," int ")"
rsa         = "rsa(" time { "," time } ")"
rest        = "rest(" time ")"
mix         = "mix(" workout { "," workout } ")"

time        = DIGIT DIGIT ":" DIGIT DIGIT
int         = DIGIT { DIGIT }
DIGIT       = "0" | "1" | ... | "9"

Workout Types

ft(time_cap [, rounds]) — For Time

A countdown timer. Complete all work before the time cap expires.

Argument Position Type Required Description
time_cap 1 MM:SS Yes Maximum time allowed
rounds 2 int No Number of rounds (default: 1)
openwodtimer=ft(20:00)       → 20-min cap, single round
openwodtimer=ft(20:00,5)     → 20-min cap, 5 rounds

amrap(total_time) — As Many Rounds As Possible

A countdown for a fixed duration.

Argument Position Type Required Description
total_time 1 MM:SS Yes Total workout duration
openwodtimer=amrap(15:00)    → 15-minute AMRAP

emom(interval, rounds) — Every Minute On the Minute

At each interval start, perform work. Remaining time is rest. Total = interval × rounds.

Argument Position Type Required Description
interval 1 MM:SS Yes Duration of each interval
rounds 2 int Yes Number of intervals
openwodtimer=emom(01:00,10)  → 10 rounds, 1 min each = 10 min total
openwodtimer=emom(00:30,20)  → 20 rounds, 30 sec each = 10 min total

tabata(work, rest, cycles) — Tabata Intervals

Alternating work/rest intervals. Total = (work + rest) × cycles.

Argument Position Type Required Description
work 1 MM:SS Yes Work interval duration
rest 2 MM:SS Yes Rest interval duration
cycles 3 int Yes Number of work/rest pairs
openwodtimer=tabata(00:20,00:10,8)   → Classic Tabata (4 min)
openwodtimer=tabata(00:40,00:20,6)   → 40/20 intervals, 6 cycles

rsa(t1, t2, t3, ...) — Round Start At

Explicit start times for each round. Times must be ascending. Minimum 2 required.

Argument Position Type Required Description
t1 1 MM:SS Yes Start time of round 1
tN N MM:SS Yes Start time of round N
openwodtimer=rsa(00:00,02:00,04:00,06:00)  → 4 rounds, uniform 2-min intervals
openwodtimer=rsa(00:00,01:30,03:30,06:00)  → 4 rounds, increasing intervals

rest(duration) — Rest Period

A standalone rest/countdown. Primarily used inside mix().

openwodtimer=rest(02:00)     → 2-minute rest timer

mix(w1, w2, ...) — Composite Workouts

Sequences multiple workout types. Nesting is allowed.

openwodtimer=mix(emom(01:00,5),tabata(00:20,00:10,8))
→ 5-min EMOM, then Tabata

openwodtimer=mix(emom(01:00,5),rest(02:00),tabata(00:20,00:10,8))
→ 5-min EMOM, 2-min rest, then Tabata

openwodtimer=mix(ft(10:00),rest(03:00),amrap(12:00))
→ For Time, rest, AMRAP

openwodtimer=mix(mix(emom(01:00,3),rest(01:00),emom(00:30,6)),rest(05:00),ft(20:00))
→ Nested: EMOM block, rest, For Time

Parsing Rules

  • URL encoding: Parentheses () and commas , do not require percent-encoding per RFC 3986, but parsers must accept both forms.
  • Case insensitive: ft(), FT(), Ft() are all equivalent.
  • No whitespace: No spaces allowed within the expression.
  • Unknown functions: Ignore for forward compatibility.
  • Max nesting depth: Parsers must support at least 4 levels.
  • Max URL length: 2000 characters recommended.

Canonical Serialization

Implementations that serialize a parsed OpenWodTimer expression should emit a canonical form so round-tripping is stable across languages.

  • Function names: Always lowercase (ft, amrap, emom, tabata, rsa, rest, mix).
  • Whitespace: Emit no spaces anywhere in the expression.
  • Time values: Always emit zero-padded MM:SS.
  • Integers: Emit base-10 integers without a leading + or leading zeros.
  • Optional FT rounds: Omit the rounds argument when its value is 1, so canonical ft(20:00,1) becomes ft(20:00).
  • Ordering: Preserve workout order inside mix() and timestamp order inside rsa().
  • Unknown functions: If ignored during parsing, they do not appear in canonical serialized output.

Examples:

FT(20:00,1) -> ft(20:00)
Mix(FT(10:00),REST(03:00),AMRAP(12:00)) -> mix(ft(10:00),rest(03:00),amrap(12:00))

Validation Rules

Rule Action
Invalid MM:SS format Reject with parsing error
Seconds > 59 Reject with parsing error
Wrong argument count Reject with descriptive error
RSA times not ascending Reject with ordering error
RSA fewer than 2 times Reject with argument count error
Unbalanced parentheses Reject with syntax error
EMOM/TABATA rounds = 0 Reject with range error
Unknown function name Ignore (forward compatibility)

Versioning

Current version is implicitly 1. Breaking changes will use a new parameter name: opentimer2=...

Reserved Function Names

Name Future Use
countdown Simple countdown
stopwatch Count-up with lap markers
pyramid Ascending/descending intervals
ladder Progressive time increases
interval Generic custom intervals

Reference Parsers

Language Path Use Case
TypeScript parsers/typescript/ Web, Node.js
Python parsers/python/ Backend, scripting, tooling
Java parsers/java/ JVM backend, Android-adjacent tooling
Kotlin parsers/kotlin/ Android
Swift parsers/swift/ iOS

Security

  • Never combine openwodtimer with user IDs, auth tokens, or PII in the same URL.
  • Applications should preview decoded timers before starting.
  • Clamp extreme values (recommended max total duration: 180 minutes).

License

Contributing

See CONTRIBUTING.md for guidelines on proposing changes.

About

The universal syntax for fitness timers. OpenWodTimer defines complex workout structures (FT, EMOM, AMRAP, RSA) via URL parameters like ?openwodtimer=emom(01:00,10). Fully composable using mix(), human-readable, and platform-agnostic. No backend required to share your training sessions. High-performance parsers included.

Resources

License

MIT, Unknown licenses found

Licenses found

MIT
LICENSE-CODE
Unknown
LICENSE-SPEC

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors