Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ body:
- type: textarea
attributes:
label: Config
description: Paste the relevant `motion.config.mjs` or the important parts.
description: Paste the relevant `screenstage.config.mjs` or the important parts.
- type: textarea
attributes:
label: Reproduction
Expand Down
20 changes: 10 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ The format is based on Keep a Changelog, and this project aims to follow Semanti

## [Unreleased]

- Open-source packaging and release prep.
- Session manifests, marker CSV/JSON exports, and marker stills.
- Pre-capture setup hooks for local app state.
- Manual recording workflow with studio mode and marker cues.
- Camera presets, timing presets, and composition/device shells.
- Nothing unreleased yet.

## [0.1.0] - 2026-03-08

- Initial public MVP for browser demo capture in TypeScript.
- Playwright capture pipeline with FFmpeg post-processing.
- Desktop browser composition shell and phone shell support.
- Manual `record` mode, scripted `run` mode, and guided `init`.
- MP4 review output and ProRes edit-friendly output.
- Initial public release of Screenstage.
- Scripted `run` mode for browser captures with FFmpeg camera/composition rendering.
- Manual `record` mode with editable generated demo scripts, studio mode, and marker cues.
- Guided `init` flow that writes `screenstage.config.mjs` and starter files.
- Desktop browser composition shell, phone shell support, and named background/chrome presets.
- Camera presets, zoom controls, and timing presets for cursor-led framing.
- MP4 review renders, ProRes edit exports, contact sheets, poster frames, manifests, and marker artifacts.
- Pre-capture setup hooks for local app state, including route, storage, cookies, and setup modules.
- Cursor options for Screenstage-owned cursors or app-owned custom cursors during capture.
15 changes: 9 additions & 6 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ This repo is set up to be published as the `screenstage` npm package.

## Before The First Public Release

1. Confirm the public repository URL and add it to `package.json`:
- `repository`
- `homepage`
- `bugs`
2. Confirm the npm package name is available.
3. Create an npm automation token and store it as `NPM_TOKEN` in GitHub Actions secrets.
1. Confirm the npm package name is still available.
2. Create an npm automation token and store it as `NPM_TOKEN` in GitHub Actions secrets.
3. Make sure the public repo metadata in `package.json` matches the live GitHub repo.

## Local Release Checklist

Expand Down Expand Up @@ -41,6 +38,12 @@ npm run pack:check
git push --follow-tags
```

6. Publish manually if you want to ship before using GitHub Actions:

```bash
npm publish --access public
```

## GitHub Release Workflow

The release workflow publishes on version tags that start with `v`, for example:
Expand Down
Binary file added docs/assets/quickstart-sample-poster.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/quickstart-sample.mp4
Binary file not shown.
4 changes: 2 additions & 2 deletions examples/quickstart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ It gives you one calm, basic workspace page with enough interaction to test both
Try the scripted pass:

```bash
node dist/cli.js run ./examples/quickstart/motion.config.mjs
node dist/cli.js run ./examples/quickstart/screenstage.config.mjs
```

Try the manual recorder:

```bash
node dist/cli.js record ./examples/quickstart/motion.config.mjs
node dist/cli.js record ./examples/quickstart/screenstage.config.mjs
```

Outputs are written under `./output/`.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default {
preset: "soft-studio",
},
browser: {
domain: "workspace.motion.local",
domain: "workspace.screenstage.local",
style: "minimal",
},
},
Expand Down
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
"name": "screenstage",
"version": "0.1.0",
"description": "TypeScript CLI for cursor-following product demo videos with Playwright and FFmpeg.",
"repository": {
"type": "git",
"url": "git+https://github.com/jodonnell24/screenstage.git"
},
"homepage": "https://github.com/jodonnell24/screenstage#readme",
"bugs": {
"url": "https://github.com/jodonnell24/screenstage/issues"
},
"type": "module",
"engines": {
"node": ">=22"
Expand Down Expand Up @@ -39,7 +47,6 @@
"video",
"cursor",
"marketing",
"motion",
"product-demo",
"screen-recording"
],
Expand Down
22 changes: 14 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,25 +83,31 @@ Scaffold a starter project:
node dist/cli.js init ./demo-project
```

If you run `init` in a terminal, it opens a short wizard and writes `motion.config.mjs` for you. In non-interactive shells it falls back to the old starter scaffold.
If you run `init` in a terminal, it opens a short wizard and writes `screenstage.config.mjs` for you. In non-interactive shells it falls back to the old starter scaffold.

If you just want to try the tool against the bundled example first:

```bash
node dist/cli.js run ./examples/quickstart/motion.config.mjs
node dist/cli.js record ./examples/quickstart/motion.config.mjs
node dist/cli.js run ./examples/quickstart/screenstage.config.mjs
node dist/cli.js record ./examples/quickstart/screenstage.config.mjs
```

## Sample Output

[![Quickstart sample capture](./docs/assets/quickstart-sample-poster.png)](./docs/assets/quickstart-sample.mp4)

See the bundled quickstart render here: [quickstart-sample.mp4](./docs/assets/quickstart-sample.mp4)

Run the starter demo:

```bash
node dist/cli.js run ./demo-project/motion.config.mjs
node dist/cli.js run ./demo-project/screenstage.config.mjs
```

Record a manual session instead of scripting the mouse:

```bash
node dist/cli.js record ./demo-project/motion.config.mjs
node dist/cli.js record ./demo-project/screenstage.config.mjs
```

Each run creates a timestamped folder inside the configured output directory with artifacts like:
Expand Down Expand Up @@ -131,8 +137,8 @@ Development shortcuts:

```bash
npm run dev -- init ./demo-project
npm run dev -- record ./demo-project/motion.config.mjs
npm run dev -- run ./demo-project/motion.config.mjs
npm run dev -- record ./demo-project/screenstage.config.mjs
npm run dev -- run ./demo-project/screenstage.config.mjs
```

`init` is non-destructive. It only writes starter files that do not already exist, and in a normal terminal it now asks a few setup questions instead of making you hand-author the config.
Expand All @@ -143,7 +149,7 @@ For local apps and local fixtures, you can enable embedded studio mode so the co

## Config

`motion.config.mjs` exports a default object:
`screenstage.config.mjs` exports a default object:

```js
export default {
Expand Down
4 changes: 2 additions & 2 deletions src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ async function promptForInit(
}

async function writeStarterProject(targetDir: string): Promise<void> {
await writeFileIfMissing(path.join(targetDir, "motion.config.mjs"), CONFIG_TEMPLATE);
await writeFileIfMissing(path.join(targetDir, "screenstage.config.mjs"), CONFIG_TEMPLATE);
await writeFileIfMissing(path.join(targetDir, "demo", "starter-demo.mjs"), DEMO_TEMPLATE);
await writeFileIfMissing(path.join(targetDir, "demo-site", "index.html"), HTML_TEMPLATE);
}
Expand All @@ -1087,7 +1087,7 @@ async function writeGuidedProject(answers: InitAnswers): Promise<void> {
answers.projectKind === "static-starter" ? "starter-demo.mjs" : "recording-demo.mjs";

await writeFileIfMissing(
path.join(targetDir, "motion.config.mjs"),
path.join(targetDir, "screenstage.config.mjs"),
buildConfigSource(answers),
);
await writeFileIfMissing(
Expand Down