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
13 changes: 13 additions & 0 deletions .autorel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
commitTypes:
- {type: feat, title: ✨ Features, release: minor}
- {type: fix, title: 🐛 Bug Fixes, release: patch}
- {type: perf, title: 🚀 Performance Improvements, release: patch}
- {type: revert, title: ⏪ Reverts, release: patch}
- {type: docs, title: 📚 Documentation, release: patch}
- {type: style, title: 💅 Styles, release: patch}
- {type: refactor, title: 🛠 Code Refactoring, release: patch}
- {type: test, title: 🧪 Tests, release: patch}
- {type: build, title: 🏗 Build System, release: patch}
- {type: ci, title: 🔧 Continuous Integration, release: patch}
branches:
- {name: main}
20 changes: 20 additions & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"include": ["src/**/*.ts"],
"exclude": [
"**/*.spec.ts",
"**/*.spec.js",
"src/components/**",
"src/overrides/**",
"src/pages/**",
"src/cs-pagefind/**",
"src/content/**",
"src/content.config.ts",
"src/integrations/**",
"src/styles/**",
"src/env.d.ts"
],
"reporter": [],
"all": true,
"cache": false,
"clean": true
}
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Keep `name: CI` — release.yml triggers on it via workflow_run.
name: CI

on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
ci:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
node-version: [20, 22, 24]
steps:
- uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint:check

- name: Type check
run: npx tsc --noEmit

- name: Build
run: npm run build

- name: Test
run: npm test

- name: Docs site
if: matrix.node-version == 24
run: npm run astro:build
70 changes: 70 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Release

# Triggered by CI completing successfully on main. CI is the gate; release
# never runs unless CI passed. This catches admin force-pushes that bypass checks.
on:
workflow_run:
workflows: [CI]
types: [completed]
branches: [main]

permissions:
id-token: write # npm trusted publishing + AWS OIDC
contents: write # Required for autorel to push release tag (and changelog)

jobs:
release:
name: Release
if: >-
github.event.workflow_run.event == 'push'
&& github.event.workflow_run.conclusion == 'success'
&& github.event.workflow_run.head_repository.full_name == github.repository
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: deploy-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
env:
# prod CloudFront — stack: infra/prod/us-east-2/static/busker
PROD_ACCOUNT: ${{ secrets.AWS_ACCOUNT_PROD }}
PROD_AWS_REGION: us-east-2
PROD_DEPLOY_ROLE: gh-deploy-busker
PROD_SSM_BUCKET_PARAM: /logfox/prod/busker/assetsBucket
PROD_SSM_DISTRIBUTION_PARAM: /logfox/prod/busker/cloudfrontDistributionId
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
fetch-tags: true

- uses: actions/setup-node@v6
with:
node-version: '24' # npm 11+ required for trusted publishing (OIDC)
registry-url: 'https://registry.npmjs.org'
cache: 'npm'

- run: npm ci

- name: Publish npm package
run: npx autorel@^2 --publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.PROD_AWS_REGION }}
role-to-assume: arn:aws:iam::${{ env.PROD_ACCOUNT }}:role/${{ env.PROD_DEPLOY_ROLE }}

- name: Load publish targets from SSM
run: |
set -eux
echo "S3_BUCKET=$(aws ssm get-parameter --name "$PROD_SSM_BUCKET_PARAM" --query Parameter.Value --output text)" >> "$GITHUB_ENV"
echo "DISTRIBUTION_ID=$(aws ssm get-parameter --name "$PROD_SSM_DISTRIBUTION_PARAM" --query Parameter.Value --output text)" >> "$GITHUB_ENV"

- name: Deploy docs site
run: ./deploy-docs.sh
env:
S3_BUCKET: ${{ env.S3_BUCKET }}
DISTRIBUTION_ID: ${{ env.DISTRIBUTION_ID }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.idea
.vscode
.vscode/*
!.vscode/settings.json
.DS_Store
node_modules
dist
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
For coding agents: read [skills/busker/SKILL.md](skills/busker/SKILL.md).
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<div align="center">
<picture>
<source srcset="assets/busker-lockup-dark.svg" media="(prefers-color-scheme: dark)" />
<source srcset="assets/busker-lockup-light.svg" media="(prefers-color-scheme: light)" />
<img src="assets/busker-lockup-light.svg" width="220" alt="busker" />
</picture>
<h3 align="center">Scripted cursor demos that really click.</h3>
<p align="center">
<a href="https://busker.logfox.ai">busker.logfox.ai</a>
</p>
</div>

Fake product demos on a landing page usually rot. The cursor is on one timeline, the page state is on another, and the moment you change a duration they drift &mdash; the cursor presses a button 200ms before the modal it opened, forever.

Busker gets rid of the second timeline. You give it a list of places the cursor goes, it glides there and **really clicks the element**, and your own handlers change the page. Nothing is timed except the pauses, so there is nothing to keep in sync.

```typescript
import {busk} from 'busker';
import 'busker/busker.css';

busk(document.querySelector('.app'), {
scene: 'home',
steps: [
{click: '[data-nav-item="alerts"]', wait: 900},
{click: '[data-row="p0"]', wait: 1500},
{to: [0.55, 0.25], wait: 2600},
],
routes: [
{click: '[data-nav-item="alerts"]', scene: 'alerts'},
{click: '[data-row="p0"]', scene: 'case'},
],
});
```

The show loops while the mock is on screen and stops when the tab is in the background. The first time a visitor clicks, busker steps aside &mdash; the cursor disappears and the mock is theirs to poke at. Click something dead and it flashes what is not.

Zero dependencies, about 4kB, no build step, no framework.

## Quick start

```bash
npm i busker
```

[Getting started](src/content/docs/getting-started.md) is a working demo in four steps.

## Contents

Same guides as [busker.logfox.ai](https://busker.logfox.ai). Links are repo-relative, so they work in a checkout and on GitHub.

### Introduction

- [Getting started](src/content/docs/getting-started.md)
- [Markup](src/content/docs/markup.md) &mdash; the five attributes busker reads and the classes it writes

### Routines

- [Click-driven routines](src/content/docs/routines.md) &mdash; steps, timing, and routes
- [Hand-timed routines](src/content/docs/timeline.md) &mdash; for what no click causes: streaming logs, typing, countdowns
- [When a visitor takes over](src/content/docs/taking-over.md)

### Reference

- [API reference](src/content/docs/api-reference.md)
- [Styling](src/content/docs/styling.md)

### Project

- [Development](src/content/docs/development.md)

## License

MIT
8 changes: 8 additions & 0 deletions assets/busker-lockup-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions assets/busker-lockup-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/favicon.svg
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 assets/fonts/inter-latin-wght-normal.woff2
Binary file not shown.
Binary file added assets/fonts/jetbrains-mono-nerd-mono-400.woff2
Binary file not shown.
Binary file added assets/fonts/jetbrains-mono-nerd-mono-600.woff2
Binary file not shown.
5 changes: 5 additions & 0 deletions assets/mark-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/mark-light.svg
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 assets/og.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading