@xtatistix/tour-agent-demo
v0.1.1
Published
Static interactive demo player for TourAgent landing pages
Readme
@xtatistix/tour-agent-demo
Framework-agnostic DOM capture and static demo package for landing pages, onboarding flows, and step-by-step product walkthroughs.
This package now covers two related jobs:
- capture live DOM states step by step and export them as static demo assets
- render static demo snapshots in an isolated
ShadowRootoriframe - load exported capture sets back from
manifest.jsonand play them directly
It stays browser-native and does not depend on React, Vue, or Angular.
Install
npm install @xtatistix/tour-agent-demoCapture Flow Example
import {
createCaptureSession,
mountCaptureWidget,
exportCaptureSession,
} from '@xtatistix/tour-agent-demo';
const session = createCaptureSession({
projectName: 'analysis-demo',
scope: document,
sanitize: {
textInputMode: 'preserve',
sensitiveValueMode: 'mask',
},
});
const widget = mountCaptureWidget({
session,
position: 'bottom-left',
});
window.demoCapture = {
capture: (label) => session.captureStep({ label }),
export: () => exportCaptureSession(session),
destroy: () => widget.destroy(),
};The floating widget adds a tiny isolated panel with:
Capture StepExport SessionClear Steps- optional label input
Each click stores a sanitized snapshot in memory, so the user can move through a wizard or modal flow and capture each visible state in order.
Output Format
Exported sessions produce a small manifest plus one HTML file per step:
analysis-demo/
manifest.json
step-001.html
step-002.html
step-003.htmlExample manifest:
{
"version": 1,
"captureSetId": "analysis-demo-lt9v5o-a1b2c3",
"projectName": "analysis-demo",
"createdAt": "2026-04-04T09:00:00.000Z",
"steps": [
{
"id": "step-001",
"order": 1,
"file": "step-001.html",
"label": "Initial screen",
"createdAt": "2026-04-04T09:00:02.000Z",
"sourceUrl": "https://app.example.com/wizard",
"scope": { "type": "document" },
"title": "Wizard"
}
]
}Public API
createCaptureSession(config)
Creates an in-memory capture set.
const session = createCaptureSession({
projectName: 'analysis-demo',
scope: document,
sanitize: {
textInputMode: 'preserve',
sensitiveValueMode: 'mask',
},
});Session methods:
session.captureStep({ label?, scope?, sanitize? })session.getSteps()session.getStepCount()session.getManifest()session.clear()session.export()
captureDOMSnapshot(options)
Captures a single sanitized snapshot without creating a session.
const snapshot = captureDOMSnapshot({
scope: '#wizard-root',
});exportCaptureSession(session, options)
Uses progressive enhancement for saving:
File System Access APIwhen available- browser downloads when not available
By default, supported browsers ask the user to pick a directory and then create a subfolder named after the project.
await exportCaptureSession(session);sanitizeSnapshotHTML(rootOrHtml, options)
Creates a static, safer HTML document from a Document, Element, selector-backed scope, or raw HTML string.
Default sanitization includes:
- remove
script,iframe,noscript,object,embed - remove inline event handlers like
onclick - strip common third-party widget and consent containers
- clear hidden inputs
- clear passwords and file inputs
- mask or clear sensitive token/auth-like values
- neutralize dangerous URLs such as
javascript: - inject a
<base>tag so exported demos resolve relative assets more reliably later
Scoped Capture
The first-class path is full-page capture via document, but the API is ready for narrower scopes:
const session = createCaptureSession({
projectName: 'pricing-flow',
scope: '#pricing-wizard',
});When the scope is an element instead of the full document, the export still includes the current page <head> so stylesheets and CSS remain available for later playback.
Static Playback API
The earlier player API remains available for rendering captured HTML snapshots in an isolated surface:
import { createDemoPlayer } from '@xtatistix/tour-agent-demo';
const player = createDemoPlayer({
container: '#interactive-demo',
isolation: 'iframe',
initialStep: 1,
snapshots: {
'1': '<div><button data-tour-id="cta">Start</button></div>',
'2': '<div><button data-tour-id="review">Review</button></div>',
},
});If you already exported a capture set, you no longer need to hand-build the snapshots map yourself.
import { createCapturePlayback } from '@xtatistix/tour-agent-demo';
const playback = await createCapturePlayback({
container: '#demo-root',
manifestUrl: '/demo/analysis-demo/manifest.json',
isolation: 'iframe',
});
document.querySelector('[data-next]').addEventListener('click', () => {
playback.next();
});
document.querySelector('[data-prev]').addEventListener('click', () => {
playback.prev();
});This path is the recommended one for exported sessions because iframe playback now preserves full exported documents, including <head> content and linked CSS.
Browser Notes
- Directory export depends on the File System Access API, which is not available in every browser.
- Download fallback saves each file separately with a project-name prefix.
- Open shadow roots from third-party components are not serialized deeply in this version.
- Runtime canvas contents are not rasterized in this version.
- Relative assets are helped by the injected
<base>tag, but cross-origin or authenticated assets can still fail during playback. - If the original page relied on runtime-injected CSS that is not reachable anymore, playback can still look incomplete.
Future Playback Readiness
The capture/export format is designed to plug into a later iframe playback layer:
- one HTML file per captured step
- a small manifest for ordering and labels
- per-step source metadata
- sanitized static HTML that can be fed into
iframe.srcdoc
