@spark-apps/quickpeek 1.2.4 → 1.2.6
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/README.md +64 -22
- package/dist/assets/music/manifest.json +1 -1
- package/dist/index.d.mts +49 -10
- package/dist/index.mjs +215 -143
- package/dist/mcp-tools.mjs +968 -431
- package/dist/qp.js +1014 -473
- package/dist/{voices-CPpnWn39.d.mts → voices-5AFt1GDp.d.mts} +80 -4
- package/dist/web.d.mts +2 -2
- package/dist/web.mjs +154 -20
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
[
|
|
2
|
-
[privacy-link]: ./PRIVACY.md
|
|
3
|
-
[discord-link]: https://discord.gg/mAjHWE3mSp
|
|
4
|
-
[stars-link]: ../../stargazers
|
|
5
|
-
[issues-link]: ../../issues
|
|
1
|
+
[coffee-link]: https://buymeacoffee.com/spark88
|
|
6
2
|
|
|
7
3
|
<div align="center">
|
|
8
4
|
|
|
9
|
-
<img src=
|
|
5
|
+
<img src="https://quickpeek.co/logo.png" alt="QuickPeek" width="220">
|
|
10
6
|
|
|
11
7
|
**Demo videos for your web app with AI**
|
|
12
8
|
|
|
13
9
|
*Because Tutorial Videos are Overrated!*
|
|
14
10
|
|
|
15
11
|
[](https://www.npmjs.com/package/@spark-apps/quickpeek)
|
|
16
|
-
|
|
17
|
-
[][discord-link]
|
|
18
|
-
[][stars-link]
|
|
12
|
+

|
|
19
13
|
|
|
20
14
|
[](https://sellular.online/badge/quickpeek/go)
|
|
21
15
|
|
|
@@ -25,18 +19,36 @@
|
|
|
25
19
|
|
|
26
20
|
## Quick Start
|
|
27
21
|
|
|
22
|
+
Nothing to install:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @spark-apps/quickpeek https://your-app.com
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or install it for repeat use:
|
|
29
|
+
|
|
28
30
|
```bash
|
|
29
31
|
npm install -g @spark-apps/quickpeek
|
|
30
32
|
qp localhost:3000
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
**Requirements:** [ffmpeg](https://ffmpeg.org/download.html)
|
|
35
|
+
**Requirements:** [ffmpeg](https://ffmpeg.org/download.html). Nothing else. The AI
|
|
36
|
+
runs through QuickPeek's hosted relay, so there is no API key to get.
|
|
37
|
+
|
|
38
|
+
**Free tier:** 5 videos on an unconfirmed email, then 10 a day once you confirm
|
|
39
|
+
it. No card either way. The CLI asks for an address on the first run because the
|
|
40
|
+
AI planner runs on our servers and is metered per account; over
|
|
41
|
+
[MCP](#mcp-server) no account is needed at all, because your own model does the
|
|
42
|
+
writing. A free video of 20 seconds or under comes out clean; a longer free video
|
|
43
|
+
carries a QuickPeek watermark. The hosted web recorder at quickpeek.co is
|
|
44
|
+
deliberately different: there, free videos are capped at 20 seconds and are
|
|
45
|
+
always watermarked. https://quickpeek.co/pricing sets the two side by side.
|
|
34
46
|
|
|
35
47
|
## Features
|
|
36
48
|
|
|
37
49
|
| Feature | Description |
|
|
38
50
|
|---------|-------------|
|
|
39
|
-
| **AI Planning** |
|
|
51
|
+
| **AI Planning** | AI analyzes your app and generates demo steps |
|
|
40
52
|
| **Script Mode** | Provide your own narration script, AI maps it to UI actions |
|
|
41
53
|
| **Capture Mode** | Record your own interactions → replayable plan.json |
|
|
42
54
|
| **Voice Over** | Free Edge TTS narration in 60+ languages |
|
|
@@ -47,13 +59,13 @@ qp localhost:3000
|
|
|
47
59
|
|
|
48
60
|
## Examples
|
|
49
61
|
|
|
50
|
-
### Basic
|
|
62
|
+
### Basic: AI generates the plan
|
|
51
63
|
|
|
52
64
|
```bash
|
|
53
65
|
qp localhost:3000
|
|
54
66
|
```
|
|
55
67
|
|
|
56
|
-
### Script mode
|
|
68
|
+
### Script mode: you write the narration
|
|
57
69
|
|
|
58
70
|
```bash
|
|
59
71
|
qp localhost:3000 --script narration.txt
|
|
@@ -63,12 +75,12 @@ Script file format (one caption per line, `#` for comments):
|
|
|
63
75
|
|
|
64
76
|
```
|
|
65
77
|
# My app demo
|
|
66
|
-
We start on the dashboard
|
|
78
|
+
We start on the dashboard, your main workspace.
|
|
67
79
|
Let's search for a customer by typing their name.
|
|
68
80
|
Click the result to open their profile.
|
|
69
81
|
```
|
|
70
82
|
|
|
71
|
-
### Capture mode
|
|
83
|
+
### Capture mode: record your own interactions
|
|
72
84
|
|
|
73
85
|
```bash
|
|
74
86
|
qp capture localhost:3000
|
|
@@ -122,7 +134,7 @@ Config is auto-generated on first run. Edit `quickpeek.config.json` to customize
|
|
|
122
134
|
| `pt` | Portuguese | `hi` | Hindi |
|
|
123
135
|
| `it` | Italian | `ru` | Russian |
|
|
124
136
|
|
|
125
|
-
|
|
137
|
+
The full list comes back from the `list_voices` tool on the MCP server.
|
|
126
138
|
|
|
127
139
|
</details>
|
|
128
140
|
|
|
@@ -131,8 +143,6 @@ See `src/voices.ts` for all 60+ supported languages.
|
|
|
131
143
|
|
|
132
144
|
Edit `captions.css` (auto-generated) to customize:
|
|
133
145
|
|
|
134
|
-

|
|
135
|
-
|
|
136
146
|
```css
|
|
137
147
|
.caption {
|
|
138
148
|
font-family: Arial, sans-serif;
|
|
@@ -177,6 +187,40 @@ Edit `demo/plan.json` to customize your demo. Each step uses one of these action
|
|
|
177
187
|
|
|
178
188
|
**Target shortcuts:** For buttons and links, use simplified text like `"download"` or `"extract frame"` instead of CSS selectors.
|
|
179
189
|
|
|
190
|
+
## MCP Server
|
|
191
|
+
|
|
192
|
+
QuickPeek ships an MCP server (`quickpeek-mcp`) so an AI agent can record a demo
|
|
193
|
+
directly, with no shelling out to the CLI.
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
claude mcp add quickpeek -- npx -y --ignore-scripts --package=@spark-apps/quickpeek quickpeek-mcp
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Or add it by hand, for any MCP client:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"mcpServers": {
|
|
204
|
+
"quickpeek": {
|
|
205
|
+
"command": "npx",
|
|
206
|
+
"args": ["-y", "--ignore-scripts", "--package=@spark-apps/quickpeek", "quickpeek-mcp"]
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Published on the [official MCP registry](https://registry.modelcontextprotocol.io)
|
|
213
|
+
as `co.quickpeek/quickpeek`.
|
|
214
|
+
|
|
215
|
+
**9 tools:** `generate_demo`, `generate_demo_from_script`, `list_demos`,
|
|
216
|
+
`get_demo_config`, `list_voices`, `open_in_editor`, `check_account`, and the
|
|
217
|
+
`start_auth` / `finish_auth` pair for recording an app you have to log into.
|
|
218
|
+
|
|
219
|
+
The server never calls an AI itself. It hands the planning and narration prompts
|
|
220
|
+
back to you, the calling model, and takes your answer as a parameter, so a demo
|
|
221
|
+
costs you no QuickPeek quota and no second-rate model. That is also why this path
|
|
222
|
+
needs no account at all for the first 5 videos, where the CLI asks for an email.
|
|
223
|
+
|
|
180
224
|
## Output
|
|
181
225
|
|
|
182
226
|
| File | Description |
|
|
@@ -190,12 +234,10 @@ Edit `demo/plan.json` to customize your demo. Each step uses one of these action
|
|
|
190
234
|
|
|
191
235
|
## 🌱 Support & Contributions
|
|
192
236
|
|
|
193
|
-
⭐ **Star the repo** & I power up like Mario 🍄
|
|
194
237
|
☕ **Devs run on coffee** - [Buy me one?][coffee-link]
|
|
195
|
-
💖 **Sponsor** [Your support][stars-link] helps maintain and improve the tool<br>
|
|
196
238
|
💰 **Crypto tips welcome** - [Tip in crypto](https://tip.md/muammar-yacoob)
|
|
197
|
-
|
|
198
|
-
|
|
239
|
+
🎬 **See it work** - [Watch a demo](https://www.youtube.com/shorts/HaibrNvJknY)
|
|
240
|
+
🐛 **Found a bug or want a feature?** Email [support@quickpeek.co](mailto:support@quickpeek.co) - the repo is private, so email is the way in.
|
|
199
241
|
|
|
200
242
|
<div align="center">
|
|
201
243
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
import { U as UserTier, C as CaptionStyle, a as CaptionPosition, b as Config, V as VoiceRate } from './voices-
|
|
2
|
-
export { A as AIError, c as AIResponse, d as AIResult, e as CLI_BACKOFF_MS, f as CONFIG_FILE, g as CaptionPreset, h as CaptionWordStyle, i as ChatOptions, D as DEFAULT_CAPTIONS, j as DEFAULT_CONFIG, E as EXCLUDED_LINK_PATTERNS, k as ElementInfo, l as ElementType, H as HighlightMode, I as INTERACTIVE_SELECTORS, m as INTERNATIONAL_VOICE, N as NO_CLIP_OUTRO, P as PLAN_MAX_TOKENS, n as Plan, R as RATE_FACTOR, o as
|
|
1
|
+
import { U as UserTier, C as CaptionStyle, a as CaptionPosition, b as Config, V as VoiceRate } from './voices-5AFt1GDp.mjs';
|
|
2
|
+
export { A as AIError, c as AIResponse, d as AIResult, e as CLI_BACKOFF_MS, f as CONFIG_FILE, g as CaptionPreset, h as CaptionWordStyle, i as ChatOptions, D as DEFAULT_CAPTIONS, j as DEFAULT_CONFIG, E as EXCLUDED_LINK_PATTERNS, k as ElementInfo, l as ElementType, H as HighlightMode, I as INTERACTIVE_SELECTORS, m as INTERNATIONAL_VOICE, N as NO_CLIP_OUTRO, P as PLAN_MAX_TOKENS, n as Plan, R as RATE_FACTOR, o as RELAY_BASE, p as RateLimitInfo, q as RetryNotice, S as SERVER_BACKOFF_MS, r as SIZE_PRESETS, s as SparkStatus, t as SparkSubscription, u as SparkTrial, v as Step, w as SuggestedAction, T as Tier, x as VERSION, y as VIDEO_PROFILES, z as VideoProfileName, B as VideoSize, F as VoiceGender, G as applyProfile, J as ariaLabelSelector, K as buildSystemPrompt, L as buildUserPrompt, M as callAI, O as callAIForPlan, Q as callAIViaRelay, W as crawlPage, X as deStock, Y as defaultCaptionsFor, Z as getErrorMessage, _ as getLanguageName, $ as getOrRefreshRelayToken, a0 as getStatus, a1 as getStatusCached, a2 as getTierByEmail, a3 as gotoSettled, a4 as hasTrialRemaining, a5 as hasVoice, a6 as idSelector, a7 as internationalVoiceFor, a8 as isCanceling, a9 as isExcludedLink, aa as isPaid, ab as isVerified, ac as normalizeUrl, ad as parseAIPlanResponse, ae as parsePartial, af as pricingUrl, ag as rgbaToHex, ah as runPooled, ai as shouldSkipLink, aj as showPaywall, ak as stripLongDashes, al as toTitleCase, am as voiceFor, an as waitForPlaceholdersGone } from './voices-5AFt1GDp.mjs';
|
|
3
3
|
export { MALE_VOICES, MULTILINGUAL_VOICES, WIDE_VOICES, hexToAss as hexToASS, windowsDrivePathToWsl as windowsPathToWSL } from '@spark-apps/video-kit';
|
|
4
4
|
import 'playwright';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Billing utilities —
|
|
7
|
+
* Billing utilities — upgrade URL generation
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Check if watermark should be applied
|
|
12
|
-
* Watermark applies to free tier videos longer than 20 seconds
|
|
13
|
-
*/
|
|
14
|
-
declare function shouldWatermark(tier: UserTier, videoDurationSeconds: number): boolean;
|
|
15
9
|
/**
|
|
16
10
|
* Get upgrade URL for pricing page
|
|
17
11
|
*/
|
|
@@ -73,6 +67,38 @@ interface ComposeOptions {
|
|
|
73
67
|
stepTransitions?: StepTransition[] | undefined;
|
|
74
68
|
/** 'off' pins the deliverable encode to libx264; anything else probes for a GPU. */
|
|
75
69
|
hwaccel?: 'auto' | 'off' | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* The tempo pass that will run AFTER this compose, if any.
|
|
72
|
+
*
|
|
73
|
+
* That pass speeds the finished file up, and it cannot tell a narrator from
|
|
74
|
+
* a song: a demo scored with a track came out with the music playing 1.2x,
|
|
75
|
+
* which is audible on anything with a beat and is simply wrong - the voice
|
|
76
|
+
* is what the pacing is for. The bed is laid down pre-slowed by the same
|
|
77
|
+
* factor here, so the later speed-up returns it to its natural tempo.
|
|
78
|
+
* atempo preserves pitch in both directions, so the round trip is a tempo
|
|
79
|
+
* change and not a transposition. 1 (the default) changes nothing.
|
|
80
|
+
*/
|
|
81
|
+
tempo?: number | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Where the music bed starts, in seconds on this compose's timeline.
|
|
84
|
+
*
|
|
85
|
+
* 0 (the default) scores the whole video. Set to the closing card's start
|
|
86
|
+
* and the demo plays dry, with the song arriving as the card does - which
|
|
87
|
+
* is what you want when the track is the product's own and is meant to be
|
|
88
|
+
* heard rather than ducked under a narrator for a minute first.
|
|
89
|
+
*/
|
|
90
|
+
musicStartSecs?: number | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Length of the music file, in seconds, so its END can be landed on the
|
|
93
|
+
* video's end.
|
|
94
|
+
*
|
|
95
|
+
* A song has an ending, and a song cut off two thirds through does not: it
|
|
96
|
+
* stops. Given the track's length, the bed is seeked so that its last note
|
|
97
|
+
* falls on the last frame, which is what makes a closing card feel closed
|
|
98
|
+
* rather than interrupted. Omitted, the bed plays from its beginning as
|
|
99
|
+
* before.
|
|
100
|
+
*/
|
|
101
|
+
musicDurationSecs?: number | undefined;
|
|
76
102
|
}
|
|
77
103
|
interface ConcatVideoOptions {
|
|
78
104
|
inputPath: string;
|
|
@@ -821,6 +847,19 @@ declare function resolveRate(config: Config): VoiceRate;
|
|
|
821
847
|
* engine to unescape an entity it may not have escaped itself.
|
|
822
848
|
*/
|
|
823
849
|
declare function speakSymbols(text: string): string;
|
|
850
|
+
/**
|
|
851
|
+
* A caption as the voice should receive it.
|
|
852
|
+
*
|
|
853
|
+
* Order is load-bearing and each pass documents why above it: symbols before
|
|
854
|
+
* anything (a bare "&" invalidates the SSML), domains before toSpokenForm
|
|
855
|
+
* (matching "vidlet dot app" cannot tell an address from prose), acronyms
|
|
856
|
+
* after (so a TLD spelled here is not re-spelled), numbers last.
|
|
857
|
+
*
|
|
858
|
+
* Exported so the shaping can be asserted directly. It used to be one inline
|
|
859
|
+
* expression, which meant the only way to test a pronunciation was to
|
|
860
|
+
* re-create the chain in the test and hope it stayed in step.
|
|
861
|
+
*/
|
|
862
|
+
declare function spokenForm(caption: string): string;
|
|
824
863
|
declare function generateVoiceover(steps: TTSStep[], config: Config, workDir: string, outputDir: string, logError: (context: string, error: unknown) => Promise<void>, task: (text: string) => {
|
|
825
864
|
succeed: (text?: string) => void;
|
|
826
865
|
}, info: (text: string) => void): Promise<AudioResult>;
|
|
@@ -904,4 +943,4 @@ declare function buildWatermarkFilters(opts: {
|
|
|
904
943
|
endsOnCreditsCard?: boolean;
|
|
905
944
|
}): string;
|
|
906
945
|
|
|
907
|
-
export { type ApplyTransitionsOptions, type AudioResult, type BlendTransition, CURSOR_CSS, CURSOR_PNG, CURSOR_SCRIPT, type CaptionCue, CaptionPosition, type CaptionRenderContext, CaptionStyle, type ComposeOptions, type ConcatVideoOptions, Config, EMPTY_SPAN_SPEED, GIF_DEFAULTS, type GifOptions, type LenientParse, MUSIC_BED_LUFS, NARRATION_LEAD_IN_MS, type SilenceSpan, type SpeedUpOptions, type SpliceVideosOptions, type SpokenWord, type StepAudio, type StepSync, type StepTransition, TRIM_EDGE_SILENCE, type TTSStep, type TimeSegment, UserTier, VOICE_LEAD_MS, type VideoOverlay, VoiceRate, type VoiceoverMeta, type WordTiming, alignVoiceoverToRecording, alignWordsToCaption, applyTransitions, atempoChain, buildCompressionFilter, buildConcatArgs, buildGifArgs, buildKeepSegments, buildPaletteArgs, buildRetimeFilter, buildStepTransitions, buildWatermarkFilters, canReuseVoiceover, captionCanvas, composeVideo, compressSilentSpans, concatMedia, concatVideoWithFullFrameOutro, concatVideoWithOutro, convertToGif, coverFilterChain, cutSpansFromVideo, detectBlackSpans, detectFrozenSpans, detectSilences, detectWhiteSpans, estimateWordTimings, extractJsonCandidates, generateASSHeader, generateSilence, generateVoiceover, getAudioCodec, getMediaDuration, getUpgradeUrl, getVideoDimensions, getVideoStreamDuration, hasAudioStream, intersectSpans, isHonestWav, loadExistingVoiceover, loadVoiceoverMeta, mapTimestampsAfterCompression, mergeSpans, parseAIJson, parseWordBoundaries, positionToAlignment, registerFreeUser, renderCaptionsAss, repairUnicodeEscapes, resetVoiceEngine, resolveCaptionFont, resolveCaptions, resolveRate, resolveVoice, retimeSpansInVideo, salvageTruncatedJson,
|
|
946
|
+
export { type ApplyTransitionsOptions, type AudioResult, type BlendTransition, CURSOR_CSS, CURSOR_PNG, CURSOR_SCRIPT, type CaptionCue, CaptionPosition, type CaptionRenderContext, CaptionStyle, type ComposeOptions, type ConcatVideoOptions, Config, EMPTY_SPAN_SPEED, GIF_DEFAULTS, type GifOptions, type LenientParse, MUSIC_BED_LUFS, NARRATION_LEAD_IN_MS, type SilenceSpan, type SpeedUpOptions, type SpliceVideosOptions, type SpokenWord, type StepAudio, type StepSync, type StepTransition, TRIM_EDGE_SILENCE, type TTSStep, type TimeSegment, UserTier, VOICE_LEAD_MS, type VideoOverlay, VoiceRate, type VoiceoverMeta, type WordTiming, alignVoiceoverToRecording, alignWordsToCaption, applyTransitions, atempoChain, buildCompressionFilter, buildConcatArgs, buildGifArgs, buildKeepSegments, buildPaletteArgs, buildRetimeFilter, buildStepTransitions, buildWatermarkFilters, canReuseVoiceover, captionCanvas, composeVideo, compressSilentSpans, concatMedia, concatVideoWithFullFrameOutro, concatVideoWithOutro, convertToGif, coverFilterChain, cutSpansFromVideo, detectBlackSpans, detectFrozenSpans, detectSilences, detectWhiteSpans, estimateWordTimings, extractJsonCandidates, generateASSHeader, generateSilence, generateVoiceover, getAudioCodec, getMediaDuration, getUpgradeUrl, getVideoDimensions, getVideoStreamDuration, hasAudioStream, intersectSpans, isHonestWav, loadExistingVoiceover, loadVoiceoverMeta, mapTimestampsAfterCompression, mergeSpans, parseAIJson, parseWordBoundaries, positionToAlignment, registerFreeUser, renderCaptionsAss, repairUnicodeEscapes, resetVoiceEngine, resolveCaptionFont, resolveCaptions, resolveRate, resolveVoice, retimeSpansInVideo, salvageTruncatedJson, speakSymbols, speedUpMiddle, speedUpVideo, spliceVideos, spokenForm, spokenWordTimings, synthesizeSpeech, trimEdgeSilence };
|