Codync
免费开源的 1:1 Grok Bot 与 Muse 替代方案。可在 iPhone、Mac 或 Linux 桌面上将 Claude 代码、Codex、Cursor 以及 40 多个编码代理作为持久机器人使用。支持群组聊天、线程、应用。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Demos as code: re-run, diff, heal and re-render narrated product walkthroughs on every release. Playwright + Remotion.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Every SaaS has a help-center graveyard: videos showing last year's UI. Loom, Guidde and Clueso make the first recording easy. Nobody re-records forty videos every sprint.
demo-engine treats a demo like a test:
# demos/invite-teammate.flow.yaml
name: Invite a teammate
url: ${BASE_URL}/settings/team
touches: ["src/settings/team/**"]
steps:
- say: Open Team settings from the sidebar.
click: { role: link, name: Team }
- say: Click Invite and enter your teammate's email.
click: { role: button, name: Invite member }
- say: Pick a role. Admins can manage billing.
select: { target: { label: Role }, option: Admin }
zoom: { scale: 1.6 }
- say: Send the invite. They'll get an email within a minute.
click: { role: button, name: Send invite }
expect: { text: Invite sent }
npx demo-engine build demos --base-url https://staging.example.com
That one command:
unchanged, cosmetic, changed or broken.npm i -D demo-engine
npx playwright install chromium
npx demo-engine init --base-url http://localhost:3000 # demos/, config, GitHub workflow
npx demo-engine build demos # run → diff → heal → narrate → render
open .demo-engine/renders/example-walkthrough/example-walkthrough.mp4
No API keys required. Without keys, healing uses the heuristic matcher and narration reads your say lines with a local voice: Kokoro (neural, open weights, pip install kokoro soundfile) if it is installed, otherwise the macOS system voice, otherwise silence. Add ANTHROPIC_API_KEY or OPENAI_API_KEY for polished scripts and smarter heals, ELEVENLABS_API_KEY for a production voice.
Try the bundled example (public TodoMVC, no app to start):
git clone https://github.com/niqbal/demo-engine && cd demo-engine
npm ci --legacy-peer-deps && npm run build && npx playwright install chromium
cd examples/todomvc && node ../../packages/cli/dist/index.js build demos
None of them is required. Each one gives the engine more visibility into what changed.
| Level | What you add | What you get |
|---|---|---|
| 0 · Nothing | Flow files anywhere, a URL | Run, diff, heal, render. Works against any site you can reach. |
| 1 · Demos in the repo | demos/*.flow.yaml with touches: globs, the GitHub Action | build --since origin/main knows which flows a PR affects and lists the touching files in the report. Healed locators come back as a diff you review. |
| 2 · Anchors | data-demo="invite-button" on a few stable elements, anchor: invite-button in flows | Locators that survive copy changes and redesigns. demo-engine anchors --src src fails CI when a flow references an anchor the source no longer has. |
| 3 · Existing tests | import { test } from "@demo-engine/playwright" and wrap actions in demo.step("…") | Your e2e suite records demos as a by-product. DEMO_ENGINE=1 npx playwright test, then demo-engine render <run-dir>. |
// Level 3: an existing Playwright test, narrated.
import { test, expect } from "@demo-engine/playwright";
test("Invite a teammate", async ({ page, demo }) => {
await page.goto("/settings/team");
const invite = page.getByRole("button", { name: "Invite member" });
await demo.step("Click Invite and enter an email.", { target: invite }, async () => {
await invite.click();
await page.getByLabel("Email").fill("[email protected]");
});
});
A flow is a template. An audience is one prospect or customer: company, logo, industry, the person watching, the rep presenting, the sample data they should see. flow × audience is a personalized run and a personalized video, and every one of them is regenerated when the product changes.
# demos/onboarding.flow.yaml
name: Onboarding
url: ${BASE_URL}/
defaults: { company: your team, task: Write the launch post } # what CI, diff and heal run with
setup: npm run seed:demo -- --tenant $AUDIENCE_ID # Layer 1: real data in the app
personalize: # Layer 2: repaint what cannot be seeded
- { css: "header h1", text: "{{audience.company}}" }
end: { text: Try it with your own data., url: https://example.com/book }
steps:
- say: Add the next thing {{audience.company}} needs done. # Layer 3: narration and cards
type: { target: { placeholder: "What needs to be done?" }, value: "{{audience.task}}" }
expect: { text: "{{audience.task}}" }
# demos/audiences/acme.yaml (or one CSV with dotted headers: contact.first, rep.name)
company: Acme Logistics
industry: Logistics
task: Confirm Q4 carrier contracts
logo: demos/audiences/logos/acme.svg
contact: { first: Priya, title: Head of Operations }
rep: { name: Asad Iqbal, title: Founder, calendar: https://cal.com/demo-engine/15min }
pitch: Ops team of 40 tracks carrier tasks in spreadsheets.
demo-engine build demos --audience acme # one prospect
demo-engine build demos --audiences acme globex initech # several
demo-engine build demos --audiences demos/prospects.csv # from a CRM export
demo-engine build demos --audiences # everything in demos/audiences/
demo-engine audiences # which steps change per audience, and why
How it stays cheap and correct:
defaults:. A flow with no {{audience.*}} in its steps and no personalize: block reuses the default run's frames for every audience; only narration and cards change. Otherwise the browser runs per audience and run.json marks which steps are personalized.industry, contact and pitch.renders/<flow>/<audience>/audience.json stamps what was rendered. When the product and the audience are unchanged, the audience is skipped outright.accent or voice overrides the brand's.Output: renders/<flow>/<audience>/<flow>.mp4 next to the default renders/<flow>/<flow>.mp4. The flow's setup: sees AUDIENCE_ID and AUDIENCE_JSON.
demo-engine init writes .github/workflows/demos.yml. The composite action installs the CLI and Chromium, runs build, uploads renders as an artifact, and posts (or updates) one PR comment:
- uses: niqbal/demo-engine@v0
with:
base-url: ${{ vars.DEMO_BASE_URL }}
since: ${{ github.event.pull_request.base.sha }}
comment: true
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
Report on a PR that renamed a button:
| flow | status | video | notes |
|---|---|---|---|
| Invite a teammate | ✏️ passed | .demo-engine/renders/invite-a-teammate/invite-a-teammate.mp4 | 1 changed, 3 unchanged · 1/1 locators healed · 2 touching files changed |
| key | meaning |
|---|---|
name, description | Title card. name also becomes the slug for output paths. |
url | Start URL. ${BASE_URL} is substituted; relative paths are joined to --base-url. |
auth.storageState | Playwright storage state file (cookies, local storage). |
auth.login | A .mjs file exporting async (page, context, { baseUrl }) that signs in before the flow. |
touches | Globs over your repo. Changed files matching them mark the flow as affected. |
setup | Shell command run before the flow (seed a demo tenant). BASE_URL is in the env. |
mask | CSS selectors hidden from the diff: the region is excluded from the pixel comparison and the elements are left out of the content comparison (clocks, live counters). Flow-level or per step. |
ignore | Regexes whose matches are dropped from the content comparison, for volatile text with no selector of its own ("\\d+ ms"). Flow-level or per step. |
viewport, voice | Default 1440×900 at 2×. Voice is provider-specific. |
defaults | Default audience values. Any string in the flow may use {{audience.field}} or {{audience.field | "fallback"}}. |
personalize | DOM rewrites applied before every screenshot: { css, text?, src?, html?, style?, attr?, all? }. |
end | Closing card: text, url. Shown when set, when brand.cta is set, or when the audience names a rep. |
Each step has say plus at most one action: goto, click, dblclick, hover, fill, type, select, check, press, scroll, wait. Optional: expect (text, visible, hidden, url), zoom, mask, pause, highlight. fill/type accept a press to hit Enter afterwards.
Locators are user-facing first: { role, name }, { label }, { placeholder }, { text }, { testid }, { anchor } (data-demo), { css } or a bare CSS string. Any locator can carry fallbacks: [...]. nth disambiguates.
| command | what it does |
|---|---|
init | Scaffold demos/, config and workflow. |
build [targets] | The pipeline. --since <ref>, --only-affected, --no-heal, --write-heals, --bless, --no-render, --no-narrate, --verbatim, --force, --report <dir>, --audience <name>, --audiences [names|files|csv...]. |
run / diff / heal / narrate / render / bless | Each stage on its own. run, narrate and render take --audience. |
audiences [flow] | List audiences and show which steps of a flow change per audience. |
changed --since <ref> | Which flows a change affects, by touches. |
anchors --src <dir> | Anchors referenced by flows but missing from the source. |
doctor | Browser, providers, keys. |
Targets are flow files, directories of *.flow.yaml, or run directories recorded by the Playwright fixture.
--write-heals. In CI, pair that with a PR-creating step so a reviewer sees the diff.| options | pick with | |
|---|---|---|
| LLM (script polish, heal) | Anthropic, OpenAI, none | llm: in config or ANTHROPIC_API_KEY / OPENAI_API_KEY |
| TTS | ElevenLabs, OpenAI, Kokoro (local neural), macOS say, silent | tts: in config or the matching key. Kokoro: pip install kokoro soundfile (Intel Mac: also brew install espeak-ng and pip install "torch==2.2.2" "numpy<2" "transformers<4.50"), DEMO_ENGINE_KOKORO_PYTHON to pick an interpreter, KOKORO_VOICE (default af_heart) |
| Render | Remotion (bundled Chrome Headless Shell) | nothing to configure |
Remotion is free for individuals and teams of up to three; larger companies need a Remotion company license.
Early. The pipeline is complete and tested end to end on the bundled example; what it needs now is your app. Open an issue with a flow that misbehaves and a run directory, and it gets fixed.
Roadmap: hosted player with analytics, Chrome-extension recorder, interactive HTML output from the same manifest, Slack alerts.
Apache-2.0. Commercial use welcome.