Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 84 additions & 5 deletions .claude/skills/open-edit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,10 @@ the defects `--verify` can't see). Exits:
on request); on a probe FAIL offer a
`--seed`/`--style` re-run; never redesign or hand-edit the .wv document · **3** = the sampled ref has no compiled
recipe (stale `style.json`; rerun SAMPLE ONE STYLE).
The chain's `--verify` runs the bounds family only. After exit 0, run the SAFE-ZONE CHECK (the VERIFY invocation
in the DESIGN + RENDER step's RENDER + VERIFY block) on `runs/<key>/final` — seconds, no re-record on a clean
result — and triage per its CHROME/TRANSIENT/MINOR/MAJOR rule: chrome, transient and minor → deliver and mention;
major → fix on a `--module` copy and re-run the chain.

CUSTOMISING (only when the user explicitly asks for a tweak to a recipe run): **NEVER edit a library
recipe (`refs/html/<id>/recipe.ts`) in place** — it is validated, shared by every run. COPY it to your
Expand Down Expand Up @@ -969,16 +973,89 @@ RENDER + VERIFY (OUTSIDE any sandbox — needs a real desktop session; binary =
— engine-limit anti-patterns (animated blur, the stacking trap, missing cue ids, per-corner radius).
Exit 1 → fix the flagged rule, re-lint before verifying.
VERIFY (analytic, fast, no video, reads manifest render block):
{repo}/.veed-engine/veed-engine-cli {repo}/runs/{key}/final --verify
{repo}/.veed-engine/veed-engine-cli {repo}/runs/{key}/final --verify=bounds,safezones --verify-report {repo}/runs/{key}/final/verify.json
It replays the whole timeline offscreen and checks the REAL draw list. Exit 0 = clean. Exit 1 = it prints ONE
stdout line per problem, naming the element id, e.g.:
frame 3 t=0.400s FAIL[bounds] #cap3 glyph 14 right 3.1px outside (8.42% of glyph box) viewport 736x1312
FAIL[never-visible] #cap5 glyph 2 ink in 300 frames, never fully visible (best 0.00% at frame 0 ...)
frame 2 t=0.200s FAIL[occluded] #cap2 glyph 5 fully covered by later opaque rect
FAIL[safezone] #b4w31 zone generic-9x16 53.5% of ink outside keep-inside, worst frame 314 t=10.5s, window 10.5..11.3s, 24 offending frames (longest run 24)
Built-in rules = the exact defects this pipeline hits: bounds (type off the viewport), never-visible (type
clipped away in EVERY frame — e.g. stuck behind a mask/box), occluded (type fully hidden under a later opaque
layer — the z-order/opacity trap). Fix ONLY the flagged element (nudge inside the safe zone / fix z-order or the
mask) and re-run --verify until exit 0. (exit 2 = engine render failure = a real authoring error, not a nit.)
layer — the z-order/opacity trap), safezone (type inside the viewport but outside the platform-safe area —
the SAFE-ZONE CHECK below owns its triage and fix). Fix ONLY the flagged element (nudge inside the safe zone /
fix z-order or the mask) and re-run --verify until exit 0. (exit 2 = engine render failure = a real authoring
error, not a nit.) If the engine prints its usage instead of a report, it predates `--verify=<rules>`
(`--help` lists `--verify[=<rules>]` on an engine that has it): run bare `--verify` for the first three rules
and say plainly that the safe-zone check did not run — never fake it from a screenshot.
SAFE-ZONE CHECK — the `safezones` family of the VERIFY invocation above. Same walk, no extra cost; it judges
GLYPH INK only (plates, boxes, images, video and semi-transparent fills are not observed) against the
platform-safe area, and both the check and every fix below are the DOCUMENT's — the mp4 is never inspected.
Zones: bare `safezones` picks the generic preset by canvas aspect — 9:16 → x 6..89% / y 11..83% (top 11%,
bottom 17%, left 6%, right 11%: the brief's own safe margins, the band feed UI covers), 16:9 → 6% inset,
1:1 → 5% inset. Custom zones when the user's platform or brand says so:
`--verify=bounds,safezones:{path}.json` with
`{"zones":[{"name":"...","rect":{"x":%,"y":%,"w":%,"h":%},"mode":"keep-inside|keep-out","severity":"error|warn"}],"exempt":["id"]}`
— or the same object as `"verify":{"safezones":{...}}` in manifest.json, which wins over the flag. `keep-out`
names a rect ink must stay OUT of (a logo corner, a sticker band); `warn` reports and scores but exits 0;
`exempt` lists ids whose bleed is the DESIGN (a full-bleed title, a ticker) — never an id you want to stop
failing.
READ THE REPORT: one FAIL[safezone] line per (element, zone), aggregated over the whole timeline — `% of ink`
is the element's intruding ink-area over its visible ink-area across every frame, `worst frame` is where to
look, `window` is first..last offending time, and `N offending frames (longest run M)` is how long the ink was
actually out (the window alone cannot tell one flash from two far apart). The element named is the INNERMOST id'd element carrying the
ink — in this pipeline's documents that is a WORD span (`#b4w31`); the thing you move is the LINE or BLOCK
that positions it (its `.ln` / page container), and the words of one line move together. `verify.json`
carries what stdout does not: `max_intrusion_px` per violation (the depth in canvas px — the number a fix
is sized from), `alpha_at_max_intrusion` (the run's effective opacity in that deepest frame — a slide-in still
fading up posts a deep number nobody sees), `offending_frames` / `longest_run_frames`, per-element scores and
an `overall_score` (100 = clean; ink-area-time weighted, so a brief
flash barely moves it and a line HELD outside sinks it — use it to describe, never to triage). To SEE a
worst frame: `{repo}/.veed-engine/veed-engine-cli {repo}/runs/{key}/final --headless --frame-num-until-exit {frame} --exit-screenshot {path}.png`.
CHROME FIRST: an element whose id ends in `-chrome` is DRESSING (kickers, credits, film-strip labels and
marks, stickers) — not the spoken line. The convention: a recipe or an authored document puts the suffix on
the element that DIRECTLY wraps the text (the engine labels a run by its direct parent's id; an id one level
up leaves the run reported by its text, pooled with every other run of the same text). A `FAIL[safezone]` on
a `-chrome` id is not triaged and is never fixed: name it in ONE clause at delivery ("the credits strip runs
under the feed UI") and deliver. Only content violations enter the triage below.
TRIAGE — TRANSIENT vs MINOR vs MAJOR, per positioned line, from the numbers (never by eye). Let `edge` = 2%
of the canvas's shorter side (22px on a 1080-wide canvas) and `hold` = 250ms in frames (8 at 30fps, 6 at
25). A report without `longest_run_frames` (an engine before that field) reads the `window` length as the
hold instead — it overstates two flashes far apart, never understates a held line.
TRANSIENT: every violation on the line has `longest_run_frames` < hold AND `ink_intruding_fraction` <= 0.05.
A line's slide-in or settle crossing the margin for a few frames, usually while still fading up; the
composition is right at rest, and `max_intrusion_px` here is the animation's travel, not a placement.
NOT a fix: deliver, and mention it in ONE clause ("two lines cross the safe margin for a few frames on
entry"). Name it as a visible flick only when `alpha_at_max_intrusion` is above 0.5.
MINOR: not transient, and every violation on the line has `max_intrusion_px` <= edge AND
`ink_intruding_fraction` <= 0.25.
A descender, an overshoot, a line box set ON the margin. AUTOCORRECT without asking: shift that line's
container inward by ceil(max_intrusion_px) + 4px (the side is the one the line sits nearest — the
document tells you, the report does not), re-run VERIFY, and mention it in ONE clause at delivery
("nudged two lines inside the safe area").
MAJOR: anything else — deeper than `edge` and not transient, more than a quarter of the ink out, or `100%`
(the whole element outside). A band placed under the feed UI, a title wider than the zone, a wrong-canvas
assumption.
AUTOCORRECT too, but as a RE-PLACEMENT, not a nudge: put the block at the nearest legal position on its
own side (bottom band → top = zone bottom px − block height − 8px; a side → left/right = zone edge + 8px);
if the block is WIDER than the zone (left AND right both fail, or its width exceeds the zone's) step it
ONE rung down the size ladder first, then place; if `analysis.json` exists and the new position lands on
`faceBbox`, take the other band. Re-run VERIFY. A major fix changes the composition, so tell the user what
moved and by how much in plain terms — not the rule name. Never resize, recolour or re-time anything
else.
keep-out zones triage on the same numbers (depth = how far INTO the rect, fraction = how much of the ink
is in it, hold = how long); the fix moves the ink OUT the shortest way.
`WARN[safezone]` lines never block; treat them as minor for the message and fix them only if the fix is a
nudge.
At most TWO correction cycles, then stop and report honestly — a third means the placement rule is wrong,
not the number. On a COMPILED-RECIPE run the document is script-owned: a safezone FAIL is a recipe geometry
bug — a CHROME one is dressing and is delivered and mentioned; a TRANSIENT one is delivered and mentioned (the
recipe's entry animation, not its placement); a MINOR
one is delivered and reported (the recipe's own margins are the fix, offline); a MAJOR one is fixed on a
`--module` COPY (the CUSTOMISING route), never in `final/template.wv` by hand.
A delivered result the user asks you to CHECK ("is this inside the safe zones?") is the same command on its
run dir's `final/` — the check needs the document; an mp4 with no run dir has nothing to replay, so say that
rather than judging frames by eye.
EXPECT WINDOWS (optional) — word-reveal TIMING: to assert a caption is shown/hidden in a time window, add a "verify" block to
manifest.json alongside "render": {"verify":{"expect":[{"element":"cap3","visible":true,"from":2.1,"to":3.4}]}}.
--verify then FAILs[expect-visible]/[expect-hidden] if a word isn't on-screen when it should be. Use when a
Expand Down Expand Up @@ -1075,8 +1152,10 @@ naming the donors in `donors`), then author
whole chain with one command (OUTSIDE any sandbox — verify and record need a real desktop session):
`npx @veedstudio/openedit-cli gates runs/<key>-remix`
It runs design → lint → `--verify` → WCAG → `--record` → probe-qa → mux, stops at the first failure and names
the gate. A `--verify` failure: fix ONLY the flagged element and re-run, at most twice, then stop and
report honestly. A probe-qa failure: report it in plain terms and pick the fix WITH the user — never
the gate. Its `--verify` is the bounds family only, so run the SAFE-ZONE CHECK (the VERIFY invocation in the
RENDER + VERIFY block) on `runs/<key>-remix/final` BEFORE the chain — you authored the document, the fix is
yours, and a clean document costs no re-record. A `--verify` failure: fix ONLY the flagged element and re-run,
at most twice, then stop and report honestly. A probe-qa failure: report it in plain terms and pick the fix WITH the user — never
redesign. The deliverable lands next to the original, and the user compares.
The WCAG AA pass runs INSIDE that chain, before the record — do not run it again afterwards. It DETECTS
and REPORTS only; the chain does not pause and does not apply anything. On `status: attention` the
Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,26 @@ OpenEdit is an open-source, agent-driven editing pipeline that ships with VEED's
source, but free to use.

There is no GUI and no timeline. The pipeline is driven entirely through your coding agent — edit,
cut, and reframe footage; layer motion graphics and visual elements; turn
slides or websites into video; capture web pages; and pull in any video/image generating service
cut, and reframe footage; layer motion graphics and visual elements; turn slides or websites into
video; capture web pages; and pull in any [AI video/image generator](https://www.veed.io/tools/ai-video)
or MCP server when it helps. Source video is optional: stills, slides, generated media, or pure
motion graphics are enough when the brief calls for it. Be creative and fluid — try new ideas
rather than collapsing every ask onto captions.

OpenEdit edits footage. Supply your own source files, or ask it to generate a talking-head clip with
VEED Fabric when you have none — that spends credits, and never without your approval.
[VEED Fabric](https://www.veed.io/ai/fabric-1-0) when you have none — that spends credits, and never
without your approval.

<a href="https://github.com/veedstudio/open-edit/releases/download/launch-examples/OpenEdit-4x3-trim.mp4"><img src="docs/examples/openedit-launch.webp" alt="OpenEdit launch video" width="100%"></a>

*This launch video was made in OpenEdit — click it to watch with sound.*

<a href="https://github.com/veedstudio/open-edit/releases/download/launch-examples/openedit-astra.mp4"><img src="docs/examples/openedit-astra.webp" alt="GPT-6 Astra title sequence made in OpenEdit" width="100%"></a>

*Also made in OpenEdit, with GPT-6 Astra driving the pipeline — pure motion graphics, no source
footage. Its prompt was written against the [OpenAI Brand Film](https://vimeo.com/1122006941) as a
visual reference.*

## Requirements

| | |
Expand Down Expand Up @@ -98,7 +105,8 @@ Real outputs, each with the prompt that produced it. Click any example to watch
create viral subtitles with /open-edit and translate my video to 5 languages using VEED Lipsync 2.0 on Fal
```

One source clip, three languages, three caption styles:
One source clip, three languages, three caption styles — translated and re-lipsynced through
[VEED's Lip Sync API](https://www.veed.io/tools/lip-sync-api):

| Spanish | French | German |
| --- | --- | --- |
Expand All @@ -108,7 +116,8 @@ One source clip, three languages, three caption styles:
generate 3 viral hooks in Seedance 2.0 on Fal and create dynamic motion graphics using /open-edit
```

Three AI-generated hooks, three motion-graphic treatments:
Three hooks generated with [Seedance](https://www.veed.io/tools/ai-video/seedance), three
motion-graphic treatments:

| | | |
| --- | --- | --- |
Expand Down
Binary file added docs/examples/openedit-astra.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion docs/recipe-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ fix loop · DO NOT → simply how the code behaves.
6. **VERIFY LOOP** — verbatim commands:
`{repo}/.veed-engine/veed-engine-cli {repo}/runs/<key>/final --verify` → per failure class a MECHANICAL fix
(bounds → which value to change by how much; never-visible → what to check; occluded → z rule), re-run
to exit 0, ≤2 fix cycles → `--record`. Manifest line included verbatim.
to exit 0, ≤2 fix cycles → `--record`. Manifest line included verbatim. Ids: the engine labels a text run by
its DIRECT parent's id, so the id goes on the element that wraps the text. Dressing text (kickers, credits,
labels, marks, stickers) ends its id in `-chrome`; the safe-zone check reports those but never fixes them, so
only the spoken line is ever moved. The bounds ladder's demotion key stops at the hyphen (`b1p2mk` for
`#b1p2mk-chrome`), so a recipe keys its demotion on the bare id.
7. **DO NOT** — no fonts/colors/keyframes beyond the sheet; no invented timing; no reading the frames; no
redesign.

Expand Down
22 changes: 16 additions & 6 deletions pipeline/director-brief.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,16 +311,26 @@ The binary is `{run dir}/../../.veed-engine/veed-engine-cli` (the preflight-mana
— catches the engine-limit anti-patterns above (animated blur, the stacking trap, a multi-value radius, missing
cue ids) before the slower verify. Exit 1 → fix the flagged rule, re-lint.
1. VERIFY (analytic, fast, no video — the ONLY self-check you perform by default; reads the manifest render block):
`.veed-engine/veed-engine-cli {run}/final --verify`. It replays the whole timeline offscreen and checks the REAL
draw list. Exit 0 = clean. Exit 1 = one stdout line per problem, naming the element id, e.g.:
`.veed-engine/veed-engine-cli {run}/final --verify=bounds,safezones --verify-report {run}/final/verify.json`. It
replays the whole timeline offscreen and checks the REAL draw list. Exit 0 = clean. Exit 1 = one stdout line per
problem, naming the element id, e.g.:
`frame 3 t=0.400s FAIL[bounds] #cap3 glyph 14 right 3.1px outside (8.42% of glyph box) viewport 736x1312`
`FAIL[never-visible] #cap5 glyph 2 ink in 300 frames, never fully visible (best 0.00% at frame 0 ...)`
`frame 2 t=0.200s FAIL[occluded] #cap2 glyph 5 fully covered by later opaque rect`
`FAIL[safezone] #b4w31 zone generic-9x16 53.5% of ink outside keep-inside, worst frame 314 t=10.5s, window 10.5..11.3s, 24 offending frames (longest run 24)`
The rules map to the real defects: bounds (type off the viewport), never-visible (type clipped away EVERY frame,
e.g. stuck behind a mask/box), occluded (type fully hidden under a later opaque layer — the z-order/opacity trap).
Fix ONLY the flagged element (nudge inside the safe zone / fix z-order or the mask) and re-run --verify until exit
0. Do NOT change the aesthetic, colours, fonts, device, animation, or timing. (exit 2 = engine render failure = a
real authoring error.) Every text layer needs a unique `id` so the failure lines name it. OPTIONAL word-reveal
e.g. stuck behind a mask/box), occluded (type fully hidden under a later opaque layer — the z-order/opacity trap),
safezone (glyph ink outside the safe margins above — the `safezones` family picks the preset by canvas aspect,
and the 9:16 preset IS those margins). Fix ONLY the flagged element (nudge inside the safe zone / fix z-order or
the mask) and re-run --verify until exit 0. A safezone line names the WORD span; move the line that positions it,
sized from `max_intrusion_px` in verify.json — the skill's SAFE-ZONE CHECK holds the transient/minor/major rule
(a slide-in crossing the margin for a few frames is not a placement defect). An engine
that prints its usage on `--verify=` predates the rule list: run bare `--verify` and report that safe zones went
unchecked. Do NOT change the aesthetic, colours, fonts, device, animation, or timing. (exit 2 = engine render failure = a
real authoring error.) Every text layer needs a unique `id` so the failure lines name it — on the element that
DIRECTLY wraps the text, since the engine labels a run by its direct parent. Dressing text (kickers, credits,
labels, stickers — anything that is not the spoken line) ends its id in `-chrome`, which the safe-zone check
reports but never fixes. OPTIONAL word-reveal
timing: add `"verify":{"expect":[{"element":"cap3","visible":true,"from":2.1,"to":3.4}]}` to manifest.json to make
--verify FAIL[expect-visible]/[expect-hidden] when a caption is on/off screen at the wrong time.
2. RECORD the deliverable — ONLY after --verify is clean. --verify and --record are mutually exclusive, so this is a
Expand Down
Loading