Parker's#3
Open
parrrkerli wants to merge 11 commits into
Open
Conversation
Owner
|
Thanks for the contribution! I took a look at the changes. A few issues need to be addressed before this can be merged:
Suggested next steps:
Happy to review again once cleaned up! |
…ements - Abort running tasks when leaving Studio (server kills CLI on disconnect) - Add /api/works/:id/abort endpoint - Don't auto-start tasks when opening draft works - Add genre-specific guides and emotional hooks modules to all skills - Move creator-analytics into trend-research, remove standalone skills - UI redesign with improved pipeline steps, asset panel, and i18n Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hance UI Add new skill modules (beat-sync, music-search, video-understanding), improve Explore/Studio/Works pages with better UX flow, and refine emotional hooks across all skill pipelines. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nd explore showcase - Add titleLocked flag to prevent auto-title overwrites after first agent-set - Add per-category title rules (envy: short+identity, anxiety: short+pain, conflict: short+controversy, comedy: suspense+no-spoiler) - Replace dropdown tags in Studio header with plain static tags - Envy cover image must be visually stunning/breathtaking (not candid) - Add Harvard showcase work to Explore page under envy category - Chat history fallback for showcase copytext extraction - Fix ContentCategory type to include anxiety/conflict/envy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…motion labels - Complete i18n: replace all hardcoded Chinese with tt() calls across 14 files (~150 new keys) - Language-aware agent: store language on Work model, switch all prompts to English when lang=en - Voice narration for short-video: edge-tts integration with auto voice selection (zh/en) - Agent announces voice choice before generating narration - Neutral emotion labels: replace 焦虑→共鸣, 愤怒→争议感 in all user-facing text - Explore showcase: image carousel with EN/ZH versions, chat fallback copytext - Install voice skill (edge-tts based TTS) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…plore page - Inspiration page: fix empty state copy, remove English override for showcase entry - Rename 素材库 → 我的素材, move from Works page into settings drawer - Restyle AssetLibrary to match product design system (blockquote guide, pill tabs) - Remove research config and save button from settings drawer - Remove grid/list view toggle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename settings to "你的画像", topbar shows icon + text horizontally - Remove AssetLibrary dropdown, show content directly in sidebar - Merge theme/language switches into one right-aligned row - Upload button → full-width dashed drop zone - Inspiration empty state → 暂无优秀作品展示 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…load API Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e page redesign - Fix Link Portrait tooltip z-index overlap with tabs - Output tab now shows phone-frame preview (Douyin style for video, XHS style for image-text) - Remove topicHint fallback in output tab — only show final copytext results - Explore page: add video playback support with Douyin-style fullscreen player - Explore page: portrait card layout (3/4 ratio), video cards fill with title overlay - Explore page: equal-height grid, author row pinned to bottom - Add "5:47. No one's up yet." as first showcase entry in 向往拥有 tab - Add AI watermark removal step (4.5) in content-assembly skill - Add talking-head/口播 default style in content-planning skill - Fix Dreamina default model from seedance2.0fast to seedance2.0 - Pass modelVersion through /api/generate/video endpoint - Cover image priority: output/cover.* > final video > output images - Remove dist/ from git tracking (already in .gitignore) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Jimeng lip-sync API (realman_change_lips) for video lip-syncing - Rewrite talking-head style: one-shot phone-selfie feel, coach presence - Smart pipeline skip: auto-detect user-provided assets/direction and skip unnecessary steps (research, plan, assets) for both video and image-text content types - Auto-detect person gender from video before selecting TTS voice - Add Quality Review info tooltip with i18n - Remove watermark removal step - Remove node_modules from version control Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
May 11, 2026
… Bug #3) Symptom (2026-05-09): 导出走完所有阶段(render → duck → loudnorm → burn → encode) 但进度条始终是 0%;走完后 modal 1.5s 自动消失,没有任何产物入口。 Root cause #1 — progress reset between stages: worker.ts:160 把 onProgress 的 pct 直接写进 store。每个 stage 在 render-pipeline.ts 内只 emit 两次:onP(stage, 0) 进入 + onP(stage, 1) 完成。下一 stage 进入时又 onP(next, 0) 把 progress 拉回 0。前端看 到 stage 切换但 progress 反复 0→1→0→1,UI 显示全程 0%。 Root cause #2 — outputPath 不在 done event 里: worker.ts:208 done event 只包含 {status, progress}。outputPath 仅 存到 store,前端只能在 reconnect 时通过 snapshot 拿到。如果 modal 在 run 期间已开,永远收不到 path。 Root cause #3 — done state UI 1.5s 后消失: ExportProgress.tsx:41 done 后 setTimeout(onClose, 1500),用户看到 "Export complete" 闪一下 modal 关掉,再也找不到产物。 Fix: • worker.ts: aggregateProgress(stage, pct) — 5 stage × 0.2 slice, 每个 stage 内的 pct 线性映射到自己的 slice。新增导出供以后扩展 (ffmpeg -progress 解析)使用。 • worker.ts: done event 带 outputPath。WorkerProgressEvent 加可选 outputPath 字段。 • render-ws.ts: snapshot 帧也带 outputPath + error,确保 reconnect 到 terminal job 时 UI 能恢复完整状态。 • ExportProgress: 移除 done auto-close。done 状态新增"open output" affordance(path 缩略 + 跳转到 /api/works/<id>/assets/output/...)。 Cancel 按钮在 terminal 状态变为 Close 同槽位(用户始终有出口)。 • TopBar: 把 workId 传给 ExportProgress 用于拼 URL。 • i18n: 新增 btnClose / btnOpen(en + zh)。 Tests: • worker.test.ts: AC1 progress=0.5 改为 0.1(render is stage 0 of 5)。 • ExportProgress.test.tsx 改两个测试匹配新契约: - "auto-closes after 1500ms" → "stays open with Close + open link" - "Cancel disabled in terminal" → "Cancel slot becomes Close" • 全量 server (15/15) + render-status (5/5) 通过。 • 5 个预存失败的 integration test (No QueryClient / Remotion mount) 跟此 commit 无关 — git stash 验证过。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
May 11, 2026
…opt #3) This is the LOAD-BEARING PRIMITIVE for the parallel streaming-encode path. The full Stage 1 replacement (Puppeteer worker pool → ffmpeg image2pipe) is a 2-3 week sprint; this commit ships the ~10% that unblocks the remaining 90%. ## What's shipped ### `src/server/render/frame-reorder-buffer.ts` (~150 LOC, full impl) The synchronization primitive that lets parallel workers render frames out-of-order yet write to ffmpeg stdin in-order: - `waitForFrame(n)` — async barrier; resolves when n === nextFrame - `advanceTo(n+1)` — release the next waiter - Idempotent advance, range-clamped, graceful dispose - Double-write detection (rejects waitForFrame for past frames) Ported nearly verbatim from heygen-com/hyperframes packages/engine/src/services/streamingEncoder.ts:51-95. 10 dedicated unit tests including the canonical 3-worker / 6-frame out-of-order completion test. ### `src/server/render/streaming-encoder.ts` (~180 LOC) Sequential streaming encoder that's already correct + production-ready: - Spawns ffmpeg with `-f image2pipe -vcodec mjpeg -i -` - Walks frames 0..N, awaits buffer.waitForFrame, writes JPEG to stdin - Honours backpressure via stdin.once("drain") - Wires AbortSignal → ffmpeg SIGTERM - Uses GPU encoder (R46 #1) for output codec choice The producer interface (`StreamingEncodeProducer.produceFrame(n)`) is the contract the future parallel implementation conforms to. ## What's NOT shipped (TODOs documented inline) The skeleton's bottom comment block details four follow-up files needed to fully replace Stage 1's Remotion render path: 3.a — headless-chrome.ts (Puppeteer pool, mirror browserManager.ts) 3.b — parallel-coordinator.ts (worker count + range partitioning) 3.c — composition-to-html.ts (replace @remotion/bundler for our AbsoluteFill/Sequence/Video/Audio/Img subset) 3.d — feature flag wiring in render-pipeline.ts Each TODO references the hyperframes file it should mirror + LOC estimate. Total remaining work ~2-3 engineer-weeks. Honest scope: this commit is the foundation, not the finished house. ## Why ship the primitive separately - Zero coupling to Chromium / Remotion / ffmpeg → trivially testable - Future incremental adopters benefit (e.g. parallel speed-ramp pre-pass on input clips also wants reorder coordination) - Reading the two files together gives a coherent architectural narrative even before the parallel coordinator exists ## Tests - 10/10 frame-reorder-buffer (waiter ordering, dispose, range checks, idempotent advance, parallel-worker simulation) - 69/69 render-area tests pass overall Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
May 11, 2026
Cinematic transition between two video clips using ffmpeg's xfade filter
combined with a procedurally generated "light leak" overlay sweep. Looks
like vintage film burn / lens flare; very common in viral editorial cuts.
## Why ffmpeg-only and not WebGL shaders
hyperframes' shader-transitions package ships ~6 transitions as GLSL
shaders rendered in their custom WebGL renderer. To port any of them
we'd either:
(a) Embed the shader as a Remotion canvas component — needs the
streaming-render path (R46 opt #3) for performance
(b) Express it as an ffmpeg filter graph — limited to what xfade /
geq / overlay can do without proper texture sampling
Light-leak is the easy first one because the visual effect (bright
streak sweeping during a cross-fade) decomposes into:
- xfade transition=fade between the two clips
- format=rgba overlay of a static gradient PNG
- overlay's x position animated via if(between(t, ...)) expression
- acrossfade for audio
No WebGL needed. Pure ffmpeg, runs in our existing pipeline.
## What's shipped
`src/server/render/transitions.ts` (~210 LOC):
- `applyLightLeakTransition(opts)` — full ffmpeg invocation
- `ensureLightLeakOverlay(width, height)` — caches overlay PNG
generated via lavfi `gradient` + pad+format=rgba. No binary asset
shipped; lazy-built on first use.
- `buildLightLeakFilterGraph(opts)` — pure-function filter graph
builder, exposed for unit testing without spawning ffmpeg.
`src/server/render/transitions.test.ts`:
- 6 tests on the filter-graph builder: xfade offset math,
enable= gate timing, audio crossfade duration, fps in overlay,
single-line graph (ffmpeg requirement), output stream labels.
## Roadmap for additional transitions
Documented inline as TODOs at end of transitions.ts. Three more worth
porting:
5.a — Glitch cut (ffmpeg geq feasible, ~1 day)
5.b — Domain warp (ffmpeg geq feasible, ~2 days)
5.c — Gravitational lens (needs Remotion canvas, blocked on R46 #3)
## Tests
- 6/6 transitions tests pass
- 75/75 tests across all R46 changes (gpu-encoder, frame-reorder-
buffer, aggregate-progress, transitions, render-pipeline,
render-queue, render-ws, store) — full pipeline still healthy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
May 11, 2026
…act (R46 #5 wire-in) Closes the "POC primitive shipped, no API path" gap from R46 #5 commit (12897ac). transitions.ts had the working filter graph + caching; now agent can invoke it via REST and the system prompt documents when to reach for it. ## Endpoint POST /api/transitions/light-leak Body: workId, clipARelative, clipBRelative, outputFilename, clipADuration: number (seconds), transitionDuration: number (seconds, default 0.8) Response: { ok: true, outputPath, previewUrl } or { errorCode, error } on failure (4-layer path-traversal defence) ffprobe-based dimension detection: probes clipA for width/height/fps so the overlay PNG cache picks the right size without the caller having to specify. Falls back to 1080×1920×30 if ffprobe fails (then ffmpeg will emit its own clear error). ## ffmpeg 8.x compat fix ensureLightLeakOverlay() previously used the `gradient` source filter, which doesn't exist in ffmpeg 8.x (was added later, then removed in favour of `gradients` plural — confusing). Replaced with `color@0` source + `geq` per-pixel expression for the streak shape: alpha(X,Y) = if X∈[0.35W, 0.65W]: 180 * (1 - (2*(X/W - 0.5) / 0.3)^2) (smooth quadratic bump centered at W/2) else: 0 End-to-end verified: 12kB streak overlay PNG generated, 5.3MB mp4 transition output produced from two real clips. ## System prompt (ws-bridge.ts) Assembly module description gains a "**过场转场**" line teaching the agent: - When to use light-leak (editorial / 文艺 / 蒙太奇) - When NOT to use it (快剪情节驱动 / 口播单镜 → use direct cut or fade) - Default 0.8s transitionDuration (viral pacing); 1.2-1.5s for editorial slow-feel - Hard "不要手写 ffmpeg drawtext / xfade filter" — must go through the endpoint (preserves the cached overlay + path-traversal defence + error consistency) ## Tests - 269/269 server tests pass (no regression — 48 files including transitions, render-pipeline, render-queue, providers, etc.) - Direct e2e: curl POST → 200 ok response, mp4 file on disk with correct dimensions + duration - No new unit test for the endpoint itself; transitions.test.ts already covers the filter graph builder, the endpoint is mostly plumbing + ffprobe + path-resolve which the existing safe-paths tests cover ## Roadmap (still open) Three more transitions worth porting (R46 #5 file's TODOs): 5.a glitch cut (~1 day, ffmpeg geq feasible) 5.b domain warp (~2 days, ffmpeg geq feasible) 5.c grav lens (blocked on streaming render path R46 #3) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
May 11, 2026
Wires @remotion/renderer's renderFrames into streamingEncode + FrameReorderBuffer primitive shipped earlier in R46 #3. Stage 1 now opt-routes via AUTOVIRAL_USE_STREAMING_RENDERER=1 env var (or composition.experimentalFlags.streamingRenderer). On failure falls back to renderCompositionToMp4 so flag-on users aren't blocked. streaming-encoder.ts gains inputCodec option (mjpeg | png) so the bridge can stream Remotion's PNG frames directly without a JPEG re-encode pass. #3.c (custom React→HTML serializer) intentionally skipped — re-implementing ~2k LOC of Remotion compatibility surface duplicates @remotion/bundler with no perf payoff. Streaming-encode wins come from parallel Chromium screenshots + ffmpeg pipe, not from owning the bundler. Keep @remotion/bundler, replace only the renderer half. Tests: 33/33 pass across remotion-bridge / frame-reorder-buffer / render-pipeline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
nanxingw
added a commit
that referenced
this pull request
Jun 3, 2026
… direct dialog dispatch Next-phase plan item #3 — "人声TTS功能完整的测试" + EN support + keep both providers. The feature was dead end-to-end despite all code existing: no edge-tts binary, no API key, and the dialog routed TTS to a DELETED modules/assets/scripts/tts_generate.py via a chat message. Rebuilt as a deterministic, work-integrated, dual-provider path. Backend (src/tts-providers/, src/server/api.ts): - New openaiTtsProvider conforming to TtsProvider (writes outputPath, ffprobe best-effort, fetch/env injection seam). mapVoiceToOpenAi() translates edge voice ids (zh-CN-Xiaoxiao/Aria→nova, Yunjian/Guy→onyx) since OpenAI rejects edge ids — the #1 fallback bug, guarded by tests. - edgeTtsProvider.resolveEdgeTtsBin(): EDGE_TTS_PATH → auto-discovered venv at <dataDir>/tts-venv/bin/edge-tts → bare "edge-tts". + isAvailable() probes. - registry.generateWithFallback(): auto = edge first, OpenAI fallback, aggregated error naming both on total failure; edge-tts/openai single modes skip fallback. - POST /api/works/:id/tts: SAFE_ID-guarded (write-side path-traversal fix), synthesizes into assets/audio/, broadcasts asset-added, returns {ok,relativeUri,providerId,durationSec,voice}; 500 tts_provider_error on fail. Frontend (GenerationDialog.tsx, messages.ts): - TTS Generate now POSTs /api/works/:id/tts DIRECTLY (mirrors video provider dispatch) instead of the dead chat-notification path; invalidates ["assets",id] + closes on success, keeps open + localized error on failure. - 4 voices for zh+en parity (added en-US-Guy); 服务/provider select (auto/edge/openai); localized progress + error i18n (EN+ZH). Verified: web 1002/1002, server 598/600 (2 ffmpeg-env, non-regression incl. real edge-tts smoke). Browser E2E through the live daemon (pure venv auto-discovery, no env override): generated zh (8.11s) + en (6.60s) narration via the real UI → both appear as library audio tiles → decodable mp3. OpenAI fallback unit-tested (no key on this machine to E2E). Test work restored, no artifacts left. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jun 4, 2026
The HITL gates of PRD-0002. A grill-with-docs session pressure-tested the PRD's recommended ContentTypeManifest + MediaProvider shapes against the ACTUAL code and surfaced three facts the PRD missed: 1. CarouselSchema + makeEmptyCarousel are web-only (web/.../editor/types.ts); composition's schema is shared. I08 (carousel CLI→bridge→server zod) and I10 (carousel migrations) are IMPOSSIBLE as specified until the carousel schema reaches the server. → ADR-006 promotes it to src/shared/carousel.ts as I06's first step. This is the real keystone of v0.1.1. 2. providers are FOUR mechanisms not three (image / video / tts-registry / tts-direct synth), and TTS has a double path. → ADR-007 scopes a 4→1 consolidation + internal TTS merge. 3. runway/sora/kling are produce-nothing stubs that violate invariant #2 (direct vendor calls). → ADR-007 drops them; video is OpenRouter-only (seedance). Also collapses checkpointTargets→deliverableFile, single capability tag over boolean flags, seedFactory as pure factory (no create-time seeding behavior change). CONTEXT.md: add `content type` + `carousel.yaml` glossary terms (carousel was absent); make `work` content-type-aware (was video-centric); update invariants #2 (single capability-tagged registry) + #3 (both deliverables are SSoT) with ADR refs. Decisions: nanxingw confirmed carousel→shared (Q1) + drop-stubs (Q8). ADRs to be added to docs/adr/README.md index by I04. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jun 4, 2026
Give "upgrade without data loss" a backbone (PRD-0002 W7.5 / deep module ③).
- Add optional `schemaVersion` to CompositionSchema + CarouselSchema. Modeled
as `.optional()` (floor 1 via readSchemaVersion), NOT zod `.default(1)`, so the
`z.infer` output type stays `number | undefined` and existing Composition /
Carousel literals (fixtures, synthesisers) don't have to stamp a redundant
field — zero collateral edits. Fresh works DO write `schemaVersion` explicitly
via makeEmptyComposition / makeEmptyCarousel (grep-confirmable).
- New src/shared/migrations/ registry skeleton:
- registry.ts — `migrate(kind, doc)` reads schemaVersion, chains registered
from→to migrations to the latest, stamping the version forward. Pure; never
writes disk (callers run migrate then hand the result to the existing
CompositionSchema.parse + atomic write — invariant #3 unbroken).
- members.ts — collects the two existing migrations as named members:
`migrateLegacyTrackIds` (composition read-time normalizer, #57 behaviour
referenced verbatim, NOT re-implemented) and the repo-root `strip-pipeline`
batch script (lazy dynamic import — kept outside the `src/`→`dist/` rootDir
program so the publish build stays green; its CLI path + tests untouched).
- index.ts — public barrel.
Range discipline (PRD-0002 N6): skeleton + collect only. No boot-time runner.
#57's behaviour is byte-for-byte unchanged — it gets a hook, not a fix. Zero
version-bumping chain migrations ship in v0.1.1; the schemaVersion floor stays 1.
Isolation tests (src/shared/migrations/__tests__): optional-field default floor,
migrate() multi-step chaining + ascending order + duplicate/non-+1 guards, the
legacy-track-ids member is the SAME fn (same in/out), strip-pipeline member runs
verbatim, and a migrated legacy composition round-trips through the atomic
write/read path carrying schemaVersion. Existing migration tests stay green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jun 5, 2026
…D-0003 §3.2) New DELETE /api/works/:id/assets/* (SAFE_ID workId + traversal-rejecting path guard, mirrors the shared-assets contract; unlinks the file + sibling .peaks.json). Library tiles + the preview modal get a trash control behind a two-step confirm. Referenced-asset policy = WARN-then-CASCADE: the dialog warns how many timeline clips use the asset; confirming removes those clips + provenance entry so the timeline never silently breaks (invariant #3). findClipsReferencingAsset canonicalises every clip.src / asset flavour (work-relative, single-prefix served URL, and the double-prefixed asset url) to one work-relative key so a served-URL clip matches (browser+disk E2E verified: tile gone, file unlinked). messages.ts also carries I24's session strings. EN+ZH incl aria-labels. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jun 5, 2026
…NewWorkCard polish Timeline (#3): clip BODY now owns cross-track moves (CapCut/剪映/Premiere style). New pure resolveDragTargetTrack core (zero React/DOM, unit-tested) decides the same-kind destination lane; commitDrag applies moveClipToTrack while preserving trackOffset. Re-runs the #88 kind guard inline against stale targets, and prunes orphaned source-track transitions (#54) so the next Composition.parse() superRefine can't reject the save round-trip. Sessions: any conversation is deletable now (incl. the default s_1) as long as one remains — swapped the "refuse-default" guard for a "refuse-last" guard in works route, ws-bridge deleteSession (now always removes the chat log + the s_1 legacy chat.json snapshot), and SessionStrip (× hidden when <=1 session; active-delete falls back to first-remaining, not always s_1). NewWorkCard: layout/CSS refresh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jun 5, 2026
…); cover error-code rules #3/#4; fix /ask comment Wave-1 review (S3, 1 MEDIUM + 2 LOW): - MEDIUM (gate): the "4-vs-3 covered by integration test" claim ran only via a separate `cd cli/autoviral && npm run test` with NO prebuild — so it silently did NOT run in `npm test` and could run stale gitignored dist against new source. Add `pretest: npm run build` to cli/autoviral (always fresh dist) + root `test:cli` script and append it to the root `test` chain. The coverage is now actually enforced and never stale. - LOW (untested branches): every prior CLI fixture returned JSON, so client.ts's defensive JSON.parse(catch) (rule #3) and the 200+{ok:false} envelope (rule #4) were exercised by inspection only. Add 3 fixtures+tests: 400 with a non-JSON (HTML) body → status-class fallback exit 4 (no crash); 200 {ok:false, code:4} → honours code exit 4; 200 {ok:false} no code → defaults exit 3. All green. - LOW (comment): bridgeRequest claimed "/ask returns 504 via this path with code:124" — false; /ask has its own fetch+exit in commands/ask.ts and never reaches bridgeRequest. Reworded to the true behaviour (this path honours any explicit numeric code incl. 124; /ask handles its own 124). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jun 5, 2026
S10 POST /clip (src/server/bridge/routes.ts): - `--duration` is a RELATIVE clip length, not an absolute `out`. The old `out = body.out ?? (body.duration ?? 5)` mis-read `--in 2 --duration 3` as out=3 (a 1s clip) instead of out=5 (a 3s clip). Now `out = in + duration` when no explicit `--out`; explicit `--out` still wins. Applied to the video + audio source-window branches (text/overlay already treat `duration` as relative). - Unknown `--track` kinds are now rejected UP FRONT with 400 + code:4 instead of relying on the kind dispatch's `else` (which treated overlay as a catch-all). The `else` branch is reached only for a real "overlay". S9 transitions: - clampHandleDuration now caps at the schema ceiling (5s), not just the handle + 0.05 floor, so two very long adjacent clips can't produce a dur > 5 that writeCompositionFor's zod parse would reject. Added TRANSITION_DURATION_MIN/MAX_SEC mirroring TransitionSchema. - studio store add/removeTransition now SURFACE the op's CompositionOpError as a localized warn toast (same pattern as splitClip) instead of silently swallowing it, so the CLI (code:4) and UI error paths no longer diverge. New i18n key studio.toast.transitionFailed (EN + ZH). Overlay consumption (finding #3) confirmed NOT a dead field: RemotionRoot renders the SAME <Scene> the preview uses → OverlayTrackRenderer emits an <Img> for the bridge-shaped overlay clip. Added a render-consumption assertion test to guard against future regression. Tests: +5 routes (in/out semantics x4, unknown-track-rejects), +1 clamp ceiling, +4 transition-toast, +2 overlay-consumption. web 1154 / server 909 / cli 101 green; web+server tsc clean of new errors (2 pre-existing routes.test/checkpoints Hono .then() typing errors unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jul 13, 2026
对抗 review 6 findings 全部指向未提交的 HEAD 前态;working tree 已含完整 S4b 实现,本 commit 将其落盘固化,令交付可复现(对齐 finding #6 交付未提交诉求): - ws-bridge.ts:无 isWorkBound / homedir·yaml / trends_ 残留(finding #1,backend tsc 退出 0) - routes/system.ts + infra/config.ts:GET 不回显 research/analytics/interests/douyin*, PUT 旧 flat 字段静默忽略返 200,无效旧 cron 不再 400(finding #2/#4) - 删 trends/analytics/coach routers + scheduler + src/trends + 各 domain + collector + context/trends + CLI trendsCommand,拆出 commands/profile.ts(finding #3/#6) - 依赖移除 node-cron / @types/node-cron / fast-xml-parser - 预设测试:removed-product-routes.test.ts 矩阵 404 + 保留路由回归(finding #5), config(.redaction).test.ts 改锁 S4 新契约,doctor-setup 退休 --heavy/trends scrape Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jul 15, 2026
reviewer findings 逐条处理(先证红再转绿): #1 [high] detach→重开原声双份出声:AudioClip 加 detachedFrom 稳定回链; 新增共享 op attachAudio(re-enable + 原子删除拆出 clip);store reattachClipAudio + Inspector 开关重开时走反向 op;sweep gate 收编。 #3 [high] 变速视频 detach 音画失步:detachAudio 对含非 1 speed keyframe 的 clip 直接拒绝(CompositionOpError code:4),不静默产出失步音轨。 #4 [medium] speed-ramp 缓存键漏 sourceAudio.enabled:静态/变速两个 cache name 都折入 enabled(默认 true 保持旧名,disabled 加 -na 后缀),读在 stat 之前;assets PIPELINE_INTERNAL 正则同步放行 -na 变体。 #2 [high] ducking 丢 in/out:MixTrack 携带 in/out,compositionToMixTracks 透传,mixAudioTracks 先 atrim=start:end + asetpts;拆出/裁剪 clip 不再从 源 0s 播。(enabled 视频源声在 duck 阶段被丢=既有 ducking 设计缺口, 非 S5 引入,另案,见 notes) #5 [medium] 同构测试:新增 sourceAudioCache 测试驱动真实 applySpeedRampPrePass 路径(预置双缓存断言 enabled/disabled 落不同文件);renderer 补 isRendering:true 导出分支(OffthreadVideo muted/volume)。 #6 [medium] CLI 假服务端:新增真实 Hono bridge 路由测试,回读持久化 composition 断言 AudioClip(type original + detachedFrom)、源声关闭、广播。 红:9 op/cache 测试对旧源码先红;转绿:server 1688 / web 1826 全过, backend+web tsc exit 0。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jul 15, 2026
…辑失败 toast + letterbox/mask-image 契约校准 - 修复 (finding #4): setClipMask op 的 rect 边界从 `1 + 1e-9` 放宽收紧为严格 `x+w<=1 / y+h<=1`,与持久化 MaskRectSchema 完全同步。此前亚 1e-9 的 sliver 能过 op 却在 CompositionWriteSchema.parse 写盘时抛 ZodError → 泄漏 HTTP 500; 现在 op 同步拒绝 → 400/code:4。补 op 层 + bridge 路由边界测试(先证红:op 未抛 / 路由 500,转绿)。 - 修复 (finding #5): store.setClipMask 遇 CompositionOpError 不再静默吞掉,改为 与相邻 transition 家族一致弹 warn toast(新增 studio.toast.maskFailed i18n 键 en/zh)。新增 store.mask.test.ts(先证红:无 toast,转绿)。 - 校准 (finding #1): letterbox-2.35 preset 展开为「非 inverted 居中 rect band」 是正确 letterbox(keep-inside 默认下 inverted 反而保留黑边、遮内容)。原 PRD 「rect+inverted」措辞有误,已修订 S13 文档;op/bridge/Inspector 三层测试补精确 展开断言(inverted 缺席 + key 集)杜绝漂移。 - 校准 (finding #2): 渲染用 CSS mask-image(alpha mask)而非 clip-path —— feather 必须走 alpha 软边(feGaussianBlur),clip-path 无法羽化。修订 S13 文档并对渲染树 加 DOM 断言(mask-image data-URI 含 SVG / feGaussianBlur / evenodd)。 - 反驳 (finding #3): S13 契约文本即为「mask 渲染组件在 renderMedia 单帧下不抛 (为 S16 铺路)」,现测试翻 isRendering=true 走导出分支断言不抛,正合契约;真 headless renderMedia 属 S16/E2E 纬度,暗亮主题 + 预览/导出肉眼一致为显式手验项, 非 vitest 可自动化。 Web 242 文件/1859 测试、Server 173/1826(+1skip)、CLI 5/291 全绿;typecheck:web + backend tsc 均 clean。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jul 15, 2026
review findings 逐条处理(7 修复 + 1 部分反驳 + 1 反驳): - #1 [high] overlay blendMode 未消费 → OverlayTrackRenderer 给 <Img> 设 mix-blend-mode(blendModeToCss);补 OverlayTrackRenderer.blend 测试。 - #2 [high] filters/effects 双写冲突 → Inspector 三旋钮改写 effects grade entry(find-or-create + updateEffectParams,不再写 clip.filters); projectLegacyFilters 在 both-present 时把非中性 filters 折进 LEADING grade 并清零 filters(无损、幂等);更新迁移测试锁新行为。 - #3 [high] effects 非有序栈 → 新增 effectStackSteps + wrapWithEffectStack, 按数组顺序生成逐层嵌套包装(grade/blur=filter 包裹,vignette/grain=overlay 包裹),跨类型 reorder 改变真实嵌套;补 DOM 行为测试。 - #4 [high] adjustment 只消费 backdrop-filter → 同时消费 vignette/grain 覆盖层, 空 filter 但有 overlay 时不再 return null;补消费测试。 - #5 [high] POST /clip adjustment 写成 OverlayClip → 新增专用 AdjustmentClip 构造分支(trackOffset+duration+空 effects,无 src/position);补路由测试。 - #6 [high] adjustment z 序按数组非 displayOrder → Scene 渲染前按 displayOrder 排序轨道;补上下移作用范围测试。 - #7 [medium] effects 列表无排序交互 → 增加上/下移按钮,统一调用 reorderClipEffect;补交互测试 + i18n。 - #8 [medium] LUT 死字段 → 反驳:LUT 从无消费者(旧 toCssFilter 也只读 b/c/s),非 S14 回归;S14 迁移反而无损保留 lut 数据。真 LUT 渲染是独立新 功能,超出 S14 平价范围。 - #9 [medium] remove/reorder/toggle/update/blend 静默吞错 → 统一 warnEffectFailed warn toast(对齐 addClipEffect);补 store.effects toast 测试。 验证:test:web 246 files/1893 绿;test:server 175 files/1853 绿; build:backend tsc 绿。web tsc 15 error 为 S14 adjustment-kind 既存 UI 债 (describeElement/Timeline/DiveCanvas,未改动文件),改动前后计数不变。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jul 15, 2026
一致性 gate 在 frame 30(0.5s 定格点之后)抓到真实预览≠导出裂缝:headless
Remotion still(A 路 == `autoviral snapshot`)在定格点之后渲成纯黑
(preview-luma=0),而导出(B 路,ffmpeg trim+tpad 烘焙的定格 MP4)正确 hold
住定格帧(export-luma=125)。根因不是 off-by-N,而是定格用 1 帧 startFrom/endAt
trim 窗口实现——<OffthreadVideo> 在 <Sequence> 里过了 endAt 就解不出帧→黑。
修复:定格时把 body 包进 Remotion `<Freeze frame={0}>`,把后代的 local frame
钉在 0,让 <Video>/<OffthreadVideo> 在每一个合成帧都渲染它那一帧 trim 帧
(源帧 freezeStart)——整条 clip 都 hold,和导出的 trim+tpad 烘焙对齐。导出侧
prepass 已 STRIP freezeAtSec,故此改动只影响预览/still/snapshot,不动导出。
gate 证据:改前 frame30 meanΔ=123.55/changed=100%(黑),改后 meanΔ=0.33/
changed=0%(时变 clock 源,见 S16 review 测试修复 commit)。web 单测更新为断言
定格帧被 <Freeze> hold 包裹(data-test=clip-freeze),trim 窗口仍选帧 45/46。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nanxingw
added a commit
that referenced
this pull request
Jul 15, 2026
逐条处置独立 reviewer 的 6 条 finding(#1 CI 单独 commit): #2 speed fixture 无牙:flat baseSrc 下导出回退 1× 也全绿。改用时变 clock 源 (每帧一个 distinct flat 色,见下),并加 Layer-2 ffmpeg 自检"注入旧 1× 回退 → 判红"(源 t=15 ≠ 2× 预览 t=30)。 #3 去除"改比较点保绿":freeze fixture 从 frame 0(定格点,掩盖裂缝)改回 honest frame 30,配时变 clock 源。配合 <Freeze> 产品修复后真正转绿 (meanΔ=0.33/changed=0%),不再掩盖发现。 #4 reverse fixture 纯色倒放不变、prepass 不跑也绿:reverse 是 export-only (预览正播 + 仅导出生效徽标),A==B 本就不成立。新增 Layer-2 自检用真 timeWarpVideoFilterChain 在 clock 源上验证 reversed[k]==source[last-k] 且 !=source[k](证明真倒放取帧)。FULL ⑦ 改为诚实契约:排除徽标区后正片 一致(meanΔ=0.00),且徽标区确实发散(hard=4.33%,证明徽标真是 preview-only)。 #5 补 adjustment 轨 fixture ⑧(ordered grade→vignette 调整窗)+ 把 effects ⑤ 从单 grade 升为两效果有序栈 grade(亮度+)→vignette。(顺序反转输出不同已在 VideoTrackRenderer.effects.test.tsx DOM 单测覆盖。) #6 双阈值盲区:5% 像素 × Δ60 时 meanΔ≈3≤4、changed≈5%≤6% 两闸皆过却是可见 局部损坏。加第三闸 hardPct(|Δ|>48 的像素占比 ≤1%)关闭盲区;配 Layer-1 自检(5%×Δ60→红 / sub-1% sliver→仍绿)。新增 ignoreRect 精确排除 reverse 徽标(非放宽容差——另断言徽标区确实发散)。 clock 源:flat 每帧 distinct 色(geq r/g/b 仿射于 N),既有牙(错帧=大 meanΔ) 又无 testsrc2 硬边的 chroma-subsampling 噪声(否则误触 changedPct 次闸)。 验证:RUN_CONSISTENCY_GATE=1 全 19 pass(8 FULL fixtures meanΔ 0.0–2.33/ changed 0%/hard 0%);非门控 test:server 1953 pass|10 skip 无回归。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.