ScreenFlow for AI agents.

screeny mascot

Polished screen recordings,on autopilot.

Script your demo in TypeScript. screeny drives your real Mac app — real cursor, real clicks, real typing — then beautifies it in post with cinematic zoom, a composited cursor, and keycaps. Record once, re-cut without re-recording.

Notes
New Note
zoom 1.0×
notes.screeny.ts
import { defineRecording, target } from "@screeny-sh/record";

const newNote = target.role("button", { name: "New Note" });

export default defineRecording({
  id: "notes-demo",
  targetApp: "com.apple.Notes",
  async prepare(screen) {
    await screen.open({ id: "launch" });
    await screen.waitUntil(() => screen.exists(newNote),
      { id: "ready", timeout: 5_000 });
  },
  async record(screen) {
    await screen.scene("write", async () => {
      if (await screen.exists(newNote))
        await screen.click(newNote, { id: "new" });
      await screen.type(target.role("textarea"),
        "screeny — agent-authored screen recordings. Smooth zoom, real cursor, premium feel.", { id: "note" });
    });
    await screen.scene("reveal", () =>
      screen.pause(2_000, { id: "hold" }));
  },
});

The two-document model

Record once. Re-cut forever.

The actions and the camera are never coupled. .screeny.ts is what happens; .screenycut is how it’s filmed — zoom, pan, and highlights anchored to named moments in the recording. Re-frame the whole video without ever re-running the app.

notes.screeny.ts
import { defineRecording, target } from "@screeny-sh/record";

export default defineRecording({
  id: "notes-demo",
  targetApp: "com.apple.Notes",
  async record(screen) {
    await screen.scene("write", async () => {
      await screen.click(target.role("button", { name: "New Note" }), { id: "new" });
      await screen.type(target.role("textarea"),
        "screeny — agent-authored recordings.", { id: "note" });
    });
    await screen.pause(2_000, { id: "hold" });
  },
});

The actions. No camera here.

notes.screenycut
<Cut take="notes-demo">
  {/* frame the button; cursor moves in and clicks */}
  <Camera anchor="click:new" to="type:note.start"
          camera="zoom-1.4 follow-target ease-cinematic" />
  {/* frame the note body while typing */}
  <Camera anchor="type:note.start" to="type:note.end"
          camera="zoom-1.5 follow-target ease-cinematic" />
  {/* pull back for the reveal */}
  <Camera anchor="pause:hold" camera="zoom-1.0 ease-cinematic" />
</Cut>

The camera. Anchored to moments.

renderlive
New Note
screeny — agent-authored recordings.

zoom 1.4× · same take, re-framed

Same recording, re-framed — the actions on the left never re-run. Only the camera changes.

Built like a product, not a screen recorder.

01

Lives with your source code.

Your demo is a live .screeny.ts module committed right beside the code it records. Use normal imports and control flow, then re-run one command against the latest state of your app.

demos
notes.screeny.ts committed
notes.screenycuttracked
$screeny render@ HEAD
02

A declarative cut.

Camera, zoom and highlights live in a separate .screenycut, anchored to named moments like click:new and type:note.start — so the frame lands on the right thing at the right time.

New Note
click:newtype:note.starttype:note.endpause:hold
03

Cinematic quality, automatically.

60fps ProRes 422 HQ capture at retina 2×, beautified in post by a critically-damped analytic-spring camera that never bounces, Lanczos upscaling, and a composited 3× cursor that never scales with the frame.

60FPS
04

Input that feels human.

The cursor follows Fitts’-law paths with natural overshoot and micro-jitter; typing uses log-normal cadence with pauses at word boundaries. It reads like a person — not a robot snapping between coordinates.

linear
organic
60fps ProResretina 2×zero-coordinate authoringdeterministic & seeded

A demo in five commands.

Capture the real app once. After a single screeny record, re-author the .screenycut and render again and again — the cinematography changes, the recording never does. No re-capture.

notes-demo — screeny
$npm install -g @screeny-sh/record# one-time setup + project dependency
Record once — drives the real app, captures the take
1$screeny record notes.screeny.ts --out rec/# run your TypeScript & capture
2$screeny moments rec/moments.json# inspect anchorable hooks
Cut & render — re-author and re-run freely, no re-capture
3$screeny compile-cut notes.screenycut# bind the cut to moments
4$screeny resolve …# resolve camera against the take
5$screeny render …# post-produce → polished .mp4

The recording is ordinary trusted project TypeScript: imports, helpers, loops, conditions, and waits all run normally. The MCP server only inspects moments and compiles .screenycut; it never evaluates recording source.

Pricing

Free to use. $49 to go watermark-free.

One free, local macOS engine. Runs entirely on your Mac — no subscription, no metering, no cloud.

Free

$0

Full-resolution, full-length renders.

Made with screeny
  • Unlimited recordings
  • Cinematic camera, organic cursor & keycaps
  • “Made with screeny” end-card

Pro

Recommended

$49

one-time

Everything in Free, watermark removed.

  • No “Made with screeny” watermark
  • One-time key — no subscription
  • Validates online once, works offline after

Runs on your Mac · no subscription · the only difference is the watermark.