Overview
Automated product-demo runtime for AbsoluteJS.
@absolutejs/demov0.0.1-beta.0betaFrontend & UXAutomated product-demo runtime that drives browser and desktop workflows, records the screen, highlights the UI, and narrates with AI voiceover.
@absolutejs/demo is an automated product-demo runtime: it drives your product through browser and desktop workflows, records the screen, draws presenter-style highlights over the UI, and coordinates AI voiceover. It is adapter-first — Playwright covers web apps, while desktop drivers, command recorders, and voiceover providers sit behind stable interfaces so each environment plugs in the right driver. Sign-in is profile-based with credentials resolved from env references, so secrets never enter the script, manifest, or recording.
bun add @absolutejs/demoAutomated product-demo runtime for AbsoluteJS.
@absolutejs/demo is the orchestration layer for enterprise-grade AI demos: drive the product, narrate with AI voiceover, record the screen, and draw presenter-style highlights over the UI.
It is intentionally adapter-first. Playwright is excellent for web apps, but real demos often need Discord, Google Meet, native apps, screen switching, and OS-level focus control. This package keeps those capabilities behind stable interfaces so each environment can provide the right driver.
Sign-in is profile-based. Declare named credential profiles on the script and trigger them with signIn("") steps. Credentials are passed as env references ({ env: "VAR_NAME" }) — the runner resolves them at sign-in time, so real secrets never enter the script object, the manifest, or the recording. A missing env var throws an error naming the variable, never its value.
Three profile kinds cover the common cases:
absolute — a site you own that uses @absolutejs/auth. Posts to the auth
login route (/auth/login by default, or routes.login).
form — any site, including ones you don't control. Drives the real login
UI: navigates to loginUrl, fills fields (with secrets from env), clicks submitSelector, and confirms via a success selector and/or URL. A steps array handles multi-step flows (username → Next → password).
storage-state — reuse a saved Playwright session; applied when the browser
context is created.
See examples/demo/src/sign-in.ts for runnable own-site (absolute) and third-party (form) examples. For bespoke auth screens, provide your own DemoAuthDriver.
createMacDesktopDriver and createCommandDesktopDriver open, focus, and key into native apps for demos that leave the browser.
createCommandRecorder wraps tools such as ffmpeg, OBS command bridges, or platform-native recorders. Browser-only demos can also use Playwright video and add the resulting path as a recording artifact.
ElevenLabs is the recommended tier for client demos — Deepgram Aura is faster and cheaper but reads more synthetic. createElevenLabsVoiceover defaults to an American voice (Rachel) and the tuned runtime settings from the Dealroom voice upgrade (eleven_flash_v2_5, stability 0.42, similarity boost 0.78, style 0.35, speaker boost on), rendering high-fidelity mp3_44100_128 files.
input.emotion (neutral | confident | excited | calm) nudges the expressive controls. The narration voice field overrides the voice id per line. Both pronunciation aliasing and the render cache are provider-agnostic wrappers — they work over the Aura and generic-adapter voiceovers too.
Set ELEVENLABS_API_KEY (restricted synthesis key) for rendering; ELEVENLABS_ADMIN_API_KEY (write-capable) is reserved for future pronunciation-dictionary sync and should stay out of the synthesis path. See .env.example.
composeDemoWithFFmpeg creates a final video artifact from the run recording and voiceover artifacts. It uses the demo timeline to offset narration against the recorded screen.
createDemoRunner executes declarative step scripts — signIn, goto, narrate, spotlight, openApp, wait — and returns a report with timeline and artifacts.
Named credential profiles cover your own @absolutejs/auth site, any third-party login form, or a saved Playwright storage state. Secrets stay in env vars.
createPlaywrightDemoSession provides the browser driver, screenshots, video recording, and on-page annotations for spotlight steps.
createElevenLabsVoiceover renders high-fidelity narration, with provider-agnostic pronunciation aliasing and a render cache so re-runs skip re-synthesis.
composeDemoWithFFmpeg merges the screen recording and voiceover artifacts into a final video, offset against the demo timeline.
Outcomes
Automated product-demo runtime for AbsoluteJS.
Install optional drivers only when needed:
Sign-in is profile-based. Declare named credential profiles on the script and trigger them with signIn("") steps. Credentials are passed as env references ({ env: "VAR_NAME" }) — the runner resolves them at sign-in time, so real secrets never enter the script object, the manifest, or the recording. A missing env var throws an error naming the variable, never its value.
Hardening checklist
Follow in order
Install optional drivers only when needed:
bun add -d playwrightWorking example for Browser demo.
import {
createDemoRunner,
goto,
narrate,
signIn,
spotlight,
writeDemoManifest,
} from "@absolutejs/demo";
import { createDemoAuthDriver } from "@absolutejs/demo/auth";
import {
createPlaywrightDemoSession,
} from "@absolutejs/demo/playwright";
const session = await createPlaywrightDemoSession({
headless: false,
recordVideoDir: ".demo-video",
screenshotDir: ".demo-shots",
});
const runner = createDemoRunner({
auth: createDemoAuthDriver(),
browser: session.browserDriver,
annotations: session.annotations,
voiceover: {
speak: async ({ text }) => {
console.log("[voiceover]", text);
},
},
});
const report = await runner.run({
profiles: [
{
id: "ae",
kind: "absolute",
baseUrl: "http://localhost:3000",
email: { env: "DEMO_EMAIL" },
password: { env: "DEMO_PASSWORD" },
afterLoginUrl: "http://localhost:3000/pipeline",
},
],
id: "crm-demo",
title: "CRM demo",
steps: [
signIn("ae"),
narrate("Here is the live pipeline view."),
goto("http://localhost:3000/pipeline"),
spotlight({
selector: "[data-demo='pipeline-total']",
label: "Revenue at risk",
durationMs: 1800,
}),
],
});
await writeDemoManifest(report, ".demo-artifacts/crm-demo.manifest.json");
console.log(report.status, report.artifacts);
await session.close();Sign-in is profile-based. Declare named credential profiles on the script and trigger them with signIn("") steps. Credentials are passed as env references ({ env: "VAR_NAME" }) — the runner resolves them at sign-in time, so real secrets never enter the script object, the manifest, or the recording. A missing env var throws an error naming the variable, never its value.
// A third-party site you do not control:
{
id: "saucedemo",
kind: "form",
loginUrl: "https://www.saucedemo.com/",
fields: [
{ selector: "#user-name", value: { env: "SAUCE_USERNAME" } },
{ selector: "#password", value: { env: "SAUCE_PASSWORD" } },
],
submitSelector: "#login-button",
success: { selector: ".inventory_list" },
}Drive a browser demo: sign in with an env-backed profile, narrate, navigate, spotlight an element, and write the run manifest.
import {
createDemoRunner,
goto,
narrate,
signIn,
spotlight,
writeDemoManifest
} from '@absolutejs/demo';
import { createDemoAuthDriver } from '@absolutejs/demo/auth';
import { createPlaywrightDemoSession } from '@absolutejs/demo/playwright';
const session = await createPlaywrightDemoSession({
headless: false,
recordVideoDir: '.demo-video',
screenshotDir: '.demo-shots'
});
const runner = createDemoRunner({
annotations: session.annotations,
auth: createDemoAuthDriver(),
browser: session.browserDriver,
voiceover: {
speak: async ({ text }) => {
console.log('[voiceover]', text);
}
}
});
const report = await runner.run({
id: 'crm-demo',
profiles: [
{
afterLoginUrl: 'http://localhost:3000/pipeline',
baseUrl: 'http://localhost:3000',
email: { env: 'DEMO_EMAIL' },
id: 'ae',
kind: 'absolute',
password: { env: 'DEMO_PASSWORD' }
}
],
steps: [
signIn('ae'),
narrate('Here is the live pipeline view.'),
goto('http://localhost:3000/pipeline'),
spotlight({
durationMs: 1800,
label: 'Revenue at risk',
selector: "[data-demo='pipeline-total']"
})
],
title: 'CRM demo'
});
await writeDemoManifest(report, '.demo-artifacts/crm-demo.manifest.json');
console.log(report.status, report.artifacts);
await session.close();Render narration with ElevenLabs, wrapped in the provider-agnostic pronunciation-alias and render-cache helpers.
import {
createElevenLabsVoiceover,
withPronunciationAliases,
withRenderCache
} from '@absolutejs/demo/voiceover';
// Premium voiceover with demo-vocabulary pronunciation fixes applied
// before TTS, and identical lines cached so re-runs skip re-synthesis.
const voiceover = withRenderCache(
withPronunciationAliases(
createElevenLabsVoiceover({
apiKey: process.env.ELEVENLABS_API_KEY ?? '',
outputDir: '.demo-voiceover'
})
),
{ cacheDir: '.demo-voiceover/cache', salt: 'rachel:flash_v2_5' }
);Produce the final demo video from a run report by composing recording and voiceover artifacts with FFmpeg.
import { composeDemoWithFFmpeg } from '@absolutejs/demo/composition';
// Merge the run recording and voiceover artifacts into a final video,
// offsetting narration against the recorded screen via the demo timeline.
const finalVideo = await composeDemoWithFFmpeg(report, {
outputPath: '.demo-artifacts/crm-demo.mp4'
});Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.
Current package surface
Import surface · click to copy