Skip to content

A skill for filming a prototype (sp-create-video), and sp- in front of every skill - #177

Merged
Jing-yilin merged 7 commits into
mainfrom
sp-scene-video
Sep 25, 2026
Merged

Jing-yilin merged 7 commits into
mainfrom
sp-scene-video

Conversation

@Jing-yilin

@Jing-yilin Jing-yilin commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Two changes: a sixth skill, and sp- in front of every skill's name.

1. sp-create-video

Turn a board into a live-action clip of a real person using the product — an office, a lift, a walk down a corridor — with the interface kept pixel-exact rather than redrawn.

This is the notion-purchase-motion session of 10–11 September, kept. Thirteen paid takes on Seedance 2.5 found the rule the skill is built on: a model shown a screenshot composes its own UI (right layout, right blue, invented words), and a model given a video of the UI keeps it and paints a room around it. So the first phase is building an animated board, not writing a prompt.

What ships

SKILL.md The route table, the spending rule (a take is the user's money: one, then show it, then ask), and the five phases.
scripts/frames.mjs Renders an animated board to PNG frames through CDP, pausing every animation and setting its currentTime rather than recording the page — a recorder drops frames under load and never says so, and this way the same board twice is the same bytes twice.
scripts/ark.py Submits one take to Ark (BytePlus ModelArk by default, Volcengine Ark with --region cn), polls it through a dropped connection, downloads the mp4 before its 24-hour URL expires, and writes the prompt, seed and usage beside it. Stdlib only.
scripts/composite.py The rescue route: corner-pins the real frames onto a green plate, thumb on top, when the model will not hold the interface. Run through uv run --with opencv-python-headless, so the toolkit keeps its two dependencies.
references/ The prompt patterns that stop the redraw and keep subtitles out; the motion board and getting its mp4 somewhere Ark can fetch it; the green-plate composite.

Decisions

docs/2026-09-25-scene-video.md covers them: why Ark and not fal (fal was paid for and never returned a clip; Replicate wanted $0.97 per second; a 720p 10s take on Ark is about ¥11) and why ark.py defaults to BytePlus ModelArk, Ark's name outside China, with --region cn for a Volcengine key. Why the green plate ships as the fallback and not the route. And the evening spent on a 530 from cloudflared: it has to run outside the agent's sandbox, and a fake-IP VPN breaks its edge lookup unless the edges are pinned.

Review

All seven Codex comments are fixed in bd74820/the follow-up commit: the scrub is now getAnimations() + currentTime (the delay rule was measured from wherever the pause landed, so two renders of one board differed by up to 170 levels a pixel); the documented ffmpeg line crops to even dimensions, without which libx264 refused the 1179 px width outright; Chrome is resolved the way refkit resolves it, Windows and Edge included, with the profile in the OS temp directory; ark.py numbers past the highest take rather than counting them, and writes its record as UTF-8; the documented call passes --key-file; composite.py handles a frame with no chroma in it.

Verified

  • frames.mjs against the real board 19: 10 frames, 8 distinct, holds where the timeline holds, transparent outside .phone.
  • composite.py (ported to derive the UI size from the frames rather than hard-coding 1179×2556) against the real plate and frames: 241 frames, the sheet upright on the glass, the thumb over it.
  • ark.py --dry emits the same request body as the takes that succeeded.
  • No API call was made and nothing was spent.

No mp4 is committed. Takes, plates and frames are derived and belong in a project's scratch/video/.

2. Every skill is named sp-

clone-prototype → sp-clone-prototype, and the same for sp-new-ui-mock, sp-define-product and sp-brand-kit. prototype-canvas becomes sp-canvas: shortened as well as prefixed, since everything here is a prototype and the skill is mostly the sp canvas command.

A skill directory is one flat namespace an agent shares between every source it installs from, and those were the plainest words for what they do — the names a user's own skill is likeliest to take. The collision is silent: linkInstall keeps the user's folder rather than replacing it (isOurCopy), so the app's skill simply never installs and the user runs something else under the name they read in the README.

The rename carries three things with it:

  • The old links are taken out on the next launch. linkInstall only ever made links, so a renamed skill left ~/.claude/skills/clone-prototype pointing into a current/skills/ entry that is gone, which the agent lists as a broken skill. It now removes a link into current that resolves to nothing, by the same rule sp uninstall uses, and leaves anything the user put there alone. Covered by a new test in desktop/launch.test.ts.
  • The copy that names a command: the welcome board and the x-ios mock post say /sp-clone-prototype.
  • The prose, across AGENTS.md, both READMEs, the canvas's strings and every skill's references. docs/ and the tagged sections of RELEASE-NOTES.md are left as they are — dated records of what was true when written.

docs/2026-09-25-sp-prefixed-skills.md has the reasoning and the two alternatives not taken.

The welcome board generates again

canvases/00-welcome/gen.py had not been runnable since boards moved into canvases/ (51220fa): ASSETS read ../../../assets/banner.webp, one level above the repo, and the banner at the real path is the landing page's hero now — download buttons and all — not the strip the board was built around. The board has its own assets/ in this PR, which is what the folder rules ask of every canvas folder: the art restored from before the landing page took the name (e47e45d), and the icon beside it. Two things that had drifted into the committed HTML are back in the generator, layout.json's ground (added by hand in 2c22caf) and the /sp-clone-prototype line, and gen.py now reproduces both committed files byte for byte.

Checks

bun test in desktop/ (10 pass), bun run test in canvas/ (227 pass, 1 skipped), pytest in tools/ (40 pass).

Since review

  • Renamed sp-scene-video → sp-create-video.
  • ark.py --region intl|cn: BytePlus ModelArk (dreamina-seedance-2-5-260628) by default, Volcengine Ark (doubao-seedance-2-5-260628) for a China key. The ModelArk endpoint answers (401 on a bad key); no ModelArk take has been shot yet.
  • Prompts and prose are in English. The takes were shot with Chinese prompts; prompting.md says the English wording is unshot.
  • Review fixes: frames.mjs cleans up Chrome and its profile on any exit and requires Node 22+; CI compiles skills/ and node --checks frames.mjs; installSkills no longer removes a newer app's skill it has not heard of (new test); unslop pass on the new prose.
  • Checks: canvas 228 pass / 1 skipped, desktop 10 pass, tools 40 pass.

🤖 Generated with Claude Code

sp-scene-video turns a board into a live-action clip of someone using the
product, with the interface kept pixel-exact rather than redrawn. It is the
notion-purchase-motion session of 10-11 September, kept: thirteen paid takes
that found out a model shown a screenshot composes its own UI, and a model
given a video of the UI keeps it.

- scripts/frames.mjs renders an animated board to PNG frames through CDP,
  scrubbing the CSS timeline rather than recording it.
- scripts/ark.py submits one take to Seedance 2.5 on 火山方舟, polls it
  through a dropped connection, and writes the prompt, seed and usage beside
  the mp4.
- scripts/composite.py is the rescue route: corner-pin the real frames onto
  a green plate when the model will not hold the interface.
- references/ carry the prompt patterns that stop the redraw, the hosting the
  reference video needs, and the compositing.

docs/2026-09-25-scene-video.md says why Ark and not fal, why the green plate
ships as a fallback rather than the route, and what the evening on a 530 from
cloudflared was about.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Deploying super-prototyping with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1d67a5b
Status: ✅  Deploy successful!
Preview URL: https://a5281895.super-prototyping.pages.dev
Branch Preview URL: https://sp-scene-video.super-prototyping.pages.dev

View logs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f70c51afb5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread skills/sp-scene-video/scripts/ark.py Outdated
a.key_file.read_text().strip() if a.key_file.is_file() else
sys.exit("no key: set ARK_API_KEY or put it in %s (chmod 600)" % a.key_file))
a.out.mkdir(parents=True, exist_ok=True)
n = 1 + len(list(a.out.glob(a.tag + "-*.mp4")))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Derive the next take number from existing suffixes

When matching files are non-contiguous, counting them does not produce an unused suffix: for example, walk-1.mp4 and walk-3.mp4 yield n == 3. After the paid task succeeds, this overwrites both walk-3.json and walk-3.mp4, losing the previous take and its provenance; parse the maximum existing suffix or otherwise reserve a free filename instead.

Useful? React with 👍 / 👎.

Comment thread skills/sp-scene-video/scripts/ark.py Outdated
"prompt": prompt,
"images": [str(p) for p in a.image], "video": a.video,
"result": st, "seconds": round(time.time() - t0)}
(a.out / ("%s-%d.json" % (a.tag, n))).write_text(json.dumps(record, ensure_ascii=False, indent=1))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Write the take record explicitly as UTF-8

On Windows installations whose locale encoding is not UTF-8, the required Chinese prompt makes this write_text call raise UnicodeEncodeError after the paid generation has succeeded but before the MP4 is downloaded. Specify encoding="utf-8", as is already done when reading the prompt, so Windows users retain both outputs.

AGENTS.md reference: AGENTS.md:L69-L75

Useful? React with 👍 / 👎.

return a[1] + (b[1] - a[1]) * (t - a[0]) / (b[0] - a[0])
}

const CHROME = process.env.CHROME || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve Chrome on every supported platform

On Windows—and on Linux—the documented node frames.mjs ... command always tries the macOS application path and fails unless the user discovers and manually sets the undocumented CHROME environment variable. Since this skill is shipped into Windows agent homes, resolve the platform-specific Chrome executable (or document and require the override) rather than making the primary rendering step macOS-only.

AGENTS.md reference: AGENTS.md:L69-L75

Useful? React with 👍 / 👎.

Comment on lines +122 to +123
screen, ref_area = biggest(chroma(ref))
quad = quad_from_mask(screen)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip frames with no chroma component during reference search

If the frame at --ref has no detectable green component—for example, the phone is initially offscreen or fully occluded—biggest() returns None, which is passed to quad_from_mask() and causes OpenCV's findContours to fail before the loop can inspect a later usable frame. Guard the empty mask and continue scanning, matching the loop's stated purpose of finding the first frame with four visible edges.

Useful? React with 👍 / 👎.

A skill directory is one flat namespace an agent shares between every source
it installs from, and `clone-prototype`, `new-ui-mock`, `prototype-canvas`,
`define-product` and `brand-kit` were the plainest words for what they do --
the names a user's own skill is likeliest to take. A collision is silent:
linkInstall keeps the user's folder rather than replacing it, so the app's
skill simply never installs. They are all `sp-` now, as sp-scene-video already
was, and `/sp-brand-kit` says whose it is where the user types it.

The app takes the old links out on its next launch. linkInstall only ever made
links, so a renamed skill left `~/.claude/skills/clone-prototype` pointing into
a `current/skills/` entry that is gone, which the agent lists as a broken
skill. It now removes a link into `current` that resolves to nothing, by the
same rule `sp uninstall` uses, and leaves the user's own alone either way.

canvases/00-welcome/00-welcome.html is edited by hand, against the folder rule,
because its gen.py cannot run: it reads ../../../assets/banner.webp, one level
above the repo since boards moved into canvases/, and the banner at the real
path is the landing page's hero now rather than the board's strip. The
generator's copy is edited to match. docs/2026-09-25-sp-prefixed-skills.md has
the rest, including what was deliberately left unrenamed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Jing-yilin Jing-yilin changed the title A skill for filming a prototype A skill for filming a prototype, and sp- in front of every skill Sep 25, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e53d4dd9bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread skills/sp-scene-video/SKILL.md Outdated
Comment on lines +76 to +78
--fps 24 --seconds 10 -o "$V/out/ui" --scale 3 # bun runs it too
ffmpeg -y -framerate 24 -i "$V/out/ui/f%04d.png" -c:v libx264 -crf 16 \
-pix_fmt yuv420p "$V/out/mockup.mp4"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pad odd-width phone frames before H.264 encoding

For the repository's standard 393px-wide .phone (skills/sp-prototype-canvas/references/layout.md:155), the documented --scale 3 produces 1179px-wide PNGs. libx264 rejects that odd width when encoding yuv420p, so this default workflow stops before producing mockup.mp4; pad/crop to even dimensions or use an even scale.

Useful? React with 👍 / 👎.

ap.add_argument("--seed", type=int, help="repeat a take you liked, or vary one you did not")
ap.add_argument("--no-audio", action="store_true", help="skip the generated ambience")
ap.add_argument("--model", default=MODEL)
ap.add_argument("--key-file", type=Path, default=Path(".ark_key"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Read the key from the documented workflow location

The skill tells users to put the key in $V/.ark_key, but its example invokes this script from the project directory without --key-file, so the default resolves to ./.ark_key instead and exits with no key. Either pass $V/.ark_key in the documented command or derive the default from the workflow's video directory.

Useful? React with 👍 / 👎.

Comment on lines +99 to +100
document.getElementById('sp-scrub').textContent =
'${selector} *{animation-play-state:paused!important;animation-delay:-${t}s!important}'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pause animations on the selected element too

When the motion is applied to .phone itself, this descendant-only rule never pauses or seeks it; animations on its pseudo-elements are missed as well. Those parts continue according to wall-clock time while the script captures frames, contradicting the deterministic scrubbing contract and producing timing-dependent output, so include the selected root and its pseudo-elements in the scrub rule.

Useful? React with 👍 / 👎.

Jing-yilin added a commit that referenced this pull request Sep 25, 2026
Seven comments on #177, six of them real. The frame renderer's scrub was the
one worth the most: a `*{animation-delay:-Ts}` rule only moves an animation
that is still running, and these are paused, so the delay was measured from
wherever the pause happened to land -- wall-clock. The same board rendered
twice came back different, by up to 170 levels a pixel. It now pauses every
animation `document.getAnimations()` returns and sets `currentTime`, which
covers pseudo-elements and the clipped element itself as well, and two runs
of the same board are now identical to the byte.

The documented ffmpeg line could not have worked: the standard 393 pt phone is
1179 px wide at --scale 3, and libx264 refuses an odd dimension in yuv420p. It
crops the column rather than padding a black line on.

Chrome is resolved the way refkit resolves it, Windows folders and Edge
included, and the profile goes in the OS temp directory, so the primary step
is not macOS-only in a skill that installs into Windows agent homes.

ark.py numbers a take past the highest already there rather than counting the
mp4s: a gap in the series would have taken a number back and overwritten the
record of a clip that cost money. Its JSON is written as UTF-8 explicitly, or
a Chinese prompt raises UnicodeEncodeError on a Windows console encoding after
the take is already paid for. The documented call passes --key-file, which the
skill's own `$V/.ark_key` needs.

composite.py returns None for a frame with no chroma in it instead of handing
None to findContours, and says so when no frame shows four edges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seven comments on #177, all of them real. The frame renderer's scrub was the
one worth the most: a `*{animation-delay:-Ts}` rule only moves an animation
that is still running, and these are paused, so the delay was measured from
wherever the pause happened to land -- wall-clock. The same board rendered
twice came back different, by up to 170 levels a pixel. It now pauses every
animation `document.getAnimations()` returns and sets `currentTime`, which
covers pseudo-elements and the clipped element itself as well, and two runs
of the same board are now identical to the byte.

The documented ffmpeg line could not have worked: the standard 393 pt phone is
1179 px wide at --scale 3, and libx264 refuses an odd dimension in yuv420p. It
crops the column rather than padding a black line on.

Chrome is resolved the way refkit resolves it, Windows folders and Edge
included, and the profile goes in the OS temp directory, so the primary step
is not macOS-only in a skill that installs into Windows agent homes.

ark.py numbers a take past the highest already there rather than counting the
mp4s: a gap in the series would have taken a number back and overwritten the
record of a clip that cost money. Its JSON is written as UTF-8 explicitly, or
a Chinese prompt raises UnicodeEncodeError on a Windows console encoding after
the take is already paid for. The documented call passes --key-file, which the
skill's own `$V/.ark_key` needs.

composite.py returns None for a frame with no chroma in it instead of handing
None to findContours, and says so when no frame shows four edges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c2826fcf1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/launch.ts
Comment on lines +164 to +168
// A skill a release renames or drops leaves its old link behind, pointing into a
// `current/skills/<name>` that is no longer there, and the agent shows it as a broken
// skill. Ours to remove, by the same rule `sp uninstall` uses: a link into `current`,
// now resolving to nothing. Anything the user put there is left as it is.
const dir = path.join(home, agentHome, "skills");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove renamed copies from the canvas workspace cache

When upgrading an installation that has already used canvas chat, the old skills are real copied directories under <projects>/.workspaces/.claude/skills and .agents/skills, not the home-level links cleaned up here. installSkills() only iterates current source names and never removes managed copies whose names disappeared, so clone-prototype, define-product, and the other old names remain visible and invokable beside the six sp- skills, with stale instructions that reference paths removed by this commit. Extend the rename migration to remove obsolete managed copies from the persistent workspace cache as well.

AGENTS.md reference: AGENTS.md:L10-L13

Useful? React with 👍 / 👎.

# Conflicts:
#	README.md
#	RELEASE-NOTES.md
#	skills/README.md
#	skills/sp-prototype-canvas/SKILL.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42661d3d58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

<h2>Start with this skill</h2>
<div class="skill">
<b>/clone-prototype</b>
<b>/sp-clone-prototype</b>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Regenerate the welcome board from gen.py

This edits the generated board directly, and the accompanying decision note confirms it was changed by hand because its generator cannot currently run. That leaves the committed output without a reproducible generation path; repair the generator’s asset input and rerun it rather than committing a manual HTML edit.

AGENTS.md reference: AGENTS.md:L92-L93

Useful? React with 👍 / 👎.

Comment on lines +43 to +44
except urllib.error.HTTPError as e:
sys.exit("HTTP %s: %s" % (e.code, e.read().decode()[:800]))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Retry transient HTTP poll failures

When a paid task’s GET poll receives a transient HTTP response such as 429 or 5xx, call() converts it to SystemExit here, so the retry handler around the poll never sees it and the process abandons the task before downloading its expiring result. Retry retryable HTTP statuses—respecting Retry-After where present—while preserving terminal client errors.

Useful? React with 👍 / 👎.

pts = np.vstack([np.array([p[0] for p in pairs]), SRC[:2]]); dst = np.vstack([np.array([p[1] for p in pairs]), q[:2]])
Hn, _ = cv2.findHomography(pts, dst, 0)
if Hn is not None: Hc = Hn; refined += 1
u = cv2.imread(str(ui[(i + a.offset) % len(ui)]), cv2.IMREAD_UNCHANGED)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clamp shifted UI frames instead of wrapping

Whenever the documented --offset is nonzero, modulo indexing wraps one end of the animation to the other: for example, --offset 1 makes the final plate frame show f0000.png. This introduces an abrupt reset at the end of an otherwise aligned take; shifted frames outside the UI range should hold the first or last frame rather than loop.

Useful? React with 👍 / 👎.

Comment on lines +92 to +96
const clip = await evaluate(`(() => {
const el = document.querySelector(${JSON.stringify(selector)})
if (!el) return null
const r = el.getBoundingClientRect()
return { x: r.x, y: r.y, width: r.width, height: r.height, scale: 1 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scrub before calculating the capture clip

When the selected .phone itself animates position, scale, or another geometry-affecting property, this rectangle is sampled after the arbitrary 1.5-second load delay and before animations are first scrubbed, then reused for every frame. The fresh code now pauses the root animation, but these pre-scrub bounds can still crop it or add varying empty space throughout the rendered sequence; establish deterministic bounds after seeking to a defined time or account for the animation’s full extent.

Useful? React with 👍 / 👎.

The prefix was the point of the rename; the word "prototype" in the middle
was not carrying any of it. Everything on the canvas is a prototype, and the
skill is mostly the `sp canvas` command, which is what the app already calls
it.

The directory moves, `name:` in its frontmatter follows, and every mention
across the prose, the canvas's agent prompt and `sp`'s help text goes with
them. `docs/` and the tagged sections of RELEASE-NOTES are left as they were,
as the rest of this branch leaves them: they are dated records. The Unreleased
bullet and the decision note now say this one was shortened as well as
prefixed, rather than implying the prefix was the whole change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d1000141c4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

(a.out / ("%s-%d.json" % (a.tag, n))).write_text(
json.dumps(record, ensure_ascii=False, indent=1), encoding="utf-8")
mp4 = a.out / ("%s-%d.mp4" % (a.tag, n))
urllib.request.urlretrieve(st["content"]["video_url"], mp4)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retry the paid result download

If the result URL returns a transient error or the connection drops, urlretrieve raises after the paid task has succeeded and can leave a truncated final .mp4. Because the JSON record already occupies this take number, rerunning the documented command submits a new paid task under the next number rather than completing the existing one. Retry this download and write to a temporary file before atomically renaming it.

Useful? React with 👍 / 👎.

Comment thread skills/sp-scene-video/SKILL.md Outdated

## Spending rule

Every take is the user's money: roughly ¥11 at 720p/10s, ¥74 at 1080p/15s,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Price the default reference-video take at ¥22

The skill's default route and example submission include --video, but the reference cost table says a 720p/10s take with a reference video costs about ¥22; ¥11 is the image-only price. Since this paragraph governs the required pre-submission cost disclosure, agents following it will underquote the default paid take by roughly half; make the estimate route-sensitive or use the ¥22 default.

Useful? React with 👍 / 👎.

```bash
uv run --with opencv-python-headless --with numpy \
"$KIT/skills/sp-scene-video/scripts/composite.py" \
out/plate-1.mp4 out/ui out/scene.mp4 --lock --stabilize

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Point the composite command at the video workspace

In the documented workflow the current directory remains the project root, while the earlier commands write the plate and UI frames beneath $V/out; this command instead reads out/plate-1.mp4 and out/ui, so copying it verbatim exits with no f*.png frames in out/ui. Use $V/out/... consistently or explicitly change into $V before this command.

Useful? React with 👍 / 👎.

Five, all real.

The welcome board can be generated again. It has its own `assets/` now, as
every canvas folder is supposed to: the art it was built from, restored from
before the landing page took the name at the repo root (e47e45d), and the icon
beside it. Two things that had drifted into the committed output are back in
the generator -- `layout.json`'s `ground`, added by hand in 2c22caf, and the
`/sp-clone-prototype` line. `gen.py` now reproduces both files byte for byte,
so the hand edit this branch documented as an exception is not one any more.

The chat panel's agent loses the old names too. Its skills are real copies
under `<projects>/.workspaces`, not the links `linkInstall` cleans up, and
`installSkills` only ever wrote the names the tree has, so `clone-prototype`
would have stayed there, listed and invokable, pointing at paths that are
gone. It now removes a copy whose name the tree no longer ships, by the
`managed-by` marker that makes a copy ours; a folder without one is the
user's and stays.

A busy Ark no longer abandons a paid take. `call` exited the process on any
HTTP error, including the 429 and 5xx a poll is most likely to meet, so the
task went on running with nobody holding its id. Those raise now, into the
poll loop's own retry; every other code still fails where it did, and a
submission that never started says so.

frames.mjs measures the capture rectangle after the first scrub rather than
1.5 s into a running board: on a board that animates the phone itself the
clip used to land wherever the load left it, x = 42.25 px one run and 42.50
the next on a test board, instead of the 20 px the phone actually starts at.

composite.py clamps `--offset` instead of wrapping it, so a shift or a plate
longer than the UI holds the first or last frame rather than cutting back to
the start of the animation mid-shot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

…iew fixes

The skill is sp-create-video. ark.py takes --region intl|cn: BytePlus ModelArk
by default, Volcengine Ark for a China key, the same request at a different
host and model id. Prompts and prose are in English; the Chinese prompts the
takes were shot with are translated, and prompting.md says the translation
is unshot.

From review: frames.mjs kills Chrome and removes its profile on any exit and
says it needs Node 22; CI compiles skills/ and checks frames.mjs; an older
app no longer removes a newer app's skill it has not heard of; ark.py's
docstring says when the record is written; composite.py notes its memory
ceiling; the prose flagged by the unslop pass is rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@Jing-yilin Jing-yilin changed the title A skill for filming a prototype, and sp- in front of every skill A skill for filming a prototype (sp-create-video), and sp- in front of every skill Sep 25, 2026
@Jing-yilin
Jing-yilin merged commit 8312e73 into main Sep 25, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant