@leejungkiin/awkit 1.3.8 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/bin/awk.js +630 -52
  2. package/bin/claude-generators.js +122 -0
  3. package/core/AGENTS.md +54 -0
  4. package/core/CLAUDE.md +155 -0
  5. package/core/GEMINI.md +44 -9
  6. package/core/GEMINI.md.bak +126 -199
  7. package/package.json +1 -1
  8. package/skills/ai-sprite-maker/SKILL.md +81 -0
  9. package/skills/ai-sprite-maker/scripts/animate_sprite.py +102 -0
  10. package/skills/ai-sprite-maker/scripts/process_sprites.py +140 -0
  11. package/skills/awf-session-restore/SKILL.md +12 -2
  12. package/skills/brainstorm-agent/SKILL.md +11 -8
  13. package/skills/code-review/SKILL.md +21 -33
  14. package/skills/gitnexus/gitnexus-cli/SKILL.md +82 -0
  15. package/skills/gitnexus/gitnexus-debugging/SKILL.md +89 -0
  16. package/skills/gitnexus/gitnexus-exploring/SKILL.md +78 -0
  17. package/skills/gitnexus/gitnexus-guide/SKILL.md +64 -0
  18. package/skills/gitnexus/gitnexus-impact-analysis/SKILL.md +97 -0
  19. package/skills/gitnexus/gitnexus-refactoring/SKILL.md +121 -0
  20. package/skills/lucylab-tts/SKILL.md +64 -0
  21. package/skills/lucylab-tts/resources/voices_library.json +908 -0
  22. package/skills/lucylab-tts/scripts/.env +1 -0
  23. package/skills/lucylab-tts/scripts/lucylab_tts.py +506 -0
  24. package/skills/nm-memory-sync/SKILL.md +14 -1
  25. package/skills/orchestrator/SKILL.md +5 -38
  26. package/skills/ship-to-code/SKILL.md +115 -0
  27. package/skills/short-maker/SKILL.md +150 -0
  28. package/skills/short-maker/_backup/storyboard.html +106 -0
  29. package/skills/short-maker/_backup/video_mixer.py +296 -0
  30. package/skills/short-maker/outputs/fitbite-promo/background.jpg +0 -0
  31. package/skills/short-maker/outputs/fitbite-promo/final/promo-final.mp4 +0 -0
  32. package/skills/short-maker/outputs/fitbite-promo/script.md +19 -0
  33. package/skills/short-maker/outputs/fitbite-promo/segments/scene-01.mp4 +0 -0
  34. package/skills/short-maker/outputs/fitbite-promo/segments/scene-02.mp4 +0 -0
  35. package/skills/short-maker/outputs/fitbite-promo/segments/scene-03.mp4 +0 -0
  36. package/skills/short-maker/outputs/fitbite-promo/segments/scene-04.mp4 +0 -0
  37. package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-01.png +0 -0
  38. package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-02.png +0 -0
  39. package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-03.png +0 -0
  40. package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-04.png +0 -0
  41. package/skills/short-maker/outputs/fitbite-promo/storyboard.html +133 -0
  42. package/skills/short-maker/outputs/fitbite-promo/storyboard.json +38 -0
  43. package/skills/short-maker/outputs/fitbite-promo/temp/merged_chroma.mp4 +0 -0
  44. package/skills/short-maker/outputs/fitbite-promo/temp/merged_crossfaded.mp4 +0 -0
  45. package/skills/short-maker/outputs/fitbite-promo/temp/ready_00.mp4 +0 -0
  46. package/skills/short-maker/outputs/fitbite-promo/temp/ready_01.mp4 +0 -0
  47. package/skills/short-maker/outputs/fitbite-promo/temp/ready_02.mp4 +0 -0
  48. package/skills/short-maker/outputs/fitbite-promo/temp/ready_03.mp4 +0 -0
  49. package/skills/short-maker/outputs/fitbite-promo/tts/manifest.json +31 -0
  50. package/skills/short-maker/outputs/fitbite-promo/tts/scene-01.wav +0 -0
  51. package/skills/short-maker/outputs/fitbite-promo/tts/scene-02.wav +0 -0
  52. package/skills/short-maker/outputs/fitbite-promo/tts/scene-03.wav +0 -0
  53. package/skills/short-maker/outputs/fitbite-promo/tts/scene-04.wav +0 -0
  54. package/skills/short-maker/outputs/fitbite-promo/tts_script.txt +11 -0
  55. package/skills/short-maker/scripts/google-flow-cli/.project-identity +41 -0
  56. package/skills/short-maker/scripts/google-flow-cli/.trae/rules/project_rules.md +52 -0
  57. package/skills/short-maker/scripts/google-flow-cli/CODEBASE.md +67 -0
  58. package/skills/short-maker/scripts/google-flow-cli/GoogleFlowCli.code-workspace +29 -0
  59. package/skills/short-maker/scripts/google-flow-cli/README.md +168 -0
  60. package/skills/short-maker/scripts/google-flow-cli/docs/specs/PROJECT.md +12 -0
  61. package/skills/short-maker/scripts/google-flow-cli/docs/specs/REQUIREMENTS.md +22 -0
  62. package/skills/short-maker/scripts/google-flow-cli/docs/specs/ROADMAP.md +16 -0
  63. package/skills/short-maker/scripts/google-flow-cli/docs/specs/TECH-SPEC.md +13 -0
  64. package/skills/short-maker/scripts/google-flow-cli/gflow/__init__.py +3 -0
  65. package/skills/short-maker/scripts/google-flow-cli/gflow/api/__init__.py +19 -0
  66. package/skills/short-maker/scripts/google-flow-cli/gflow/api/client.py +1921 -0
  67. package/skills/short-maker/scripts/google-flow-cli/gflow/api/models.py +64 -0
  68. package/skills/short-maker/scripts/google-flow-cli/gflow/api/rpc_ids.py +98 -0
  69. package/skills/short-maker/scripts/google-flow-cli/gflow/auth/__init__.py +15 -0
  70. package/skills/short-maker/scripts/google-flow-cli/gflow/auth/browser_auth.py +692 -0
  71. package/skills/short-maker/scripts/google-flow-cli/gflow/auth/humanizer.py +417 -0
  72. package/skills/short-maker/scripts/google-flow-cli/gflow/auth/proxy_ext.py +120 -0
  73. package/skills/short-maker/scripts/google-flow-cli/gflow/auth/recaptcha.py +482 -0
  74. package/skills/short-maker/scripts/google-flow-cli/gflow/batchexecute/__init__.py +5 -0
  75. package/skills/short-maker/scripts/google-flow-cli/gflow/batchexecute/client.py +414 -0
  76. package/skills/short-maker/scripts/google-flow-cli/gflow/cli/__init__.py +1 -0
  77. package/skills/short-maker/scripts/google-flow-cli/gflow/cli/main.py +1075 -0
  78. package/skills/short-maker/scripts/google-flow-cli/pyproject.toml +36 -0
  79. package/skills/short-maker/scripts/google-flow-cli/script.txt +22 -0
  80. package/skills/short-maker/scripts/google-flow-cli/tests/__init__.py +0 -0
  81. package/skills/short-maker/scripts/google-flow-cli/tests/test_batchexecute.py +113 -0
  82. package/skills/short-maker/scripts/google-flow-cli/tests/test_client.py +190 -0
  83. package/skills/short-maker/templates/aida_script.md +40 -0
  84. package/skills/short-maker/templates/mimic_analyzer.md +29 -0
  85. package/skills/single-flow-task-execution/SKILL.md +412 -0
  86. package/skills/single-flow-task-execution/code-quality-reviewer-prompt.md +20 -0
  87. package/skills/single-flow-task-execution/implementer-prompt.md +78 -0
  88. package/skills/single-flow-task-execution/spec-reviewer-prompt.md +61 -0
  89. package/skills/skill-creator/SKILL.md +44 -0
  90. package/skills/spm-build-analysis/SKILL.md +92 -0
  91. package/skills/spm-build-analysis/references/build-optimization-sources.md +155 -0
  92. package/skills/spm-build-analysis/references/recommendation-format.md +85 -0
  93. package/skills/spm-build-analysis/references/spm-analysis-checks.md +105 -0
  94. package/skills/spm-build-analysis/scripts/check_spm_pins.py +118 -0
  95. package/skills/symphony-enforcer/SKILL.md +83 -97
  96. package/skills/symphony-orchestrator/SKILL.md +1 -1
  97. package/skills/trello-sync/SKILL.md +52 -45
  98. package/skills/verification-gate/SKILL.md +13 -2
  99. package/skills/xcode-build-benchmark/SKILL.md +88 -0
  100. package/skills/xcode-build-benchmark/references/benchmark-artifacts.md +94 -0
  101. package/skills/xcode-build-benchmark/references/benchmarking-workflow.md +67 -0
  102. package/skills/xcode-build-benchmark/schemas/build-benchmark.schema.json +230 -0
  103. package/skills/xcode-build-benchmark/scripts/benchmark_builds.py +308 -0
  104. package/skills/xcode-build-fixer/SKILL.md +218 -0
  105. package/skills/xcode-build-fixer/references/build-settings-best-practices.md +216 -0
  106. package/skills/xcode-build-fixer/references/fix-patterns.md +290 -0
  107. package/skills/xcode-build-fixer/references/recommendation-format.md +85 -0
  108. package/skills/xcode-build-fixer/scripts/benchmark_builds.py +308 -0
  109. package/skills/xcode-build-orchestrator/SKILL.md +156 -0
  110. package/skills/xcode-build-orchestrator/references/benchmark-artifacts.md +94 -0
  111. package/skills/xcode-build-orchestrator/references/build-settings-best-practices.md +216 -0
  112. package/skills/xcode-build-orchestrator/references/orchestration-report-template.md +143 -0
  113. package/skills/xcode-build-orchestrator/references/recommendation-format.md +85 -0
  114. package/skills/xcode-build-orchestrator/scripts/benchmark_builds.py +308 -0
  115. package/skills/xcode-build-orchestrator/scripts/diagnose_compilation.py +273 -0
  116. package/skills/xcode-build-orchestrator/scripts/generate_optimization_report.py +533 -0
  117. package/skills/xcode-compilation-analyzer/SKILL.md +89 -0
  118. package/skills/xcode-compilation-analyzer/references/build-optimization-sources.md +155 -0
  119. package/skills/xcode-compilation-analyzer/references/code-compilation-checks.md +106 -0
  120. package/skills/xcode-compilation-analyzer/references/recommendation-format.md +85 -0
  121. package/skills/xcode-compilation-analyzer/scripts/diagnose_compilation.py +273 -0
  122. package/skills/xcode-project-analyzer/SKILL.md +76 -0
  123. package/skills/xcode-project-analyzer/references/build-optimization-sources.md +155 -0
  124. package/skills/xcode-project-analyzer/references/build-settings-best-practices.md +216 -0
  125. package/skills/xcode-project-analyzer/references/project-audit-checks.md +101 -0
  126. package/skills/xcode-project-analyzer/references/recommendation-format.md +85 -0
  127. package/templates/CODEBASE.md +26 -42
  128. package/templates/configs/trello-config.json +2 -2
  129. package/templates/workflow_dual_mode_template.md +5 -5
  130. package/workflows/_uncategorized/conductor-codex.md +125 -0
  131. package/workflows/_uncategorized/conductor.md +97 -0
  132. package/workflows/_uncategorized/ship-to-code.md +85 -0
  133. package/workflows/_uncategorized/trello-sync.md +52 -0
  134. package/workflows/context/codebase-sync.md +10 -87
  135. package/workflows/quality/visual-debug.md +66 -12
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: ship-to-code
3
+ description: >-
4
+ Universal Code Porting & Migration Specialist. Translates legacy or reference code
5
+ from ANY source language/framework to ANY target language/framework.
6
+ Rebuilds the architecture while adhering to the target's modern best practices.
7
+ author: Antigravity Team
8
+ version: 1.0.0
9
+ trigger: conditional
10
+ activation_keywords:
11
+ - "/ship-to-code"
12
+ - "/port-code"
13
+ - "/migrate-code"
14
+ - "port code"
15
+ - "chuyển ngôn ngữ"
16
+ - "ship to code"
17
+ - "dịch code"
18
+ priority: high
19
+ platform: agnostic
20
+ ---
21
+
22
+ # 🚢 Ship-to-Code Skill
23
+
24
+ > **Purpose:** Transform reference codebase from ANY source language/framework to ANY modern target language/framework.
25
+ > **Philosophy:** "Read source to understand WHAT and WHY → Write target for HOW."
26
+
27
+ ---
28
+
29
+ ## ⚠️ SCOPE CLARITY
30
+
31
+ | This skill DOES | This skill DOES NOT |
32
+ |-----------------|---------------------|
33
+ | Read & analyze source language code & structure | Write in the obsolete/source language |
34
+ | Rebuild logic idiomatically in modern target language | Blindly translate line-by-line (syntax-only) |
35
+ | Map source dependencies to target equivalents | Auto-migrate production database records directly |
36
+ | Implement Clean Architecture/Modern patterns in target | Just copy-paste without adapting paradigms |
37
+ | Extract/convert needed resources on-demand | Mass-copy entire resource folders blindly |
38
+
39
+ ---
40
+
41
+ ## 🎯 ROLE DEFINITION
42
+
43
+ When this skill is active, the agent becomes:
44
+
45
+ > **Expert Multi-Language Porting Architect**
46
+ > - Master at deciphering unfamiliar, foreign or legacy codebases.
47
+ > - Fluent in modern target architectures (Clean Architecture / MVC / MVVM / Hexagonal depending on target ecosystem).
48
+ > - Knows how to map business logic across different language paradigms (e.g., Object-Oriented to Functional, Sync to Async, etc).
49
+ > - Enforces exact Input/Output mathematical parity for core algorithms and cryptology.
50
+
51
+ ---
52
+
53
+ ## 📋 EXECUTION PIPELINE (6 Phases)
54
+
55
+ > **Rule:** Always complete one phase fully before moving to the next.
56
+ > **Rule:** After each phase, create a checkpoint summary for the user to approve.
57
+
58
+ ### Phase 0: Ecosystem & Dependency Mapping 🔍
59
+ **Purpose:** Identify all 3rd-party libraries, SDKs, and frameworks in the source project and map them to the best modern equivalents in the target ecosystem.
60
+ 1. Scan source project configuration files (`package.json`, `build.gradle`, `requirements.txt`, `Cargo.toml`, `go.mod`, etc.).
61
+ 2. Generate a Library Detection Report featuring a **Matrix (Source Lib → Target Lib)**.
62
+ 3. Present to the user for evaluation and approval.
63
+
64
+ ### Phase 1: Architecture Design & Project Bootstrap 📄
65
+ **Purpose:** Analyze application entry points, metadata, lifecycle, and propose a robust target directory structure.
66
+ 1. Identify how the app starts, handles authentication, routes traffic, and loads plugins.
67
+ 2. Propose a modern project folder layout aligned with target language standards (e.g., standard Go layout, feature-first React layout, Clean Architecture for Mobile).
68
+ 3. Scaffold initial configuration files for the target language.
69
+
70
+ ### Phase 2: Data & Domain Layer Reconstruction 💾
71
+ **Purpose:** Rebuild strict data contracts and persistence infrastructure.
72
+ 1. Convert source models/POJOs/Entities into target native DTOs, interfaces, structs, or dataclasses (e.g., implementing `.fromJson()`, `Codable`, `serde`).
73
+ 2. Port Database schemas/ORMs to target paradigms (e.g., translating SQLAlchemy to Prisma, Room to SwiftData).
74
+ 3. Migrate API clients using target's native concurrency mechanisms (Coroutines, `async/await`, Goroutines).
75
+
76
+ ### Phase 3: Core Business Logic & Utils 🧮
77
+ **Purpose:** Port specialized algorithms, encryption, math, and custom helpers.
78
+ 1. Translate raw logic with strict adherence to the exact mathematical and state behavior of the source.
79
+ 2. Provide **Unit Tests** in the target language to prove 100% computational parity with source output (especially for Base64, MD5/SHA, AES, timezone parsing).
80
+
81
+ ### Phase 4: UI & Presentation / Controller Layer 🎨
82
+ **Purpose:** Rebuild user interfaces or API controllers utilizing the target's standard frameworks.
83
+ 1. Map source UI components to target equivalents (e.g., React to Compose, HTML/Jinja to Vue, Android XML to SwiftUI).
84
+ 2. For backend APIs: Convert source controller route handling to modern target framework routing (e.g., Express.js to FastAPI, Spring Boot to Go Gin).
85
+ 3. Implement modern state management and reactive data flows native to the new ecosystem.
86
+
87
+ ### Phase 5: SDK Integration & Parity Quality Gate ✅
88
+ **Purpose:** Finalize third-party setups and ensure feature completeness.
89
+ 1. Wire up heavy SDKs (Auth, Analytics, Push Notifications, Payment gateways) with target SDKs.
90
+ 2. Perform rigorous Parity Validation across:
91
+ - *Branch Coverage:* Ensure all `if/switch` edge cases from source were ported.
92
+ - *Endpoint Parity:* Ensure headers, bodies, status codes match output.
93
+ - *Visual Parity:* (If UI) Layout behaves correctly.
94
+
95
+ ---
96
+
97
+ ## 🚫 ANTI-PATTERNS
98
+
99
+ ```yaml
100
+ never_do:
101
+ - Line-by-line verbatim syntax translation (e.g., writing Java code in Go syntax using 'for' instead of 'range', or ignoring Swift optionals to force unwrap like in C#).
102
+ - Use deprecated patterns in the target ecosystem just because the source used them.
103
+ - Skip extracting business rules before writing the target implementation.
104
+ - Alter encryption hashes / outputs — they must match the original exactly for server compatibility!
105
+
106
+ always_do:
107
+ - Write Idiomatic Code: Fully embrace the target language's design patterns, conventions, and error-handling features.
108
+ - Checkpoint and halt after generating the Ecosystem Dependency Matrix to let the user review framework choices.
109
+ - Build test suites to verify math and crypto translations against known source outputs.
110
+ ```
111
+
112
+ ---
113
+
114
+ *ship-to-code v1.0.0 — Universal Code Porting Skill*
115
+ *Created by Antigravity Team*
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: short-maker
3
+ description: |
4
+ Đạo diễn sản xuất video quảng cáo App (App Promo) bằng AI. Tự động hóa quy trình viết kịch bản AIDA,
5
+ quản lý storyboard qua ShortMaker Studio MCP Server, và gọi Google Flow (Veo 3) render video bối cảnh thật
6
+ kèm Native Voice. Hỗ trợ Mimic Mode bóc tách nội dung trending từ YouTube/TikTok.
7
+ metadata:
8
+ stage: workflow
9
+ version: "2.0"
10
+ requires: "ShortMaker Studio (MCP Server), google-flow-cli, ffmpeg"
11
+ tags: [video, marketing, ads, app-promo, veo, gflow, tiktok, youtube, shorts, mcp]
12
+ trigger: explicit
13
+ activation_keywords:
14
+ - "/short"
15
+ - "/promo"
16
+ - "/mimic"
17
+ - "làm video tiktok"
18
+ - "chạy video flow"
19
+ ---
20
+
21
+ # 🎬 Short Maker v2.0 (MCP Client Mode)
22
+
23
+ > **Mục tiêu**: Tối đa hóa traffic miễn phí từ Video ngắn (TikTok, YouTube Shorts, Reels)
24
+ > bằng cách tự động sản xuất video quảng cáo App với cấu trúc AIDA hoặc copy (Mimic) hook viral.
25
+
26
+ ## ⚠️ Prerequisites (BẮT BUỘC)
27
+
28
+ Skill này hoạt động như **MCP Client** — mọi thao tác project/storyboard/render đều gọi qua **ShortMaker Studio MCP Server**.
29
+
30
+ **Trước khi bắt đầu, KIỂM TRA:**
31
+ 1. ShortMaker Studio MCP Server đang chạy (IDE đã kết nối qua MCP config)
32
+ 2. Gọi thử `shortmaker_list_projects` — nếu thành công → MCP Server OK
33
+ 3. Google Flow auth: kiểm tra `~/.gflow/env` tồn tại. Nếu chưa:
34
+ ```bash
35
+ cd ~/Dev2/MacOS/Shortmaker/scripts/google-flow-cli && PYTHONPATH=. python3 gflow/cli/main.py auth
36
+ ```
37
+
38
+ ## 📡 Chế độ hoạt động (Triggers)
39
+
40
+ - **Original Mode (`/promo`, `/short`)**: User nhập [Tên App + Tính năng]. AI đóng vai Giám đốc Marketing, lên kịch bản AIDA.
41
+ - **Mimic Mode (`/mimic`)**: User cung cấp [Link YouTube/TikTok]. AI trích xuất transcript, phân tích Hook/Pacing, sau đó clone cấu trúc kịch bản đó nhưng áp dụng cho App của user.
42
+
43
+ ## 🧱 Quy trình hoạt động (Mandatory Flow)
44
+
45
+ **Bảo vệ Credit**: Mọi video Veo 3 đều tốn 20 credit. TUYỆT ĐỐI không gọi render khi chưa có xác nhận từ người dùng qua bước Storyboard Review.
46
+
47
+ ### Giai đoạn 1: Bootstrap Project
48
+
49
+ Gọi MCP tool để tạo project:
50
+ ```
51
+ shortmaker_create_project(name: "FitWitness Promo", appName: "FitWitness", description: "30s TikTok promo")
52
+ ```
53
+ → Trả về `projectId` và `path`. Dùng `projectId` cho tất cả các bước sau.
54
+
55
+ ### Giai đoạn 2: Kịch Bản & Character Casting
56
+
57
+ 1. Sinh kịch bản `script.md` (dùng template `aida_script.md` hoặc `mimic_analyzer.md`).
58
+ 2. **Character Setup** — gọi MCP tool:
59
+ ```
60
+ shortmaker_setup_character(projectId: "...", prompt: "A young Vietnamese woman, long black hair...", seed: "123456")
61
+ ```
62
+ 3. **Xử lý ảnh tham chiếu**:
63
+ - User cung cấp ảnh → AI phân tích, viết `character_prompt`, copy ảnh vào project dir
64
+ - User không có ảnh → AI thiết kế character, gọi `generate-image` tạo mẫu
65
+ 4. **Actor Approval**: Trình bày ảnh cho User. CHỈ TIẾP TỤC khi User chốt nhân vật.
66
+
67
+ ### Giai đoạn 3: Storyboard (0 Cost)
68
+
69
+ Gọi MCP tool lặp lại cho từng scene:
70
+ ```
71
+ shortmaker_add_scene(
72
+ projectId: "...",
73
+ prompt: "A woman standing in a modern gym, looking at her phone...",
74
+ speech: "Tired of forgetting your workouts?",
75
+ duration: 8,
76
+ transition: "fade",
77
+ sceneType: "hook"
78
+ )
79
+ ```
80
+
81
+ **Quy tắc prompt**:
82
+ - **ƯU TIÊN MÔI TRƯỜNG THẬT**: TUYỆT ĐỐI KHÔNG dùng Greenscreen/Chroma key mặc định
83
+ - Character prompt sẽ được auto-prepend bởi MCP Server
84
+ - BẮT BUỘC truyền `--seed` đã chốt khi render
85
+
86
+ Sau khi thêm đủ scenes, hướng dẫn User mở **ShortMaker Studio** để review storyboard trực quan.
87
+ Hoặc AI tự review bằng:
88
+ ```
89
+ shortmaker_get_storyboard(projectId: "...")
90
+ ```
91
+
92
+ Sửa scene nếu cần:
93
+ ```
94
+ shortmaker_update_scene(projectId: "...", sceneId: "scene-01", speech: "Updated narration")
95
+ ```
96
+
97
+ **CHỈ TIẾP TỤC khi User xác nhận đã duyệt xong Storyboard.**
98
+
99
+ ### Giai đoạn 4: Render (Batch)
100
+
101
+ Gọi MCP tool:
102
+ ```
103
+ shortmaker_trigger_render(projectId: "...", fadeDuration: 1.0, bgmVolume: 0.1)
104
+ ```
105
+
106
+ User có thể theo dõi tiến trình trên ShortMaker Studio GUI.
107
+
108
+ ## 🔀 Hiệu ứng Chuyển Cảnh (Transitions)
109
+
110
+ Các hiệu ứng được hỗ trợ (truyền vào `transition` khi `add_scene`):
111
+ - `fade` — Chuyển mờ dần (mặc định)
112
+ - `slideleft` / `slideright` — Trượt sang trái/phải
113
+ - `wipeleft` / `wiperight` — Quét sang trái/phải
114
+ - `circlecrop` — Thu nhỏ hình tròn
115
+ - `dissolve` — Hòa tan
116
+ - `none` — Cắt thẳng, không hiệu ứng
117
+
118
+ ## 🌿 Green Screen (Fallback Option)
119
+
120
+ Nếu User ĐẶC BIỆT yêu cầu greenscreen:
121
+ - Thêm "on a solid chroma green screen background" vào prompt scene
122
+ - Render pipeline sẽ tự xử lý chroma key với background được cung cấp
123
+
124
+ ## 📁 Output Convention
125
+
126
+ Projects được lưu tại `~/ShortMaker-Projects/<project-id>/`:
127
+ ```
128
+ <project-id>/
129
+ ├── shortmaker.config.json # Project config (auto-managed)
130
+ ├── storyboard.json # Scene data (auto-managed)
131
+ ├── assets/ # Character ref, BGM
132
+ ├── storyboard/ # Scene preview images
133
+ ├── segments/ # Rendered video segments
134
+ ├── tts/ # TTS audio files
135
+ ├── temp/ # Temporary processing files
136
+ └── final/ # Final mixed output
137
+ ```
138
+
139
+ ## 🔧 MCP Tools Reference
140
+
141
+ | Tool | Mục đích |
142
+ |------|----------|
143
+ | `shortmaker_list_projects` | Liệt kê projects hiện có |
144
+ | `shortmaker_create_project` | Tạo project mới |
145
+ | `shortmaker_setup_character` | Chốt nhân vật (prompt + seed) |
146
+ | `shortmaker_add_scene` | Thêm scene vào storyboard |
147
+ | `shortmaker_update_scene` | Sửa scene đã có |
148
+ | `shortmaker_get_storyboard` | Xem toàn bộ storyboard |
149
+ | `shortmaker_trigger_render` | Bắt đầu render pipeline (async, chạy ngầm) |
150
+ | `shortmaker_get_render_status` | Kiểm tra tiến trình render đang chạy (polling) |
@@ -0,0 +1,106 @@
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Storyboard Preview</title>
7
+ <style>
8
+ :root {
9
+ --bg: #121212; --card-bg: #1E1E1E; --text: #E0E0E0; --accent: #BB86FC; --accent-hover: #9965f4;
10
+ }
11
+ body {
12
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
13
+ background-color: var(--bg); color: var(--text); padding: 20px;
14
+ }
15
+ header { text-align: center; margin-bottom: 30px; }
16
+ h1 { margin: 0; color: var(--accent); }
17
+ .meta { color: #888; font-size: 0.9em; margin-top: 5px; }
18
+ .grid {
19
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 20px;
20
+ }
21
+ .card {
22
+ background: var(--card-bg); border-radius: 12px; overflow: hidden;
23
+ box-shadow: 0 4px 6px rgba(0,0,0,0.3); border: 1px solid #333;
24
+ }
25
+ .card-img-wrapper { position: relative; padding-top: 56.25%; /* 16:9 Aspect Ratio */ background: #000; }
26
+ .card img {
27
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover;
28
+ }
29
+ .scene-number {
30
+ position: absolute; top: 10px; left: 10px; background: rgba(0,0,0,0.7);
31
+ color: #fff; padding: 4px 8px; border-radius: 6px; font-weight: bold; font-size: 0.8em;
32
+ }
33
+ .card-content { padding: 15px; }
34
+ .duration { color: var(--accent); font-weight: bold; font-size: 0.9em; margin-bottom: 8px; }
35
+ .script { font-size: 1em; line-height: 1.4; margin-bottom: 12px; }
36
+ .prompt { font-size: 0.8em; color: #888; font-style: italic; background: #2a2a2a; padding: 8px; border-radius: 6px; }
37
+ .timeline-bar {
38
+ height: 6px; background: #333; margin-top: 30px; border-radius: 3px; position: relative; overflow: hidden;
39
+ }
40
+ .timeline-progress { height: 100%; background: var(--accent); width: 0%; }
41
+ </style>
42
+ </head>
43
+ <body>
44
+
45
+ <header>
46
+ <h1 id="title">Loading Storyboard...</h1>
47
+ <div class="meta" id="meta">Duration: 0s</div>
48
+ </header>
49
+
50
+ <div class="timeline-bar">
51
+ <div class="timeline-progress" id="timeline"></div>
52
+ </div>
53
+
54
+ <div class="grid" id="grid">
55
+ <!-- Cards will be injected here -->
56
+ </div>
57
+
58
+ <script>
59
+ async function loadStoryboard() {
60
+ try {
61
+ // Fetch expects storyboard.json in the same directory
62
+ const response = await fetch('storyboard.json');
63
+ const data = await response.json();
64
+
65
+ document.getElementById('title').textContent = data.title || 'App Promo Storyboard';
66
+ document.getElementById('meta').textContent = `Total Duration: ${data.duration || 0}s | Video Target: ${data.target_format || '16:9'}`;
67
+
68
+ const grid = document.getElementById('grid');
69
+ grid.innerHTML = '';
70
+
71
+ let totalTime = data.duration || 1; // avoid /0
72
+ let cumulative = 0;
73
+
74
+ data.scenes.forEach((scene, index) => {
75
+ cumulative += scene.duration;
76
+
77
+ const card = document.createElement('div');
78
+ card.className = 'card';
79
+ card.innerHTML = `
80
+ <div class="card-img-wrapper">
81
+ <img src="${scene.image || 'https://via.placeholder.com/640x360?text=Generating+Image...'}" alt="Scene ${scene.id}">
82
+ <div class="scene-number">Scene ${scene.id}</div>
83
+ </div>
84
+ <div class="card-content">
85
+ <div class="duration">⏱️ ${scene.duration}s</div>
86
+ <div class="script">🎙️ "${scene.script}"</div>
87
+ <div class="prompt">🎨 Prompt: ${scene.prompt}</div>
88
+ </div>
89
+ `;
90
+ grid.appendChild(card);
91
+ });
92
+
93
+ // Setup dumb timeline animation for fun
94
+ const timeline = document.getElementById('timeline');
95
+ timeline.style.width = '100%';
96
+ timeline.style.transition = `width ${data.duration}s linear`;
97
+ } catch (e) {
98
+ document.getElementById('title').innerHTML = `<span style="color:red">Error Loading storyboard.json</span>`;
99
+ console.error(e);
100
+ }
101
+ }
102
+
103
+ loadStoryboard();
104
+ </script>
105
+ </body>
106
+ </html>
@@ -0,0 +1,296 @@
1
+ import argparse
2
+ import glob
3
+ import json
4
+ import os
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+
10
+ def get_duration(filepath: Path) -> float:
11
+ cmd = [
12
+ "ffprobe",
13
+ "-v", "error",
14
+ "-show_entries", "format=duration",
15
+ "-of", "default=noprint_wrappers=1:nokey=1",
16
+ str(filepath)
17
+ ]
18
+ try:
19
+ output = subprocess.check_output(cmd, text=True).strip()
20
+ return float(output)
21
+ except Exception as e:
22
+ print(f"Error getting duration for {filepath}: {e}")
23
+ return 0.0
24
+
25
+
26
+ def check_has_audio(filepath: Path) -> bool:
27
+ cmd = [
28
+ "ffprobe", "-v", "error",
29
+ "-select_streams", "a",
30
+ "-show_entries", "stream=codec_type",
31
+ "-of", "csv=p=0",
32
+ str(filepath)
33
+ ]
34
+ try:
35
+ output = subprocess.check_output(cmd, text=True).strip()
36
+ return len(output) > 0
37
+ except Exception:
38
+ return False
39
+
40
+
41
+ def ensure_dir(path: Path) -> Path:
42
+ path.mkdir(parents=True, exist_ok=True)
43
+ return path
44
+
45
+
46
+ # Supported FFmpeg xfade transitions
47
+ SUPPORTED_TRANSITIONS = [
48
+ 'fade', 'slideleft', 'slideright', 'circlecrop',
49
+ 'dissolve', 'wipeleft', 'wiperight',
50
+ 'smoothleft', 'smoothright', 'smoothup', 'smoothdown',
51
+ ]
52
+
53
+
54
+ def load_storyboard_transitions(project_dir: Path) -> list:
55
+ """Read per-scene transitions from storyboard.json if available."""
56
+ sb_path = project_dir / "storyboard.json"
57
+ if not sb_path.exists():
58
+ return []
59
+ try:
60
+ with open(sb_path, 'r') as f:
61
+ data = json.load(f)
62
+ transitions = []
63
+ for scene in data.get('scenes', []):
64
+ t = scene.get('transition', 'fade')
65
+ if t not in SUPPORTED_TRANSITIONS:
66
+ t = 'fade'
67
+ transitions.append(t)
68
+ return transitions
69
+ except Exception as e:
70
+ print(f"Warning: Could not read storyboard.json: {e}")
71
+ return []
72
+
73
+
74
+ def main():
75
+ parser = argparse.ArgumentParser(description="Auto-Mixer cho Short Maker bằng FFmpeg")
76
+ parser.add_argument("--project-dir", required=True, help="Thư mục project chứa outputs (ví dụ: outputs/promo-app)")
77
+ parser.add_argument("--fade-duration", type=float, default=1.0, help="Thời gian crossfade giữa các cảnh (giây)")
78
+ parser.add_argument("--bgm-volume", type=float, default=0.1, help="Âm lượng nhạc nền (0.0 đến 1.0)")
79
+ parser.add_argument("--chroma-bg", type=str, help="Đường dẫn đến ảnh/video nền để thay thế phông xanh")
80
+ parser.add_argument("--chroma-color", type=str, default="0x00FF00", help="Mã màu phông xanh (mặc định: 0x00FF00)")
81
+ parser.add_argument("--chroma-sim", type=float, default=0.3, help="Độ tương đồng màu (0.01 - 1.0, mặc định: 0.3)")
82
+ parser.add_argument("--chroma-blend", type=float, default=0.2, help="Độ mượt viền (0.0 - 1.0, mặc định: 0.2)")
83
+ args = parser.parse_args()
84
+
85
+ project_dir = Path(args.project_dir)
86
+ segments_dir = project_dir / "segments"
87
+ tts_dir = project_dir / "tts"
88
+ audio_dir = project_dir / "audio"
89
+ temp_dir = ensure_dir(project_dir / "temp")
90
+ final_dir = ensure_dir(project_dir / "final")
91
+
92
+ if not segments_dir.exists() or not tts_dir.exists():
93
+ print(f"Error: Thư mục segments hoặc tts không tồn tại trong {project_dir}")
94
+ sys.exit(1)
95
+
96
+ # Liệt kê các cảnh
97
+ video_files = sorted(glob.glob(str(segments_dir / "*.mp4")))
98
+ if not video_files:
99
+ print("Không tìm thấy video nào trong segments/")
100
+ sys.exit(1)
101
+
102
+ scenes = []
103
+ for v_path in video_files:
104
+ v_path = Path(v_path)
105
+ scene_name = v_path.stem # vd: scene-01
106
+
107
+ # Tìm file TTS tương ứng (mp3 hoặc wav)
108
+ tts_path = tts_dir / f"{scene_name}.mp3"
109
+ if not tts_path.exists():
110
+ tts_path = tts_dir / f"{scene_name}.wav"
111
+
112
+ if not tts_path.exists():
113
+ print(f"Thêm cảnh {scene_name} nhưng KHÔNG có file âm thanh TTS.")
114
+ scenes.append({"video": v_path, "audio": None})
115
+ else:
116
+ scenes.append({"video": v_path, "audio": tts_path})
117
+
118
+ print(f"Bắt đầu mix {len(scenes)} cảnh...")
119
+
120
+ # Bước 1: Render từng cảnh riêng lẻ (Loop video để khớp với audio)
121
+ ready_scenes = []
122
+ for idx, scene in enumerate(scenes):
123
+ out_scene = temp_dir / f"ready_{idx:02d}.mp4"
124
+ ready_scenes.append(out_scene)
125
+
126
+ # Tiết kiệm thời gian nếu render rồi
127
+ if out_scene.exists():
128
+ print(f" - [Skip] Cảnh {idx+1} đã được chuẩn bị.")
129
+ continue
130
+
131
+ print(f" - [Render] Chuẩn bị cảnh {idx+1}...")
132
+ if scene["audio"]:
133
+ # Dùng stream_loop để loop video nếu nó ngắn hơn audio
134
+ cmd = [
135
+ "ffmpeg", "-y",
136
+ "-stream_loop", "-1", "-i", str(scene["video"]),
137
+ "-i", str(scene["audio"]),
138
+ "-c:v", "libx264", "-c:a", "aac",
139
+ "-map", "0:v:0", "-map", "1:a:0",
140
+ "-shortest", "-pix_fmt", "yuv420p",
141
+ str(out_scene)
142
+ ]
143
+ else:
144
+ # Ưu tiên Native Voice của Veo 3 nếu không có file TTS ngoài.
145
+ # Nếu video không có audio stream, thêm audio âm câm để mix tránh lỗi acrossfade.
146
+ has_audio = check_has_audio(scene["video"])
147
+ if has_audio:
148
+ cmd = [
149
+ "ffmpeg", "-y",
150
+ "-i", str(scene["video"]),
151
+ "-c:v", "libx264", "-c:a", "aac", "-pix_fmt", "yuv420p",
152
+ str(out_scene)
153
+ ]
154
+ else:
155
+ cmd = [
156
+ "ffmpeg", "-y",
157
+ "-f", "lavfi", "-i", "anullsrc=channel_layout=stereo:sample_rate=44100",
158
+ "-i", str(scene["video"]),
159
+ "-c:v", "libx264", "-c:a", "aac",
160
+ "-map", "1:v:0", "-map", "0:a:0",
161
+ "-shortest", "-pix_fmt", "yuv420p",
162
+ str(out_scene)
163
+ ]
164
+
165
+ subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
166
+
167
+ # Bước 2: Ghép các cảnh bằng XFade (Chuyển cảnh nhẹ nhàng)
168
+ # Load per-scene transitions from storyboard.json
169
+ scene_transitions = load_storyboard_transitions(project_dir)
170
+ print("Bắt đầu Crossfade nối màn...")
171
+ merged_output = temp_dir / "merged_crossfaded.mp4"
172
+ fade_d = args.fade_duration
173
+
174
+ if len(ready_scenes) == 1:
175
+ merged_output = ready_scenes[0]
176
+ else:
177
+ # Tính toán duration để tính offset
178
+ durations = [get_duration(f) for f in ready_scenes]
179
+
180
+ filter_complex = ""
181
+ inputs = []
182
+
183
+ for i, sc in enumerate(ready_scenes):
184
+ inputs.extend(["-i", str(sc)])
185
+
186
+ offsets = []
187
+ current_offset = 0.0
188
+
189
+ for i in range(len(durations) - 1):
190
+ current_offset += durations[i] - fade_d
191
+ offsets.append(current_offset)
192
+
193
+ # Build video filter with per-scene transitions
194
+ v_labels = [f"[{i}:v]" for i in range(len(ready_scenes))]
195
+ for i in range(len(offsets)):
196
+ # Get transition for this join (from scene i to i+1)
197
+ transition_type = 'fade' # default
198
+ if i < len(scene_transitions):
199
+ t = scene_transitions[i]
200
+ if t != 'none':
201
+ transition_type = t
202
+
203
+ last_out = v_labels[0]
204
+ next_in = v_labels[i+1]
205
+ out_label = f"[v{i+1}]"
206
+
207
+ if i < len(scene_transitions) and scene_transitions[i] == 'none':
208
+ # No transition — simple concat (handled by offset = duration)
209
+ filter_complex += f"{last_out}{next_in}xfade=transition=fade:duration=0.01:offset={offsets[i]}{out_label}; "
210
+ else:
211
+ filter_complex += f"{last_out}{next_in}xfade=transition={transition_type}:duration={fade_d}:offset={offsets[i]}{out_label}; "
212
+ v_labels[0] = out_label # Cập nhật pipe hiện tại
213
+
214
+ print(f" Scene {i+1} → {i+2}: transition={transition_type}")
215
+
216
+ # Build audio filter
217
+ a_labels = [f"[{i}:a]" for i in range(len(ready_scenes))]
218
+ for i in range(len(offsets)):
219
+ last_out = a_labels[0]
220
+ next_in = a_labels[i+1]
221
+ out_label = f"[a{i+1}]"
222
+ filter_complex += f"{last_out}{next_in}acrossfade=d={fade_d}{out_label}; "
223
+ a_labels[0] = out_label
224
+
225
+ cmd_merge = ["ffmpeg", "-y"] + inputs + [
226
+ "-filter_complex", filter_complex.strip(" ;"),
227
+ "-map", v_labels[0],
228
+ "-map", a_labels[0],
229
+ "-c:v", "libx264", "-c:a", "aac", "-pix_fmt", "yuv420p",
230
+ str(merged_output)
231
+ ]
232
+
233
+ print(" Đang render crossfade... (có thể mất vài phút)")
234
+ subprocess.run(cmd_merge, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
235
+
236
+ # Bước 2.5: Ghép hình nền tách phông xanh (nếu có)
237
+ if args.chroma_bg and os.path.exists(args.chroma_bg):
238
+ print(f"Bắt đầu tách phông xanh và ghép nền: {args.chroma_bg}...")
239
+ merged_chroma = temp_dir / "merged_chroma.mp4"
240
+ bg_ext = Path(args.chroma_bg).suffix.lower()
241
+ is_image = bg_ext in ['.png', '.jpg', '.jpeg']
242
+
243
+ filter_complex = (
244
+ f"[0:v][1:v]scale2ref=w=iw:h=ih[bg][ref];"
245
+ f"[ref]colorkey={args.chroma_color}:{args.chroma_sim}:{args.chroma_blend}[ckout];"
246
+ f"[bg][ckout]overlay=shortest=1"
247
+ )
248
+
249
+ if is_image:
250
+ cmd_chroma = [
251
+ "ffmpeg", "-y",
252
+ "-loop", "1", "-framerate", "30", "-i", str(args.chroma_bg),
253
+ "-i", str(merged_output),
254
+ "-filter_complex", filter_complex,
255
+ "-c:v", "libx264", "-c:a", "copy", "-pix_fmt", "yuv420p",
256
+ str(merged_chroma)
257
+ ]
258
+ else:
259
+ cmd_chroma = [
260
+ "ffmpeg", "-y",
261
+ "-stream_loop", "-1", "-i", str(args.chroma_bg),
262
+ "-i", str(merged_output),
263
+ "-filter_complex", filter_complex,
264
+ "-c:v", "libx264", "-c:a", "copy", "-pix_fmt", "yuv420p",
265
+ str(merged_chroma)
266
+ ]
267
+
268
+ subprocess.run(cmd_chroma, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
269
+ merged_output = merged_chroma
270
+
271
+ # Bước 3: Lồng nhạc nền
272
+ bgm_file = audio_dir / "bgm.mp3"
273
+ final_output = final_dir / "promo-final.mp4"
274
+
275
+ if bgm_file.exists():
276
+ print(f"Mix nhạc nền (âm lượng {args.bgm_volume})...")
277
+ cmd_bgm = [
278
+ "ffmpeg", "-y",
279
+ "-i", str(merged_output),
280
+ "-stream_loop", "-1", "-i", str(bgm_file),
281
+ "-filter_complex", f"[1:a]volume={args.bgm_volume}[bgm];[0:a][bgm]amix=inputs=2:duration=first:dropout_transition=2[a]",
282
+ "-map", "0:v:0", "-map", "[a]",
283
+ "-c:v", "copy", "-c:a", "aac",
284
+ str(final_output)
285
+ ]
286
+ subprocess.run(cmd_bgm, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
287
+ else:
288
+ print("Không tìm thấy bgm.mp3, bỏ qua mix nhạc nền.")
289
+ import shutil
290
+ shutil.copy(merged_output, final_output)
291
+
292
+ print(f"\n✅ Hoàn tất! Video lưu tại: {final_output}")
293
+
294
+
295
+ if __name__ == "__main__":
296
+ main()