autokap 1.6.2 → 1.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-config.js +69 -25
- package/dist/cli-contract.d.ts +19 -5
- package/dist/cli-contract.js +55 -151
- package/dist/cli-doctor.d.ts +0 -1
- package/dist/cli-doctor.js +15 -143
- package/dist/cli-runner.d.ts +1 -1
- package/dist/cli-runner.js +2 -2
- package/dist/cli.js +24 -1163
- package/dist/execution-schema.d.ts +3 -3
- package/dist/program-signing.d.ts +1 -1
- package/dist/skill-packaging.d.ts +0 -16
- package/dist/skill-packaging.js +1 -51
- package/dist/video-narration-schema.d.ts +1 -1
- package/package.json +2 -6
- package/readme.md +15 -12
- package/assets/skill/OPCODE-REFERENCE.md +0 -625
- package/assets/skill/README.md +0 -38
- package/assets/skill/SKILL.md +0 -590
- package/assets/skill/references/STANDARDS.md +0 -236
- package/assets/skill/references/examples.md +0 -88
- package/assets/skill/references/mock-data.md +0 -178
- package/dist/auth-capture.d.ts +0 -17
- package/dist/auth-capture.js +0 -199
- package/dist/cli-utils.d.ts +0 -5
- package/dist/cli-utils.js +0 -14
- package/dist/version-check.d.ts +0 -4
- package/dist/version-check.js +0 -102
package/assets/skill/SKILL.md
DELETED
|
@@ -1,590 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: autokap-preset
|
|
3
|
-
description: >
|
|
4
|
-
Generate AutoKap capture programs — deterministic opcode sequences for automated
|
|
5
|
-
screenshot and clip capture of web apps. Use when: creating or updating presets,
|
|
6
|
-
adding data-ak attributes for capture automation, or debugging failed capture programs.
|
|
7
|
-
metadata:
|
|
8
|
-
author: AutoKap
|
|
9
|
-
version: 2.3.0
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# AutoKap Preset Creation Skill
|
|
13
|
-
|
|
14
|
-
## Mental Model
|
|
15
|
-
|
|
16
|
-
AutoKap is **not** a freeform runtime navigation agent. Your job is to inspect the user's codebase, add stable selectors where needed, and generate a **deterministic program** (a JSON sequence of browser opcodes) that the AutoKap CLI executes locally via Playwright.
|
|
17
|
-
|
|
18
|
-
Normal navigation and interaction stay deterministic. Runtime AI is limited to narrow fallback tasks such as overlay dismissal fallback, capture verification, alt text generation, and the last-resort healer. Do **not** design flows that depend on an LLM improvising navigation at runtime.
|
|
19
|
-
|
|
20
|
-
This installed skill is the **source of truth** for the AutoKap contract: opcode schema, login rules, variant handling, persistence, and validation. The copied prompt from the AutoKap dashboard is only the **preset-specific brief** (project URL, variants, template goal, mock data guidance, etc.).
|
|
21
|
-
|
|
22
|
-
> **Compatibility note.** The dashboard prompts now embed a mini AutoKap mental-model so they remain useful for assistants that don't have this skill installed (Cursor without the bundle, Codex, Copilot, plain Claude Code). When this skill IS installed, **the rules below override anything that contradicts them in the inline mental-model** — the inline version is necessarily a summary.
|
|
23
|
-
|
|
24
|
-
## When To Use This Skill
|
|
25
|
-
|
|
26
|
-
- User wants to capture screenshots or clips of their web app
|
|
27
|
-
- User asks to create or update an AutoKap preset
|
|
28
|
-
- User needs `data-ak` attributes added to UI elements for capture
|
|
29
|
-
- User is debugging a failed capture program
|
|
30
|
-
|
|
31
|
-
## Before Generating Anything
|
|
32
|
-
|
|
33
|
-
1. **Inspect the codebase first** — Read the relevant routes, layouts, auth checks, theme/locale system, and the components you may need to tag. Do not start by guessing opcodes.
|
|
34
|
-
2. **Decide whether auth is required** — If any target route is protected, the program must begin with the canonical login flow. Never assume the user is already logged in.
|
|
35
|
-
3. **Understand how locale and theme really work** — Prefer storage-based `SET_LOCALE` / `SET_THEME` with `"$variant"` when the app supports it. If the app uses URL-based locale routing, reflect that in `NAVIGATE`.
|
|
36
|
-
4. **Understand the UI states** — Know which conditions make modals, dropdowns, tabs, tables, empty states, or dashboards appear before you write selectors or opcodes.
|
|
37
|
-
5. **Use planning mode if the assistant supports it** — Make a short plan before editing code or generating the program.
|
|
38
|
-
6. **Ask clarifying questions when navigation is ambiguous** — If the codebase or prompt does not clearly reveal how to reach a state, ask instead of inventing UI details.
|
|
39
|
-
7. **Do not break the one-shot flow** — When CLI access is available, persist the preset so the user can run `autokap run <preset-id>` immediately. Manual JSON output is a fallback, not the default.
|
|
40
|
-
|
|
41
|
-
## Quick Workflow
|
|
42
|
-
|
|
43
|
-
1. **Understand the capture goal** — What pages/states should be captured? Screenshot or clip? Which viewports, locales, themes, and mockups matter?
|
|
44
|
-
2. **Inspect the implementation** — Confirm routes, auth, theme, locale, and any dynamic UI state in the codebase.
|
|
45
|
-
3. **Add `data-ak` attributes** — Tag every element the opcodes must interact with using stable selectors.
|
|
46
|
-
4. **Choose media mode and variants** — Set `mediaMode` and define the exact viewport/locale/theme combinations.
|
|
47
|
-
5. **Generate the `ExecutionProgram`** — Write deterministic opcodes and explicit postconditions.
|
|
48
|
-
6. **Persist the preset** — Prefer `autokap preset create|update` so the program lives inside `config.program`.
|
|
49
|
-
7. **Validate it** — Run the recommended checks and at least one real `autokap run <preset-id>` before considering the work done.
|
|
50
|
-
8. **Integrate dev links** — Run `autokap preset info <preset-id>` and use the structured output to wire endpoint URLs into the codebase (`<img>`, `<video>`, `<iframe>`, or component props). This is part of the one-shot flow — do not stop after validation.
|
|
51
|
-
|
|
52
|
-
## Bundled References
|
|
53
|
-
|
|
54
|
-
Load these only when the request actually needs them:
|
|
55
|
-
|
|
56
|
-
- **Opcode parameters** — [OPCODE-REFERENCE.md](OPCODE-REFERENCE.md)
|
|
57
|
-
- **Mock data** — [references/mock-data.md](references/mock-data.md)
|
|
58
|
-
- **Complete examples** — [references/examples.md](references/examples.md)
|
|
59
|
-
- **Prompt charter** — [references/STANDARDS.md](references/STANDARDS.md) — defines the structure every dashboard-generated prompt now follows. Use it when authoring new prompts, when extending existing builders, or to understand why a copied prompt is shaped the way it is.
|
|
60
|
-
|
|
61
|
-
Keep the core `SKILL.md` for the non-negotiable contract. Reach for the
|
|
62
|
-
references only after you know which mode or advanced feature the user needs.
|
|
63
|
-
|
|
64
|
-
## Adding `data-ak` Attributes
|
|
65
|
-
|
|
66
|
-
For every element you interact with in the opcodes, add a `data-ak="descriptive-name"` attribute:
|
|
67
|
-
|
|
68
|
-
```jsx
|
|
69
|
-
// Before
|
|
70
|
-
<button onClick={handleLogin}>Sign in</button>
|
|
71
|
-
<input type="email" placeholder="Email" />
|
|
72
|
-
|
|
73
|
-
// After
|
|
74
|
-
<button data-ak="login-btn" onClick={handleLogin}>Sign in</button>
|
|
75
|
-
<input data-ak="login-email" type="email" placeholder="Email" />
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
**Rules:**
|
|
79
|
-
- Use kebab-case: `login-btn`, `pricing-table`, `theme-toggle`
|
|
80
|
-
- Add ONLY to elements that opcodes interact with
|
|
81
|
-
- For dynamic lists, add `data-ak` to the container AND item template:
|
|
82
|
-
```jsx
|
|
83
|
-
<ul data-ak="project-list">
|
|
84
|
-
{projects.map(p => <li data-ak="project-item" key={p.id}>{p.name}</li>)}
|
|
85
|
-
</ul>
|
|
86
|
-
```
|
|
87
|
-
Target: `[data-ak="project-list"] [data-ak="project-item"]:nth-child(2)`
|
|
88
|
-
- Zero runtime cost and no security implications
|
|
89
|
-
|
|
90
|
-
## ExecutionProgram Schema
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
interface ExecutionProgram {
|
|
94
|
-
presetId: string; // Unique slug (e.g. "homepage-hero")
|
|
95
|
-
programVersion: number; // Always 1 for new programs
|
|
96
|
-
mediaMode: 'screenshot' | 'clip' | 'video';
|
|
97
|
-
baseUrl: string; // Root URL of the application
|
|
98
|
-
variants: VariantSpec[]; // Viewport/locale/theme combinations
|
|
99
|
-
preconditions: {
|
|
100
|
-
// Auth bootstrap auto-adapts to whatever is configured on the preset.
|
|
101
|
-
// If the preset has stored auth cookies, the runtime injects them into
|
|
102
|
-
// the browser context. If it has stored credentials (email/password), they
|
|
103
|
-
// are substituted into {{email}}/{{password}}/{{loginUrl}} placeholders
|
|
104
|
-
// inside opcodes — the program performs the UI login itself.
|
|
105
|
-
// If neither is set, the run is anonymous. Both can coexist.
|
|
106
|
-
credentialsId?: string; // Optional metadata pointer
|
|
107
|
-
};
|
|
108
|
-
steps: ExecutionOpcode[];
|
|
109
|
-
artifactPlan: {
|
|
110
|
-
mediaMode: 'screenshot' | 'clip' | 'video';
|
|
111
|
-
cursorTheme?: 'minimal' | 'macos' | 'windows'; // Clip/video recordings. Default: 'minimal'
|
|
112
|
-
format?: {
|
|
113
|
-
clipFormat?: 'gif' | 'mp4' | 'both'; // Default: 'gif'
|
|
114
|
-
screenshotFormat?: 'png' | 'jpeg'; // Default: 'png'
|
|
115
|
-
// Video-only — required when mediaMode='video'.
|
|
116
|
-
// captureResolution must be 1920×1080; legacy 2560×1440 is normalized by AutoKap.
|
|
117
|
-
// captureFps defaults to 30; deliveryResolution defaults to 1920×1080.
|
|
118
|
-
captureResolution?: { width: number; height: number };
|
|
119
|
-
captureFps?: number;
|
|
120
|
-
deliveryResolution?: { width: number; height: number };
|
|
121
|
-
};
|
|
122
|
-
applyMockup?: boolean; // Apply device frame mockup
|
|
123
|
-
applyStatusBar?: boolean; // Add status bar to mockup
|
|
124
|
-
};
|
|
125
|
-
compileFingerprint: string; // e.g. "v1-homepage"
|
|
126
|
-
variantFingerprint?: string; // "langs:en,fr|themes:dark,light"
|
|
127
|
-
compiledAt: string; // ISO timestamp
|
|
128
|
-
compiledWith?: string; // "ai-assistant"
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
interface VariantSpec {
|
|
132
|
-
id: string; // e.g. "desktop-en-light"
|
|
133
|
-
viewport: { width: number; height: number };
|
|
134
|
-
deviceScaleFactor?: number;
|
|
135
|
-
locale?: string; // BCP-47 (e.g. "en", "fr")
|
|
136
|
-
theme?: 'light' | 'dark';
|
|
137
|
-
targetId?: string; // Stable preset target id (e.g. "desktop")
|
|
138
|
-
targetLabel?: string; // Human-readable label (e.g. "Desktop")
|
|
139
|
-
deviceFrame?: string; // e.g. "iphone-16-pro" for mockup
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Opcode Quick Reference
|
|
144
|
-
|
|
145
|
-
24 opcodes available. For full parameter documentation, see [OPCODE-REFERENCE.md](OPCODE-REFERENCE.md).
|
|
146
|
-
|
|
147
|
-
| Kind | Selector? | Key Params | Typical Postcondition | Notes |
|
|
148
|
-
|------|-----------|-----------|----------------------|-------|
|
|
149
|
-
| `NAVIGATE` | no | `url` | `route_matches` | Always first step |
|
|
150
|
-
| `DISMISS_OVERLAYS` | no | — | `overlay_dismissed` | Always after NAVIGATE |
|
|
151
|
-
| `CLICK` | yes | `button?` | `element_visible` / `route_matches` | Postcondition = what CHANGED |
|
|
152
|
-
| `TYPE` | yes | `text`, `clearFirst` | `any_change` | `{{email}}` / `{{password}}` for creds |
|
|
153
|
-
| `PRESS_KEY` | no | `key` | specific result / `any_change` | `"Enter"`, `"Escape"`, `"Tab"`, etc.; use `any_change` only when the key must visibly change state |
|
|
154
|
-
| `WAIT_FOR` | yes* | `state` | `element_visible` | `"visible"` or `"attached"` (DOM only) |
|
|
155
|
-
| `SLEEP` | no | `durationMs` (1..60000), `narrationTextByLocale?` | `always` | Pause N ms. Reserved for video narration anchors. Use `durationMs: 1` as a placeholder; AutoKap rewrites it during `autokap run` after generating TTS. |
|
|
156
|
-
| `SCROLL` | no | `direction`, `targetSelector?`, `amount?` | `element_visible` | Use `targetSelector` for precise scroll |
|
|
157
|
-
| `HOVER` | yes | — | `element_visible` | Capture immediately after for hover state |
|
|
158
|
-
| `SELECT_OPTION` | yes | `optionLabel` / `optionValue` / `optionIndex` | `text_contains` | **Native `<select>` only.** Custom dropdowns: use CLICK sequence |
|
|
159
|
-
| `CHECK` | yes | `checked` | `always` | Idempotent. Safer than CLICK for checkboxes |
|
|
160
|
-
| `DOUBLE_CLICK` | yes | — | `element_visible` / `any_change` | Inline editing, text selection |
|
|
161
|
-
| `DRAG` | yes | `toSelector?` / `toTarget?` / `offset?` | `element_visible` / `any_change` | Animated cursor A→B. Use `toSelector` for Kanban-style drops, `offset` for sliders / canvas |
|
|
162
|
-
| `SET_LOCALE` | no | `locale`, `method`, `storageHints?` | `always` | Use `"$variant"`. Prefer `method: "storage"` |
|
|
163
|
-
| `SET_THEME` | no | `theme`, `method`, `storageHints?` | `always` | Use `"$variant"`. Prefer `method: "storage"` |
|
|
164
|
-
| `ASSERT_ROUTE` | no | `urlPattern` | `always` / matching `route_matches` | `urlPattern` is the source of truth |
|
|
165
|
-
| `ASSERT_SURFACE` | no | `selectors[]`, `matchAll` | `always` / matching `element_visible` | `selectors` + `matchAll` are the source of truth |
|
|
166
|
-
| `CAPTURE_SCREENSHOT` | no | `captureId`, `captureName`, `elementSelector?`, `outscale?` | `always` | `elementSelector` for element-level crop. `outscale` adds padding around the element (user-edited post-generation; omit by default) |
|
|
167
|
-
| `BEGIN_CLIP` | no | `clipId`, `clipName` | `always` | Start recording |
|
|
168
|
-
| `END_CLIP` | no | `clipId`, `clipName` | `always` | Stop recording. Same `clipId` as BEGIN_CLIP |
|
|
169
|
-
| `CLONE_ELEMENT` | yes | `sourceSelector`, `containerSelector`, `count` | `always` | **Non-blocking.** Duplicate a template element N times |
|
|
170
|
-
| `INJECT_MOCK_DATA` | yes | `groupName` + clone fields and/or trigger fields | `always` | **Non-blocking.** Apply both clone (instant visual) AND trigger (survives re-renders) whenever possible |
|
|
171
|
-
| `REMOVE_ELEMENT` | yes | `selector` | `always` | **Non-blocking.** Remove empty-state placeholders / unwanted nodes |
|
|
172
|
-
| `SET_ATTRIBUTE` | yes | `attribute`, `value` | `always` | **Non-blocking.** Set attribute (e.g. `src` on an `<img>`) |
|
|
173
|
-
|
|
174
|
-
*WAIT_FOR requires `selector` or semantic `target`.
|
|
175
|
-
|
|
176
|
-
## Postcondition Types
|
|
177
|
-
|
|
178
|
-
| Type | Fields | When to use |
|
|
179
|
-
|------|--------|-------------|
|
|
180
|
-
| `route_matches` | `pattern` | After NAVIGATE, CLICK that changes page |
|
|
181
|
-
| `element_visible` | `selector`, `waitMs?` | After CLICK/HOVER that opens modal/dropdown/tooltip |
|
|
182
|
-
| `element_absent` | `selector` | After CLICK that closes modal |
|
|
183
|
-
| `text_contains` | `selector`, `text` | After TYPE, SELECT_OPTION |
|
|
184
|
-
| `overlay_dismissed` | — | After DISMISS_OVERLAYS |
|
|
185
|
-
| `screenshot_stable` | `threshold?` (0-1), `waitMs?` | Before CAPTURE_SCREENSHOT when page has animations |
|
|
186
|
-
| `any_change` | — | Verifier-backed state change after TYPE, CLICK, SELECT_OPTION, DOUBLE_CLICK, DRAG, etc.; no-op actions fail |
|
|
187
|
-
| `always` | — | CAPTURE_SCREENSHOT, SET_LOCALE, SET_THEME, CHECK, BEGIN/END_CLIP |
|
|
188
|
-
|
|
189
|
-
## What Presets Can and Cannot Do
|
|
190
|
-
|
|
191
|
-
### Capabilities
|
|
192
|
-
|
|
193
|
-
- **Multi-viewport**: desktop, tablet, mobile in a single program
|
|
194
|
-
- **Multi-locale**: switch languages via SET_LOCALE with `"$variant"` placeholder
|
|
195
|
-
- **Multi-theme**: switch light/dark via SET_THEME with `"$variant"` placeholder
|
|
196
|
-
- **Authenticated flows**: login via TYPE with `{{email}}`/`{{password}}` credential placeholders
|
|
197
|
-
- **Element-level capture**: crop screenshot to a specific component with `elementSelector`
|
|
198
|
-
- **Clips**: record interactions as GIF, MP4, or both via BEGIN_CLIP/END_CLIP
|
|
199
|
-
- **Device mockups**: wrap screenshots in device frames (`applyMockup: true`)
|
|
200
|
-
- **Status bars**: add device status bar to mockups (`applyStatusBar: true`)
|
|
201
|
-
- **Hover states**: capture tooltips, dropdown menus via HOVER + CAPTURE_SCREENSHOT
|
|
202
|
-
- **Scroll-to-element**: scroll specific sections into view with SCROLL
|
|
203
|
-
- **Right-click menus**: context menus via CLICK with `button: "right"`
|
|
204
|
-
- **Native selects**: option selection via SELECT_OPTION
|
|
205
|
-
- **Checkboxes/toggles**: idempotent state control via CHECK
|
|
206
|
-
|
|
207
|
-
### Limitations
|
|
208
|
-
|
|
209
|
-
- **No file uploads**: native OS file dialogs cannot be automated
|
|
210
|
-
- **No complex drag-and-drop**: simple clicks only, no drag gestures
|
|
211
|
-
- **No multi-tab workflows**: single page context per execution
|
|
212
|
-
- **No native OS dialogs**: print, save-as, permission prompts are inaccessible
|
|
213
|
-
- **No CAPTCHAs**: cannot solve CAPTCHAs or bot detection challenges
|
|
214
|
-
- **No real-time dynamic data**: data that changes between runs produces inconsistent captures
|
|
215
|
-
- **No cross-origin iframes**: cannot interact with content from different origins
|
|
216
|
-
- **No browser extensions**: extension UIs are not accessible via Playwright
|
|
217
|
-
|
|
218
|
-
## Anti-Patterns
|
|
219
|
-
|
|
220
|
-
| Do NOT | Do instead |
|
|
221
|
-
|--------|-----------|
|
|
222
|
-
| Use SELECT_OPTION for custom dropdowns (Radix, Headless UI, MUI) | CLICK to open + WAIT_FOR options + CLICK the option |
|
|
223
|
-
| Use CLICK for checkboxes | CHECK (idempotent, sets state directly) |
|
|
224
|
-
| Omit postconditions | Every opcode needs a postcondition describing the expected result |
|
|
225
|
-
| Hardcode locale/theme values in SET_LOCALE/SET_THEME | Use `"$variant"` — runtime substitutes the current variant's value |
|
|
226
|
-
| Use `method: "ui_interaction"` for locale/theme | Use `method: "storage"` — instant, reliable, no UI dependency |
|
|
227
|
-
| Tell the user to save a local `program.json` file | Persist the preset via CLI; only output full JSON as a fallback if the CLI/server write fails |
|
|
228
|
-
| Guess CSS selectors | Add `data-ak` attributes to the code first |
|
|
229
|
-
| Skip WAIT_FOR after page transitions | Add WAIT_FOR with `waitMs: 10000` after login, navigation, modal open |
|
|
230
|
-
| Use NAVIGATE inside a clip (between BEGIN_CLIP and END_CLIP) | Always CLICK the in-app element (sidebar Link, modal trigger button) or PRESS_KEY Escape to close modals. NAVIGATE is `page.goto` = full reload + white flash + cursor lost. See "Designing human-like clip programs" below for the patterns |
|
|
231
|
-
| Skip `cursorTheme` in clip `artifactPlan` | Set `cursorTheme: "macos"` or `"windows"` for polished recordings |
|
|
232
|
-
|
|
233
|
-
## Clip Workflow
|
|
234
|
-
|
|
235
|
-
For recording video clips of interactions:
|
|
236
|
-
|
|
237
|
-
1. Set `mediaMode: "clip"` on the program
|
|
238
|
-
2. Set `artifactPlan.format.clipFormat` to `"gif"`, `"mp4"`, or `"both"`
|
|
239
|
-
3. Set `artifactPlan.cursorTheme` to `"minimal"`, `"macos"`, or `"windows"` (default: `"minimal"`)
|
|
240
|
-
4. Put navigation and setup steps **before** BEGIN_CLIP (they won't be recorded)
|
|
241
|
-
5. Place `BEGIN_CLIP` with a `clipId` and `clipName` to start recording
|
|
242
|
-
6. All interaction steps between BEGIN_CLIP and END_CLIP are recorded
|
|
243
|
-
7. Place `END_CLIP` with the **same `clipId`** to stop recording
|
|
244
|
-
|
|
245
|
-
### Cursor animation (automatic)
|
|
246
|
-
|
|
247
|
-
During clip recording, the runtime automatically animates a visible cursor with **cubic Bézier curves** for every CLICK, HOVER, TYPE, CHECK, DOUBLE_CLICK, and SCROLL opcode. The cursor moves smoothly (350–900 ms depending on distance), with randomized control points and micro-jitter to look human. You do **not** need to script cursor movement yourself — just emit the right interaction opcodes and the runtime handles the animation.
|
|
248
|
-
|
|
249
|
-
### Designing human-like clip programs
|
|
250
|
-
|
|
251
|
-
Because the cursor is visible during recording, **how** you reach a target matters as much as reaching it:
|
|
252
|
-
|
|
253
|
-
| Do | Don't | Why |
|
|
254
|
-
|---|---|---|
|
|
255
|
-
| **CLICK** on a nav link / anchor to scroll to a section | SCROLL blindly then capture | The cursor animates to the link before clicking — the viewer sees intentional navigation |
|
|
256
|
-
| **CLICK** on an in-page `<Link>` (sidebar, breadcrumb, card) to change route | NAVIGATE to the new URL mid-clip | NAVIGATE always calls Playwright's `page.goto` — a full HTTP navigation that destroys the document, wipes the cursor overlay, and shows a white flash. Even SPAs are forced into a hard reload. CLICK lets Next.js / React Router intercept and use prefetched `router.push` instead — no flash, cursor preserved |
|
|
257
|
-
| **CLICK** on the modal's trigger button (e.g. `[data-ak-interact="new-preset-btn"]`) to open a modal | NAVIGATE to the modal's deep-link route | Most modals open via local React state, not URL navigation. The deep-link route exists for direct entry but forces a real reload — using the trigger button keeps the recording in one fluid take |
|
|
258
|
-
| **PRESS_KEY** `"Escape"` to close a modal (or CLICK its close button) | NAVIGATE back to the previous URL | Radix/shadcn dialogs (the AutoKap dashboard convention) close on Escape and run their `onClose` handler — which usually does the SPA route change internally. NAVIGATE back triggers another full reload |
|
|
259
|
-
| **HOVER** → pause → **CLICK** for important interactions | CLICK without HOVER | HOVER gives the viewer time to see where the cursor is heading and creates anticipation |
|
|
260
|
-
| Keep the clip short and focused (5–15 interactions) | Record an entire user journey in one clip | Long clips lose the viewer. Split into multiple clips if needed |
|
|
261
|
-
| Place WAIT_FOR after CLICK that triggers a route change | Immediately interact after navigation | Gives the page time to render and the viewer time to register the new state |
|
|
262
|
-
| Add a `screenshot_stable` WAIT_FOR before BEGIN_CLIP when DISMISS_OVERLAYS precedes it | Start recording immediately after DISMISS_OVERLAYS | Overlay dismiss animations (fade-out, slide) bleed into the first frames of the clip |
|
|
263
|
-
|
|
264
|
-
**Rule of thumb — NEVER `NAVIGATE` inside a clip.** NAVIGATE = `page.goto()` = full document reload, white flash, cursor overlay destroyed. There is no exception, even when the destination is on the same origin or the framework supports SPA routing — Playwright doesn't use the framework router. Reach every destination through the actual UI element a real user would interact with:
|
|
265
|
-
|
|
266
|
-
- **Page change** → `CLICK` on a `<Link>` (sidebar item, breadcrumb, card). If no Link points where you need to go, ask the user where the user-facing entry point is — don't invent a NAVIGATE workaround.
|
|
267
|
-
- **Open a modal** → `CLICK` on its trigger button (annotate it with `data-ak-interact="..."`). Even if the modal also has a deep-link URL, the trigger is the smooth path.
|
|
268
|
-
- **Close a modal** → `PRESS_KEY "Escape"` (or CLICK the close button if present). The modal's `onClose` handler does any required SPA route change for you.
|
|
269
|
-
- **Reveal off-screen content** → `SCROLL` is still fine when there's no clickable anchor (long content sections, lists inside a container).
|
|
270
|
-
|
|
271
|
-
If you find yourself wanting to write `NAVIGATE` between `BEGIN_CLIP` and `END_CLIP`, stop and reconsider — there is almost always an annotated UI element to CLICK instead. Add a `data-ak-interact` to the source if it's missing.
|
|
272
|
-
|
|
273
|
-
## Demo Video Workflow
|
|
274
|
-
|
|
275
|
-
For narrated demo videos (`mediaMode: "video"`), AutoKap captures a language/theme matrix:
|
|
276
|
-
|
|
277
|
-
1. Use **one desktop target** at 1920x1080. Do not multiply demo videos by device.
|
|
278
|
-
2. Generate one variant for every app locale x theme pair. Variant ids must be stable, for example `desktop-1920x1080-fr-dark`.
|
|
279
|
-
3. Add `SET_LOCALE` and `SET_THEME` with `"$variant"` during setup when the app supports locale/theme switching.
|
|
280
|
-
4. Put all recorded content inside `BEGIN_CLIP` / `END_CLIP`.
|
|
281
|
-
5. Every narrated pause is a `SLEEP` with `stepId`, `durationMs: 1`, and `narrationTextByLocale`.
|
|
282
|
-
|
|
283
|
-
Voice-over settings are row-based: each app locale maps to a spoken TTS locale and a voice in `narration_by_app_locale`. `narrationTextByLocale` is the source of truth for TTS text. It must include one entry for every spoken TTS locale used by those rows. AutoKap currently supports TTS for `en` and `fr`; unsupported TTS locales are rejected explicitly. Keep `narrationText` only as a legacy fallback for single-row demos.
|
|
284
|
-
|
|
285
|
-
```json
|
|
286
|
-
{
|
|
287
|
-
"kind": "SLEEP",
|
|
288
|
-
"stepId": "opening-hello",
|
|
289
|
-
"durationMs": 1,
|
|
290
|
-
"narrationTextByLocale": {
|
|
291
|
-
"en": "Hey, welcome — I'll show you the dashboard quickly.",
|
|
292
|
-
"fr": "Salut, bienvenue — je te montre rapidement le dashboard."
|
|
293
|
-
},
|
|
294
|
-
"description": "Narration anchor: opening greeting",
|
|
295
|
-
"postcondition": { "type": "always" },
|
|
296
|
-
"recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false },
|
|
297
|
-
"timeoutMs": 65000,
|
|
298
|
-
"maxFailures": 1
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
The server synthesizes TTS once per app-locale voice row, not once per theme. It rewrites every narrated `SLEEP.durationMs` to the maximum audio duration for that `stepId` across rows so the same runtime program can capture every variant.
|
|
303
|
-
|
|
304
|
-
### Clean start: wait for visual stability before recording
|
|
305
|
-
|
|
306
|
-
When `DISMISS_OVERLAYS` runs shortly before `BEGIN_CLIP`, overlay dismiss animations (fade-out, slide-away) can bleed into the first frames of the clip. Add a `screenshot_stable` WAIT_FOR between them so the page is visually settled before recording begins:
|
|
307
|
-
|
|
308
|
-
```json
|
|
309
|
-
{ "kind": "WAIT_FOR", "description": "Wait for page to be visually stable", "selector": "[data-ak=\"main-content\"]", "state": "visible", "postcondition": { "type": "screenshot_stable", "threshold": 0.01, "waitMs": 3000 }, "recovery": { "retries": 0, "useSelectorMemory": false, "useAltInteraction": false, "allowReload": false, "allowHealer": false }, "timeoutMs": 5000, "maxFailures": 1 }
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
Place this step **after** DISMISS_OVERLAYS + any content WAIT_FOR, and **immediately before** BEGIN_CLIP.
|
|
313
|
-
|
|
314
|
-
```json
|
|
315
|
-
{
|
|
316
|
-
"steps": [
|
|
317
|
-
{ "kind": "NAVIGATE", "url": "https://app.example.com", "..." : "..." },
|
|
318
|
-
{ "kind": "DISMISS_OVERLAYS", "..." : "..." },
|
|
319
|
-
{ "kind": "WAIT_FOR", "selector": "[data-ak=\"dashboard\"]", "state": "visible", "..." : "..." },
|
|
320
|
-
{ "kind": "WAIT_FOR", "description": "Let overlays finish animating", "selector": "[data-ak=\"dashboard\"]", "state": "visible", "postcondition": { "type": "screenshot_stable", "threshold": 0.01, "waitMs": 3000 }, "..." : "..." },
|
|
321
|
-
{ "kind": "BEGIN_CLIP", "clipId": "add-project", "clipName": "Add project", "postcondition": { "type": "always" }, "..." : "..." },
|
|
322
|
-
{ "kind": "CLICK", "selector": "[data-ak=\"add-project-btn\"]", "..." : "..." },
|
|
323
|
-
{ "kind": "TYPE", "selector": "[data-ak=\"project-name\"]", "text": "My Project", "clearFirst": true, "..." : "..." },
|
|
324
|
-
{ "kind": "CLICK", "selector": "[data-ak=\"save-btn\"]", "..." : "..." },
|
|
325
|
-
{ "kind": "END_CLIP", "clipId": "add-project", "clipName": "Add project", "postcondition": { "type": "always" }, "..." : "..." }
|
|
326
|
-
]
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
## Recovery System Overview
|
|
331
|
-
|
|
332
|
-
When an opcode fails, AutoKap tries 5 recovery strategies in order:
|
|
333
|
-
|
|
334
|
-
1. **Deterministic retry** — Same opcode, fresh page observation. Exponential backoff (500ms, 1000ms...).
|
|
335
|
-
2. **Selector memory** — Tries known-good selectors from previous successful runs stored in Supabase.
|
|
336
|
-
3. **Alternative interaction** — Keyboard (Tab+Enter), JS dispatch, coordinate-based click.
|
|
337
|
-
4. **Targeted reload** — Reloads the page and retries. **Loses UI state** (open modals, form data).
|
|
338
|
-
5. **LLM Healer** — AI analyzes the page screenshot and AKTree, then rewrites the failing opcode. Max 3 invocations per run.
|
|
339
|
-
|
|
340
|
-
**Guidance:** Keep `allowReload: false` for most steps (it loses state). Set `allowReload: true` only for the first NAVIGATE or after full page transitions where UI state is expendable. Never rely on reload recovery inside a `BEGIN_CLIP` / `END_CLIP` recording window.
|
|
341
|
-
|
|
342
|
-
## SET_LOCALE / SET_THEME: Method Selection
|
|
343
|
-
|
|
344
|
-
**Investigate the app's i18n/theme mechanism first** by reading configuration files:
|
|
345
|
-
|
|
346
|
-
| Framework | Opcode | Method | Storage | Key |
|
|
347
|
-
|-----------|--------|--------|---------|-----|
|
|
348
|
-
| next-intl | SET_LOCALE | `storage` | `cookie` | `NEXT_LOCALE` |
|
|
349
|
-
| i18next / react-intl | SET_LOCALE | `storage` | `localStorage` | `i18nextLng` |
|
|
350
|
-
| URL-based (e.g. `/fr/page`) | NAVIGATE | — | — | Use locale in URL path |
|
|
351
|
-
| Browser-level only | SET_LOCALE | `browser_context` | — | — |
|
|
352
|
-
| next-themes | SET_THEME | `storage` | `localStorage` | `theme` |
|
|
353
|
-
| CSS `prefers-color-scheme` | SET_THEME | `color_scheme` | — | — |
|
|
354
|
-
|
|
355
|
-
Place SET_LOCALE/SET_THEME **after NAVIGATE + DISMISS_OVERLAYS** but **before WAIT_FOR or CAPTURE_SCREENSHOT**. The runtime reloads the page after applying storage-based changes.
|
|
356
|
-
|
|
357
|
-
If the preset has only one locale and one theme, these opcodes are unnecessary.
|
|
358
|
-
|
|
359
|
-
## Mock Data Injection
|
|
360
|
-
|
|
361
|
-
Use mock data only when the capture would otherwise look empty or broken.
|
|
362
|
-
|
|
363
|
-
Core rules:
|
|
364
|
-
|
|
365
|
-
- wire both delivery mechanisms whenever possible: clone + hidden trigger/input
|
|
366
|
-
- every variable UI element must become a slot
|
|
367
|
-
- add `data-ak` markers to the template, container, variable children, and
|
|
368
|
-
hidden receivers
|
|
369
|
-
- declare `mockDataInjection.groups` at the top level of the preset config
|
|
370
|
-
- place `INJECT_MOCK_DATA` after `WAIT_FOR` and before `CAPTURE_SCREENSHOT`
|
|
371
|
-
- keep the opcode non-blocking with `postcondition: { type: "always" }`
|
|
372
|
-
|
|
373
|
-
Read the full reference before adding mock data:
|
|
374
|
-
|
|
375
|
-
- [references/mock-data.md](references/mock-data.md)
|
|
376
|
-
|
|
377
|
-
## Critical Rules
|
|
378
|
-
|
|
379
|
-
1. **Always start with `NAVIGATE` + `DISMISS_OVERLAYS`**
|
|
380
|
-
2. **Every CLICK/TYPE uses a `data-ak` selector** — add the attribute to the code first
|
|
381
|
-
3. **Never guess selectors** — if the element doesn't have a stable selector, add `data-ak` to it
|
|
382
|
-
4. **CLICK postconditions describe the result**, not the action (what changed, not what was clicked)
|
|
383
|
-
5. **Add `WAIT_FOR` after page transitions** (login, route change, modal open)
|
|
384
|
-
6. **Set `waitMs: 10000`** on postconditions involving async transitions
|
|
385
|
-
7. **Persist the preset via the CLI — the program lives INSIDE `config.program`**, not in a separate file. After generating the program JSON, write the full config to a temp file and run `autokap preset create` or `autokap preset update` so the saved preset contains `program: { ...the full ExecutionProgram... }` plus any `mockDataInjection` blocks. The user MUST be able to run `autokap run <preset-id>` afterwards with no `--program` flag and no extra files. **Never tell the user to save the JSON to a local file**, never suggest `--program <file>` as the normal run path. The CLI fetches the program from the server.
|
|
386
|
-
8. **Use `captureId`/`clipId`** on CAPTURE_SCREENSHOT/BEGIN_CLIP for Studio and dev links to work. Always set `"devLinksEnabled": true` in the preset config when creating via API so endpoints are visible on the dashboard
|
|
387
|
-
9. **Mock data opcodes are non-blocking** — they log a warning and continue if selectors miss; always pair them with `recovery: { retries: 0, ... }` and `postcondition: { type: "always" }`
|
|
388
|
-
10. **Hardcode the login URL — never use `{{loginUrl}}`.** The login URL is just another navigation. You generate the entire program, so you know which path the app's login lives at — write it directly (`https://app.example.com/login`, `http://localhost:3000/login`, etc.). The `{{loginUrl}}` placeholder is **deprecated** and produces broken navigations when the user hasn't filled the optional `loginUrl` credential field. `{{email}}` and `{{password}}` placeholders for `TYPE` opcodes are still correct and required (those are sensitive secrets the user fills in).
|
|
389
|
-
11. **Capturing an auth-protected route requires a login flow at the START of the program.** Do NOT assume the user is "already logged in". Before any opcode that hits a route behind authentication, emit the canonical login sequence (see "Login flow" below). Skipping this is the #1 cause of "preset runs but never reaches the dashboard" failures.
|
|
390
|
-
|
|
391
|
-
## Login flow
|
|
392
|
-
|
|
393
|
-
If **any** of the captures or DOM states in the program lives on an auth-protected route, the program MUST start with this canonical login sequence — placed BEFORE the first capture/state-bearing NAVIGATE.
|
|
394
|
-
|
|
395
|
-
```json
|
|
396
|
-
{ "kind": "NAVIGATE", "description": "Open login page", "url": "https://app.example.com/login", "postcondition": { "type": "route_matches", "pattern": "/login" }, "recovery": { "retries": 2, "useSelectorMemory": true, "useAltInteraction": true, "allowReload": true, "allowHealer": true }, "timeoutMs": 20000, "maxFailures": 3 },
|
|
397
|
-
{ "kind": "DISMISS_OVERLAYS", "description": "Dismiss any overlays on login", "postcondition": { "type": "overlay_dismissed" }, "recovery": { "retries": 2, "useSelectorMemory": true, "useAltInteraction": true, "allowReload": false, "allowHealer": true }, "timeoutMs": 5000, "maxFailures": 3 },
|
|
398
|
-
{ "kind": "WAIT_FOR", "description": "Wait for the login email input", "selector": "[data-ak=\"login-email\"]", "state": "visible", "postcondition": { "type": "element_visible", "selector": "[data-ak=\"login-email\"]", "waitMs": 5000 }, "recovery": { "retries": 2, "useSelectorMemory": true, "useAltInteraction": true, "allowReload": false, "allowHealer": true }, "timeoutMs": 10000, "maxFailures": 3 },
|
|
399
|
-
{ "kind": "TYPE", "description": "Enter login email", "selector": "[data-ak=\"login-email\"]", "text": "{{email}}", "clearFirst": true, "postcondition": { "type": "any_change" }, "recovery": { "retries": 2, "useSelectorMemory": true, "useAltInteraction": true, "allowReload": false, "allowHealer": true }, "timeoutMs": 10000, "maxFailures": 3 },
|
|
400
|
-
{ "kind": "TYPE", "description": "Enter login password", "selector": "[data-ak=\"login-password\"]", "text": "{{password}}", "clearFirst": true, "postcondition": { "type": "any_change" }, "recovery": { "retries": 2, "useSelectorMemory": true, "useAltInteraction": true, "allowReload": false, "allowHealer": true }, "timeoutMs": 10000, "maxFailures": 3 },
|
|
401
|
-
{ "kind": "CLICK", "description": "Submit the login form", "selector": "[data-ak=\"login-submit\"]", "postcondition": { "type": "route_matches", "pattern": "/dashboard**", "waitMs": 10000 }, "recovery": { "retries": 2, "useSelectorMemory": true, "useAltInteraction": true, "allowReload": false, "allowHealer": true }, "timeoutMs": 15000, "maxFailures": 3 }
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### Decision rule: do I need a login flow?
|
|
405
|
-
|
|
406
|
-
Walk through the routes you're about to capture:
|
|
407
|
-
|
|
408
|
-
| Route shape | Login flow needed? |
|
|
409
|
-
|---|---|
|
|
410
|
-
| `/`, `/pricing`, `/blog/*`, `/docs/*` (marketing / public) | **No** |
|
|
411
|
-
| `/dashboard`, `/projects/*`, `/settings`, `/admin/*` (anything behind a guard) | **Yes** |
|
|
412
|
-
| `/login`, `/signup`, `/forgot-password` (the auth pages themselves) | **No** (you're already there) |
|
|
413
|
-
| Mixed (some public, some private) | **Yes** if at least one is private — emit the login sequence first, then NAVIGATE to each route |
|
|
414
|
-
|
|
415
|
-
When in doubt: **inspect the route's component file** for auth checks (`useSession`, `redirect()`, middleware, layout-level auth wrapper, server-side `getServerSession`, etc.). If you find any, emit the login flow.
|
|
416
|
-
|
|
417
|
-
### Anti-patterns
|
|
418
|
-
|
|
419
|
-
| Don't | Why |
|
|
420
|
-
|---|---|
|
|
421
|
-
| `{ "kind": "NAVIGATE", "url": "{{loginUrl}}" }` | Deprecated placeholder. The user often leaves `loginUrl` empty (it's optional), and the substitution produces an empty string that crashes Playwright. Hardcode the URL. |
|
|
422
|
-
| Skip the login flow because "the user runs locally and is already logged in" | Playwright launches a fresh browser context with no cookies. Sessions never carry over. |
|
|
423
|
-
| Capture a private route with no preceding login sequence | You'll capture the login screen (or a 401 page) instead of the actual dashboard. |
|
|
424
|
-
| Place login steps in the middle of the program after a public capture | The first NAVIGATE to a private route fails with a 401/redirect before login runs. Login goes FIRST. |
|
|
425
|
-
| Use `{{loginUrl}}` in any example or doc you write into chat | Reinforces the broken pattern. Always hardcode. |
|
|
426
|
-
|
|
427
|
-
## How to persist the preset
|
|
428
|
-
|
|
429
|
-
The user expects a **one-shot flow**: copy prompt → paste → assistant does the work → user runs `autokap run <preset-id>`. **Never break this flow.**
|
|
430
|
-
|
|
431
|
-
Use the AutoKap CLI commands to create, update, and query presets. The CLI reads the stored CLI key from `~/.autokap/config.json` automatically — **do NOT read the key yourself or build raw HTTP requests as the normal path**.
|
|
432
|
-
|
|
433
|
-
### Step 1: Write the config JSON to a temp file
|
|
434
|
-
|
|
435
|
-
Build the full config object (with `program`, `pages`, and optionally `mockDataInjection`) and write it to a temporary file:
|
|
436
|
-
|
|
437
|
-
```bash
|
|
438
|
-
cat > /tmp/autokap-preset.json << 'EOF'
|
|
439
|
-
{
|
|
440
|
-
"captureMode": "screenshot",
|
|
441
|
-
"devLinksEnabled": true,
|
|
442
|
-
"pages": [
|
|
443
|
-
{ "id": "dashboard", "name": "Dashboard" },
|
|
444
|
-
{ "id": "settings", "name": "Settings" }
|
|
445
|
-
],
|
|
446
|
-
"program": {
|
|
447
|
-
"presetId": "my-preset",
|
|
448
|
-
"programVersion": 1,
|
|
449
|
-
"mediaMode": "screenshot",
|
|
450
|
-
"baseUrl": "https://app.example.com",
|
|
451
|
-
"variants": [ { "id": "desktop-en-light", "viewport": { "width": 1440, "height": 900 }, "locale": "en", "theme": "light", "targetId": "desktop", "targetLabel": "Desktop" } ],
|
|
452
|
-
"preconditions": {},
|
|
453
|
-
"steps": [ { "kind": "NAVIGATE", "..." : "..." } ],
|
|
454
|
-
"artifactPlan": { "mediaMode": "screenshot" },
|
|
455
|
-
"compileFingerprint": "v1-my-preset",
|
|
456
|
-
"compiledAt": "2026-04-11T00:00:00.000Z",
|
|
457
|
-
"compiledWith": "ai-assistant"
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
EOF
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
#### Config requirements
|
|
464
|
-
|
|
465
|
-
- **`pages`** — one entry per `CAPTURE_SCREENSHOT` opcode (`{ "id": "<captureId>", "name": "<captureName>" }`). Drives endpoint (dev link) creation. **Screenshot presets only.**
|
|
466
|
-
- **`clips`** — one entry per `BEGIN_CLIP`/`END_CLIP` pair (`{ "id": "<clipId>", "name": "<clipName>" }`). Drives endpoint and Studio slot creation. **Clip presets only.** Do NOT put clip entries in `pages` — the server treats `pages` as screenshots.
|
|
467
|
-
- **`program`** — the full `ExecutionProgram` with `steps`, `variants`, `artifactPlan`, etc.
|
|
468
|
-
- **`captureMode`** — `"screenshot"` or `"clip"`.
|
|
469
|
-
- **`devLinksEnabled: true`** — enables endpoints on the dashboard.
|
|
470
|
-
|
|
471
|
-
The server auto-syncs `langs`, `themes`, `targets`, and `viewports` from `program.variants` — you do NOT need to set these manually.
|
|
472
|
-
|
|
473
|
-
### Step 2: Create the preset
|
|
474
|
-
|
|
475
|
-
```bash
|
|
476
|
-
npx autokap@latest preset create \
|
|
477
|
-
--project <project-id> \
|
|
478
|
-
--name "My preset" \
|
|
479
|
-
--config /tmp/autokap-preset.json
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
The command outputs **only the preset ID** to stdout. Capture it for the next steps:
|
|
483
|
-
|
|
484
|
-
```bash
|
|
485
|
-
PRESET_ID=$(npx autokap@latest preset create --project <project-id> --name "My preset" --config /tmp/autokap-preset.json)
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
### Step 3: Run the preset
|
|
489
|
-
|
|
490
|
-
```bash
|
|
491
|
-
npx autokap@latest run $PRESET_ID
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
### Step 4: Fetch dev link endpoints
|
|
495
|
-
|
|
496
|
-
```bash
|
|
497
|
-
npx autokap@latest endpoints list --preset $PRESET_ID
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
Outputs JSON with endpoint IDs and public asset URLs:
|
|
501
|
-
```json
|
|
502
|
-
[
|
|
503
|
-
{ "id": "abc123...", "capture_name": "dashboard", "label": "Dashboard", "url": "https://app.example.com/api/v1/assets/abc123..." }
|
|
504
|
-
]
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
### Step 5: Integrate dev links into the codebase
|
|
508
|
-
|
|
509
|
-
After the run succeeds, wire the endpoints into the user's code. **This is part of the one-shot flow** — do not stop at validation.
|
|
510
|
-
|
|
511
|
-
First, get the structured integration info:
|
|
512
|
-
|
|
513
|
-
```bash
|
|
514
|
-
npx autokap@latest preset info $PRESET_ID
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
This returns JSON with all endpoints, their URLs, asset types, available variants (langs, themes, targets with device slugs), and per-type URL parameters.
|
|
518
|
-
|
|
519
|
-
Then, use the output to embed the links in the appropriate places in the codebase:
|
|
520
|
-
|
|
521
|
-
- **Screenshots** → `<img src="{url}?lang=en&theme=light&format=webp" alt="..." loading="lazy" />`
|
|
522
|
-
- **Clips** → `<img src="{url}" alt="..." loading="lazy" />` (GIF, default) or `<video src="{url}?format=mp4" autoplay loop muted playsinline />`
|
|
523
|
-
- **Interactive demos** → `<iframe src="{embed_url}" style="width: 100%; border: none; aspect-ratio: 16/9;" allow="clipboard-write" loading="lazy"></iframe>`
|
|
524
|
-
- **Compositions** → `<img src="{url}?format=webp" alt="..." loading="lazy" />`
|
|
525
|
-
|
|
526
|
-
Where to embed depends on what the user asked for (README, landing page, docs, component props, etc.). **Ask the user if the target location is ambiguous.**
|
|
527
|
-
|
|
528
|
-
Append variant query params (`lang`, `theme`, `target`) based on context — for example, match the page locale, or use the user's preferred theme. If uncertain, use the first variant from the `preset info` output as default.
|
|
529
|
-
|
|
530
|
-
### Updating an existing preset
|
|
531
|
-
|
|
532
|
-
```bash
|
|
533
|
-
npx autokap@latest preset update <preset-id> --config /tmp/autokap-preset.json
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
Optional `--name` and `--description` flags to update metadata.
|
|
537
|
-
|
|
538
|
-
### Deleting a preset
|
|
539
|
-
|
|
540
|
-
```bash
|
|
541
|
-
npx autokap@latest preset delete <preset-id>
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
### Anti-patterns (NEVER do these)
|
|
545
|
-
|
|
546
|
-
| Don't | Why |
|
|
547
|
-
|---|---|
|
|
548
|
-
| Read `~/.autokap/config.json` and make raw `fetch`/`curl` calls | The CLI handles auth automatically. Raw HTTP calls are fragile and expose the key. |
|
|
549
|
-
| Tell the user to save the program to a local JSON and pass `--program` | Defeats the one-shot flow. The user expected the AI to handle persistence. |
|
|
550
|
-
| Create the preset without `config.program` | The CLI then has nothing to run; the dashboard shows "No capture program". |
|
|
551
|
-
| Create the preset without `config.pages` (for screenshot presets) | No dev link endpoints will be created. |
|
|
552
|
-
| Put clip entries in `config.pages` instead of `config.clips` | The server treats `pages` as screenshots. Clips won't appear in Studio or get endpoints. |
|
|
553
|
-
| Create a clip preset without `config.clips` | No clip endpoints or Studio slots will be created. |
|
|
554
|
-
| Output the program as a code block "for the user to copy" | Forces a manual step. Use the CLI instead. |
|
|
555
|
-
|
|
556
|
-
### Fallback (when the CLI is genuinely unavailable)
|
|
557
|
-
|
|
558
|
-
If the CLI command fails, output the full config JSON as a code block and tell the user to import it via the dashboard. Make it clear this is a recovery path, not the normal one.
|
|
559
|
-
|
|
560
|
-
## Running
|
|
561
|
-
|
|
562
|
-
```bash
|
|
563
|
-
# Run a preset (the program lives in preset.config.program — no --program flag):
|
|
564
|
-
autokap run <preset-id>
|
|
565
|
-
|
|
566
|
-
# Watch the browser execute:
|
|
567
|
-
autokap run <preset-id> --headed
|
|
568
|
-
|
|
569
|
-
# Save the artifacts to a local directory in addition to uploading them:
|
|
570
|
-
autokap run <preset-id> --output ./screenshots
|
|
571
|
-
|
|
572
|
-
# Dry run: validate the opcode program end-to-end without capturing or
|
|
573
|
-
# uploading anything (0 credits charged). Use this right after generating
|
|
574
|
-
# or updating a preset to confirm navigation, clicks, and postconditions
|
|
575
|
-
# work before spending credits on a real capture.
|
|
576
|
-
autokap run <preset-id> --dry
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
## Complete Examples
|
|
580
|
-
|
|
581
|
-
Use the examples reference for ready-made shapes of:
|
|
582
|
-
|
|
583
|
-
- anonymous screenshot presets
|
|
584
|
-
- authenticated screenshot presets
|
|
585
|
-
- clip presets
|
|
586
|
-
- mock-data-enabled presets
|
|
587
|
-
|
|
588
|
-
Read:
|
|
589
|
-
|
|
590
|
-
- [references/examples.md](references/examples.md)
|