Skip to content

Releases: airiclenz/photon

Release list

v0.2.0

Choose a tag to compare

@airiclenz airiclenz released this 22 Oct 06:43

photon — v0.2.0 — 2026-10-22

This release adds photon tune, a timing editor that runs in your browser, and gives storyboards a camera that aims and zooms, plus captions drawn over the GIF.

Breaking changes

  • A beat no longer takes a zoom — a storyboard written for v0.1.0 that sets zoom on a beat is now refused when it loads, with beat <id>: zoom: removed; zoom with camera.zooms and aim with camera.positions. What to do: move each beat zoom into an entry of the storyboard's camera.zooms list, and aim it with an entry in camera.positions.
  • frame.font_size must lie between 6 and 72 — a storyboard whose font size is outside that range now fails to load, and photon lint reports frame.font_size: want in [6, 72], got …. What to do: set frame.font_size to a value from 6 to 72.

New

  • photon tune, a timing editor in the browser — photon tune <storyboard> [<take>] serves an editor on 127.0.0.1 (any free port, or the one you give --port), prints its address and previews the take until you press Ctrl-C. You can edit each beat's duration, hold and cut and the clip's frame width, fps, font_size, line_height, padding and scale with undo, redo and revert, and saving writes back only the values you changed.
  • A camera that aims and zooms — a storyboard can declare a top-level camera with positions (where the camera aims: a cell or a text target, with at, hold and ease) and zooms (to from 1 to 3, with at, over and ease), where at is a clip time or a beat plus an offset. photon render holds each position, glides to the next and keeps the crop inside the frame, and photon lint reports camera mistakes such as a position naming an undeclared area.
  • Captions — a storyboard can declare a top-level captions list of text shown on the clip's clock (at, then for or until) with a font size and weight, a place, alignment, offset or explicit position, colours, a background box and fades. photon render and photon tune draw captions on top of everything, cursor included, so zooming or aiming the camera never moves or scales them, and photon lint reports bad captions.
  • Caption fonts — captions use the built-in Source Sans 3 Regular and Bold, or the font files you name with caption_font.regular and caption_font.bold in photon.yaml; a caption_font entry that names a directory is refused when the config loads. Release archives now include the font's licence, SourceSans3-OFL.txt.
  • Smooth preview while playing or scrubbing — photon tune's preview shows quick draft frames while it plays or while you scrub, fetching up to 4 frames ahead, and settles on the exact frame photon render would produce once it stops.
  • Editing the camera in photon tune — you can change, add and remove camera positions (at, hold, ease, a cell or a text target) and zooms (at, over, ease, to), and move the edges of the transition between two positions, with only those keys written back. An edit that would make two positions or two zooms overlap is refused with a message naming both, and removing a list's last entry removes the list, and camera: too once it is empty.
  • Position lane — photon tune's timeline shows each camera position as a bar (or a point when it has no hold) with a transition bar between it and the next, each opening a panel to edit it; bars and their edge grips drag in 50ms steps, each drag one undoable edit. The lane's + adds a point at the playhead on the cell the camera is already centred on, so adding it does not move the camera.
  • Zoom lane — photon tune's timeline shows one bar per zoom, labelled with its zoom factor: + adds a zoom at the playhead and dragging a bar moves it while keeping its beat. Clicking a bar opens a panel that edits at, over, to and ease, shows the zoom's errors and removes it.
  • Aiming on the full frame — selecting a camera position in photon tune jumps the playhead to it, and while paused the preview shows the whole frame with the camera's crop dashed and a marker you drag onto the cell the position should aim at. A pick's Set as position target sets the selected position's text target instead, and stays disabled until a position is selected.
  • Captions lane — photon tune shows captions as bars on their own lane: + adds one at the playhead, dragging moves it in 50ms steps, and its panel edits text, at, for or until, place and align, moves it up or down the list or removes it. A caption's rendering error, such as a box bigger than the frame, shows on its own panel, and the Inspect list marks captions that have one.
  • Caption style and timing in photon tune — the caption panel edits font size and weight, text and box colours, box opacity, fade in and out, an offset and an explicit position, and sets start and end by beat or clip time plus an offset in milliseconds. Choosing "none" for the end turns an until into a for of the same length.
  • Target picker — press ⌖ Pick in photon tune and drag across one row of the paused frame to get a target photon has checked against the screen, ready to copy as click, seen, drag-from or drag-to YAML. A target's nth: last is kept when it is set or copied.
  • A page that fits the window — in a short window photon tune shrinks the preview (keeping its shape, never below 120px tall) so the transport bar and timeline stay on screen. The transport bar also shows which photon build serves the page, and why a lane's add button was refused, until the next accepted edit.

Improved

  • photon version shows the build — photon version and photon --version now print the version with the commit it was built from, such as photon 0.1.0 (a1b2c3d), adding , dirty when the tree had uncommitted changes; a build without that information prints just photon 0.1.0.
  • Takes recorded out of order are refused — photon check, photon render and photon tune refuse a take that started its beats in a different order from the storyboard, naming both orders so you know to re-record it, and report a beat that started twice.
  • photon lint checks caption sizes — once the storyboard and config load cleanly, photon lint lays the captions out with the config's fonts and reports any caption box larger than the frame, instead of leaving it for photon render to fail on.
  • All-cut storyboards caught early — a storyboard in which every beat is cut is now refused when it loads (beats: every beat is cut), so photon lint reports it.

Fixed

  • Stopped services free their port — when photon stops a project service it now waits for every process of that service to exit, so the service no longer keeps holding its port afterwards (Windows ends those processes with a delay); a process that survives being killed is reported.

Docs & install

  • README rewritten — the README is reorganised with Contents, Why, Features, FAQ and License sections, and Install now leads with Homebrew (brew install airiclenz/tap/photon) and Scoop, then go install and release archives, without the pre-release caveat.
  • Camera and captions documented — the README gains Camera (positions, transitions, zooms, eases) and Captions reference sections, and its photon tune section, photon tune --help, photon render --help and the glossary describe camera positions and zooms.

v0.1.0

Choose a tag to compare

@airiclenz airiclenz released this 17 Oct 17:13

photon — v0.1.0 — 2026-10-17

photon's first release. You describe a demo once as a storyboard, photon performs it against your real terminal app, checks the result and renders the GIF you ship, so a demo that goes stale after a UI change is re-recorded with one command.

New

  • Record a demo from a storyboard — photon record <storyboard> starts your app in a terminal at the storyboard's frame size, performs every beat (typing, keys, clicks, drags, waits) and saves what the screen showed as a take, <work>/<clip>.take, ready to check and render. On Windows, record and setup refuse to run with the message that recording needs a unix pty.
  • Check a take, and retake until it passes — photon check <storyboard> [<take>] compares a take (by default the one photon record saved) with the storyboard's expects and prints a PASS/FAIL table. photon record checks each take whose beats all succeeded and exits 0 only when every beat and expect passed, so until photon record ...; do :; done is the whole retake loop.
  • Render the finished GIF — photon render <storyboard> [<take>] turns a take into the GIF, giving each beat exactly its duration (played at normal speed, held, or sped up to fit) and leaving out beats marked cut. Memory stays flat however long the clip, the file is shrunk further when gifsicle is installed, and --dry-run prints the ffmpeg commands instead of running them.
  • Lint before you record — photon lint <storyboard> reads the storyboard and its config without recording anything and lists every problem by the field it sits in, or prints a one-line ok summary; it exits 1 when anything is wrong.
  • Project config in photon.yaml — one photon.yaml, given with --config or found at or above the storyboard, names the program to launch (its directory, extra env, and strip patterns that keep your own environment variables out), the setup and reset commands, a work directory, services, profiles, named areas, an end block (keys, idle wait, settle_timeout, kill_after), a theme of foreground, background and 16 ANSI colours, and a fonts directory. Unknown keys are rejected.
  • The storyboard format — a storyboard file describes one clip: where its GIF ships, the terminal frame (columns, rows, font size, line height, padding, width, fps, palette size), then beats that each run actions — type with human-like typing, key with 27 named keys and repeats, click, wait for text to appear or be gone, pause — and set their duration, hold, cut and zoom. Each beat lists expects that some text is seen (optionally within an area) or that a run command succeeds, and unknown fields or bad values are rejected.
  • Aim at text, not coordinates — clicks, drags and zooms find their target by a regular expression on the screen's text, picking the first, last or Nth match, optionally inside a named area: a band of rows bounded by text anchors and found afresh on every screen, so the storyboard keeps working as the layout shifts.
  • Drag with the mouse — a beat can drag from one piece of text to another (or by a cell offset) in a set number of steps; photon presses, moves and releases the button as a real mouse would, and the rendered cursor and zoom follow the drag.
  • Services and profiles — photon.yaml can start helper processes, such as a fake backend, before your app, wait until each is ready by a port accepting connections or a line of output, pass their ports along as PHOTON_PORT and PHOTON_PORT_<NAME>, log their output in the work directory and stop them after the take. photon record --profile <name> swaps their commands or environment and runs an on_success command after a passing take.
  • Zoom and a drawn cursor — a beat's zoom pushes in on its target (by a factor from 1 to 3, or sized automatically) and eases back out within the beat, and a drawn cursor fades in, glides to each click and drag, rings on the press and fades away.
  • Fonts built in — frames are drawn with Source Code Pro, with Noto Sans Symbols 2, Math and Symbols as fallbacks, all bundled in the binary so a clip renders the same on every machine; point the config's fonts directory at all six files to use your own faces.
  • One-time setup — photon setup <storyboard> creates the work directory and runs the config's setup command once, for building whatever your app needs before the first recording.
  • Clear exit statuses — every command exits 0 on success, 1 when a run started and failed, and 2 for a bad command line, and errors go to stderr prefixed with photon:.
  • Version — photon version and photon --version print photon's version number.

Docs & install

  • Install with Homebrew, Scoop or a download — besides go install, photon installs with brew install airiclenz/tap/photon, with scoop install airiclenz/photon, or from the release archives for Linux, macOS and Windows on amd64 and arm64; a guide to cutting a release ships alongside.
  • ffmpeg comes with the package — installing through Homebrew or Scoop also installs ffmpeg, so photon render works straight away.
  • A full user guide in the README — the README now covers installing, a quick start, every command and exit status, the take and retake loop, the photon.yaml and storyboard references, targets and areas, expects, services and profiles, zoom and cursor, the environment variables your commands see, the key names and the fonts.
  • Font licences in every archive — each release archive carries the SIL Open Font License texts of the bundled fonts beside LICENSE and README.md, with a SHA256SUMS file to verify the downloads.