@kaydash9999/banker-plugins 0.27.0 → 0.28.0

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 (54) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +22 -0
  4. package/README.md +17 -5
  5. package/codex/manifest.json +3 -0
  6. package/package.json +1 -1
  7. package/skills/video-gen/SKILL.md +141 -0
  8. package/skills/video-gen/assets/example.json +36 -0
  9. package/skills/video-gen/scripts/vg-catalog.mjs +23 -0
  10. package/skills/video-gen/scripts/vg-deck.mjs +72 -0
  11. package/skills/video-gen/scripts/vg-draw.mjs +231 -0
  12. package/skills/video-gen/scripts/vg-engine.mjs +74 -0
  13. package/skills/video-gen/scripts/vg-fx.mjs +106 -0
  14. package/skills/video-gen/scripts/vg-model.mjs +236 -0
  15. package/skills/video-gen/scripts/vg-render.mjs +151 -0
  16. package/skills/video-gen/scripts/vg-scenes.mjs +226 -0
  17. package/skills/video-gen/scripts/video-gen.mjs +212 -0
  18. package/skills/video-gen/vendor/README.md +25 -0
  19. package/skills/video-gen/vendor/aimotion/LICENSE.md +21 -0
  20. package/skills/video-gen/vendor/canvaskit/LICENSE.md +29 -0
  21. package/skills/video-gen/vendor/canvaskit/THIRD-PARTY-NOTICES.md +1366 -0
  22. package/skills/video-gen/vendor/canvaskit/canvaskit.js +270 -0
  23. package/skills/video-gen/vendor/canvaskit/canvaskit.wasm +0 -0
  24. package/skills/video-gen/vendor/fonts/NotoSans-Bold.ttf +0 -0
  25. package/skills/video-gen/vendor/fonts/NotoSans-Regular.ttf +0 -0
  26. package/skills/video-gen/vendor/fonts/NotoSansKR-Bold.otf +0 -0
  27. package/skills/video-gen/vendor/fonts/NotoSansKR-Regular.otf +0 -0
  28. package/skills/video-gen/vendor/fonts/OFL-noto-sans-kr.md +94 -0
  29. package/skills/video-gen/vendor/fonts/OFL-noto-sans.md +93 -0
  30. package/skills/video-gen/vendor/h264-mp4-encoder/LICENSE.md +21 -0
  31. package/skills/video-gen/vendor/h264-mp4-encoder/MPL-1.1.md +469 -0
  32. package/skills/video-gen/vendor/h264-mp4-encoder/h264-mp4-encoder.node.js +2 -0
  33. package/skills/wbs-gen/SKILL.md +127 -0
  34. package/skills/wbs-gen/assets/example.json +58 -0
  35. package/skills/wbs-gen/scripts/wbs-gen.mjs +238 -0
  36. package/skills/wbs-gen/scripts/wg-dates.mjs +106 -0
  37. package/skills/wbs-gen/scripts/wg-holidays.mjs +89 -0
  38. package/skills/wbs-gen/scripts/wg-html.mjs +108 -0
  39. package/skills/wbs-gen/scripts/wg-plan.mjs +230 -0
  40. package/skills/wbs-gen/scripts/wg-xlsx.mjs +328 -0
  41. package/skills/wbs-gen/scripts/wg-zip.mjs +83 -0
  42. package/skills/wide-pptx/SKILL.md +121 -0
  43. package/skills/wide-pptx/assets/example.json +63 -0
  44. package/skills/wide-pptx/scripts/wide-pptx.mjs +185 -0
  45. package/skills/wide-pptx/scripts/wp-html.mjs +98 -0
  46. package/skills/wide-pptx/scripts/wp-model.mjs +236 -0
  47. package/skills/wide-pptx/scripts/wp-pptx.mjs +219 -0
  48. package/skills/wide-pptx/scripts/wp-svg.mjs +114 -0
  49. package/skills/wide-pptx/vendor/LICENSE-jszip.md +651 -0
  50. package/skills/wide-pptx/vendor/LICENSE-pako.md +21 -0
  51. package/skills/wide-pptx/vendor/LICENSE-pptxgenjs.md +21 -0
  52. package/skills/wide-pptx/vendor/README.md +12 -0
  53. package/skills/wide-pptx/vendor/THIRD-PARTY-NOTICES.md +142 -0
  54. package/skills/wide-pptx/vendor/pptxgen.bundle.js +96 -0
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code skills + commands — QA, audit, docs, architecture, dependency setup, and wiki; the banker plugin marketplace.",
9
- "version": "0.27.0"
9
+ "version": "0.28.0"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "banker",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "Claude Code plugin: QA/audit/docs/architecture skills + commands, a /banker:setup installer for OS dependencies (playwright, etc.), and wiki compaction.",
5
5
  "author": {
6
6
  "name": "smallOpenSource",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.28.0] - 2026-11-10
4
+
5
+ ### Added
6
+ - 새 스킬 `wide-pptx`: 발표용 16:9 슬라이드를 한 JSON 덱에서 PPTX 와 단일 HTML 덱으로 같은 배치로 만든다.
7
+ - 슬라이드 종류 9개(표지, 구역, 글머리, 2단, 표, 차트, 그림, 인용, 끝)와 발표자 노트. `example`, `check`(넘침 어림 경고), `build` 명령.
8
+ - PptxGenJS 4.0.1 번들을 스킬에 넣고(sha256 고정, 라이선스 동봉) Node `vm` 의 별도 컨텍스트에서 불러 쓴다. 호스트의 내장 객체를 바꾸지 않는다.
9
+ - 글꼴은 한글 Noto Sans KR, 그 밖 Noto Sans. 테마, 차트, 표의 글꼴과 언어(ko-KR)를 쓴 뒤에 고친다.
10
+ - HTML 덱은 자체 스크립트와 SVG 차트로 동작하고 16:9 로 인쇄된다. 설치와 내려받기가 없다.
11
+ - 새 스킬 `wbs-gen`: WBS 를 간트 차트 XLSX 와 같은 격자의 단일 HTML 표로 만든다.
12
+ - XLSX 는 순수 Node 로 직접 쓴다(자체 ZIP, CRC-32). 막대는 셀 채움, 틀 고정, 인쇄 제목, A3 가로 한 장 너비. 셀 안의 한글과 라틴 글자는 서식 조각으로 글꼴을 나눈다.
13
+ - 영업일과 주차를 계산한다. 공휴일은 온라인이면 Google 공개 캘린더(대한민국)에서 `공휴일` 만 읽어 사용자가 확인하고, 닿지 못하면 종료 코드 3 으로 끝나 사용자가 `월/일, 월/일` 로 입력한다.
14
+ - 기간은 5년까지, 두 해에 걸치는 `월/일` 은 오류로 묻는다. 출력은 모두 만든 뒤 쓰고, `--force` 없이 덮어쓰지 않는다.
15
+ - 새 스킬 `video-gen`: 만들 수 있는 영상 목록을 보이고 고르게 한 뒤, 빠진 내용은 인터뷰로 받아 MP4 를 만든다.
16
+ - 내장 종류 9개(제목, 키네틱 타이포, 글머리, 차트, 카운터, 이름 자막, 인용, 사진, 크레디트)와 장면 전환 4개(cut, fade, wipe, stripes). `wide-pptx` 덱을 장면으로 바꾸고, 정지 화면으로 미리 확인한다.
17
+ - 렌더 엔진을 스킬에 넣었다. Skia CanvasKit 0.42.0(WASM)이 프레임을 그리고 h264-mp4-encoder 1.0.12(WASM)가 MP4 를 쓴다. Chrome, ffmpeg, 네이티브 모듈, 설치, 내려받기 없이 모든 OS 에서 같게 렌더한다.
18
+ - 글꼴은 Noto Sans 와 Noto Sans KR 을 넣었고, 글자마다 맞는 글꼴을 고른다. 프레임은 시간만의 함수라 정지 화면과 영상 프레임이 같다. 짧은 장면도 끝 프레임에 모든 내용이 보인다.
19
+ - 동작 도우미 일부는 aimotion(MIT)에서 옮겼다. libmp4v2(MPL 1.1)의 소스 묶음은 GitHub 저장소 `third_party/` 에 둔다(npm 묶음에는 없음).
20
+ - 다른 종류는 `motion-graphic-make`, `3d-intro-build`, `motion-sites` 로 넘긴다.
21
+
22
+ ### Fixed
23
+ - README: Codex 훅 신뢰 안내에 신뢰해야 도는 훅으로 banker `ralph` 계속(Stop 훅)을 더했다.
24
+
3
25
  ## [0.27.0] - 2026-11-06
4
26
 
5
27
  ### Added
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  [빠른 시작](#빠른-시작) · [워크플로 예시](#워크플로-사용-예시) · [구성](#구성) · [설치 상세](#설치-상세-npm--codex) · [설정 변경 지점](#설정-변경-지점-claude-code--codex) · [요구사항](#요구사항) · [업데이트 / 제거](#업데이트--제거) · [업데이트 확인](#업데이트-확인-및-사용량-카운팅) · [오프라인](#오프라인에서-쓰기) · [라이선스 / 서드파티](#라이선스--서드파티)
10
10
 
11
11
  □ banker는 다음을 포함하는 Claude Code 및 Codex CLI 플러그인입니다.
12
- - QA·보안 감사·문서·아키텍처·위키·미디어 작업과 의존성·개발환경(OS별) 설치를 아우르는 **스킬 72개 + 커맨드 2개**(총 74개 구성요소. Codex 는 Claude Code 전용 `ultraqa` 를 뺀 스킬 71개와 Codex 전용 스킬 4개)
12
+ - QA·보안 감사·문서·아키텍처·위키·미디어 작업과 의존성·개발환경(OS별) 설치를 아우르는 **스킬 75개 + 커맨드 2개**(총 77개 구성요소. Codex 는 Claude Code 전용 `ultraqa` 를 뺀 스킬 74개와 Codex 전용 스킬 4개)
13
13
  - Claude Code 즉시 명령 `/graceful-pause`, `/progress`
14
14
 
15
15
  □ 설치하면 스킬과 커맨드가 `/banker:<이름>` 네임스페이스로 노출됩니다.
@@ -49,7 +49,7 @@ codex plugin add banker@banker-plugins
49
49
  ```
50
50
 
51
51
  스킬을 `$banker:audit-security` 처럼 `$banker:<name>` 으로 호출합니다.\
52
- 훅(업데이트 알림, 사용량 카운팅)은 Codex 를 다시 열 때 뜨는 Hooks need review 창이나 `/hooks` 에서 신뢰해야 돕니다.\
52
+ 훅(업데이트 알림, 사용량 카운팅, banker `ralph` 계속)은 Codex 를 다시 열 때 뜨는 Hooks need review 창이나 `/hooks` 에서 신뢰해야 돕니다.\
53
53
  Codex 는 세션을 시작할 때 마켓플레이스를 스스로 올려 새 판을 받습니다. 바로 올리려면 `codex plugin marketplace upgrade banker-plugins` 를 실행합니다.
54
54
 
55
55
  2) npm 전역 설치 후 `banker setup`
@@ -126,6 +126,8 @@ Claude Code 2.1.296 은 Claude 5 모델(Opus 5.5 등)에 작업 목록 도구(Ta
126
126
  |---|---|
127
127
  | `arch-diagram` | 시스템 아키텍처 구성도 (PlantUML + 편집가능 PPTX) |
128
128
  | `vertical-pptx` | A4 세로(210x297mm) 규격 PPTX 생성·점검·수리, 16:9 덱의 A4 세로 변환 |
129
+ | `wide-pptx` | 발표용 16:9 슬라이드를 한 JSON 덱에서 PPTX 와 단일 HTML 덱으로 같은 배치로 만듦. 슬라이드 종류 9개(표지, 글머리, 2단, 차트, 표, 그림, 인용, 구역, 끝)와 발표자 노트. 번들한 PptxGenJS 4.0.1 을 써 설치와 내려받기 없이 동작하고, 글꼴은 한글 Noto Sans KR, 그 밖 Noto Sans |
130
+ | `wbs-gen` | WBS 를 간트 차트 XLSX(셀 채움 막대, 인쇄 설정)와 같은 격자의 단일 HTML 표로 만듦. 영업일과 주차를 계산하고 공휴일은 온라인이면 Google 공개 캘린더에서 읽어 사용자가 확인, 닿지 못하면 사용자가 `월/일, 월/일` 로 입력. XLSX 는 순수 Node 로 직접 써 설치가 필요 없음 |
129
131
  | `make-notion-guide` | API 호출 가이드를 노션 양식 문서로 작성 |
130
132
  | `pdf-vision-extract` | 비주얼 PDF를 고해상도 PNG로 변환(비전 입력) |
131
133
  | `nothing-design` | Nothing 스타일 UI 디자인 적용 |
@@ -181,6 +183,7 @@ Claude Code 2.1.296 은 Claude 5 모델(Opus 5.5 등)에 작업 목록 도구(Ta
181
183
 
182
184
  | 스킬 | 설명 |
183
185
  |---|---|
186
+ | `video-gen` | 만들 수 있는 영상 목록을 보이고 고르게 한 뒤, 빠진 내용은 인터뷰로 받아 MP4 를 만듦. 내장 종류 9개(제목, 키네틱 타이포, 글머리, 차트, 카운터, 이름 자막, 인용, 사진, 크레디트)와 장면 전환 4개, `wide-pptx` 덱 변환, 정지 화면 확인. 번들한 WASM 엔진(Skia CanvasKit, H.264 MP4 인코더)과 Noto 글꼴로 Chrome, ffmpeg, 설치, 내려받기 없이 모든 OS 에서 같게 렌더. 다른 종류는 `motion-graphic-make`, `3d-intro-build`, `motion-sites` 로 넘김 |
184
187
  | `motion-graphic-make` | 10초 내외 내레이션 없는 무료 모션 그래픽 제작 (hyperframes 위임). 계획 승인, 스냅숏과 렌더 검토 페이지, 독립 검증, 사이트 배치는 선택 |
185
188
  | `motion-sites` | MotionSites 의 `motionsites-web-builder` 스킬을 짧은 이름으로 부름. 첫 실행 때 원본 플러그인을 MotionSites 마켓플레이스에서 설치하고 Playwright 와 Chromium 을 갖춘 뒤 프롬프트를 그대로 넘김. 원본은 banker 에 복사하지 않음(예시와 미디어 재배포 금지), 첫 실행에 네트워크 필요 |
186
189
  | `3d-intro-build` | 스크롤-스크럽 3D 인트로 사이트 제작 (Azure gpt-image 스틸 + WAN 키 풀 영상, 소진 시 Sora-2 폴백, 유료). 단계별 검토 페이지, 엄격한 CSP 에서 도는 페이지, 실제 브라우저 독립 검증. 영상 모드는 chain, dive 나가기 없음(기본), dive 나가기 있음 가운데 고름. 장면 단위 이동(장면 시작점에 멈춤, Home, End, 장면 점은 바로 이동)은 기본 켬이고 끌 수 있음, 기존 사이트 통합은 선택 |
@@ -461,8 +464,9 @@ banker setup
461
464
  - `npx` 로 부르는 도구(`motion-graphic-make` 의 hyperframes 등): 전역 설치가 없으면 패키지를 받으려 해, 네트워크가 없으면 약 70초 뒤 실패합니다. 오프라인에서는 전역 설치한 실행 파일을 부릅니다.
462
465
  - 유료 API 를 부르는 `3d-intro-build`(요청마다 시간 제한), `ralph-qa` 의 외부 좌석(codex, gemini, opencode, 좌석마다 600초)
463
466
  - `build-testbox`: `run` 은 내려받지 않고, 없는 이미지, 브라우저, 엔진의 칸은 `unverified` 와 setup 할 항목으로 끝납니다. `setup` 은 `--yes` 확인 뒤에만 받고, 원천에 닿지 못하면 받지 않고 "네트워크 필요" 로 끝납니다.
467
+ - `wbs-gen` 의 공휴일 조회(Google 공개 캘린더): 닿지 못하면 기다리지 않고 종료 코드 3 으로 끝나고, 스킬이 사용자에게 공휴일을 `월/일, 월/일` 로 받습니다. 공휴일 표를 지어내지 않습니다.
464
468
  - `vertical-pptx`, `pdf-vision-extract` 가 빠진 도구를 설치하라고 안내할 때, `nothing-design` 의 글꼴(Google Fonts. 받지 못하면 대체 글꼴로 보임)
465
- - 네트워크를 쓰지 않는 스킬(예: `lineage`, `setup-omc-hud`, `tone-compact`, `anti-drm`, `payload-mon`, `init-dir`, `git-init`, `tune-tmux`)은 네트워크 없이 그대로 씁니다.
469
+ - 네트워크를 쓰지 않는 스킬(예: `lineage`, `setup-omc-hud`, `tone-compact`, `anti-drm`, `payload-mon`, `init-dir`, `git-init`, `tune-tmux`, `wide-pptx`, `video-gen`)은 네트워크 없이 그대로 씁니다.
466
470
 
467
471
  ## 라이선스 / 서드파티
468
472
 
@@ -479,8 +483,16 @@ banker 자체는 **MIT** ([LICENSE](LICENSE)). Owner: [smallOpenSource](https://
479
483
  - `skills/theme-selection/assets`: 번들 팔레트(`palettes.json`)는 [VoltAgent/awesome-design-md](https://github.com/VoltAgent/awesome-design-md) 의 DESIGN.md 에서 색 값을 읽어 만든 것, **MIT License**(© 2026 VoltAgent).\
480
484
  원본 라이선스 고지는 `skills/theme-selection/assets/LICENSE` 와 `NOTICE.md` 에 포함.\
481
485
  테마 이름의 상표는 각 소유자에게 있으며, banker 는 그 회사들과 관계가 없습니다.
482
-
483
- 코드로 포함(재배포)하는 서드파티는 `humanizer` 와 `scroll-world`(`3d-intro-build`) 둘이고, 데이터로 포함하는 것은 `awesome-design-md`(`theme-selection`) 하나입니다.\
486
+ - `skills/wide-pptx/vendor`: [PptxGenJS](https://github.com/gitbrent/PptxGenJS) 4.0.1 의 `pptxgen.bundle.js` 를 고치지 않고 벤더링, **MIT License**.\
487
+ 안에 든 JSZip(MIT 또는 GPLv3 중 MIT), pako(MIT), core-js 등의 고지는 같은 폴더의 `LICENSE-*.md` 와 `THIRD-PARTY-NOTICES.md` 에 포함.
488
+ - `skills/video-gen/vendor`: 아래를 고치지 않고 벤더링. 파일별 판과 sha256 은 `skills/video-gen/vendor/README.md`.
489
+ - [Skia CanvasKit](https://skia.org/docs/user/modules/canvaskit/) 0.42.0(`canvaskit-wasm`), **BSD-3-Clause**. 안에 든 ICU, FreeType, HarfBuzz, libpng, zlib 등의 고지는 `canvaskit/THIRD-PARTY-NOTICES.md`.
490
+ - [h264-mp4-encoder](https://github.com/TrevorSundberg/h264-mp4-encoder) 1.0.12, **MIT License**. 안의 minih264 는 public domain(CC0), libmp4v2 는 **Mozilla Public License 1.1**(전문 `h264-mp4-encoder/MPL-1.1.md`).\
491
+ libmp4v2 소스 묶음은 GitHub 저장소의 `third_party/libmp4v2-d49b4466.tar.gz` 에 둡니다(npm 묶음에는 넣지 않음).
492
+ - [Noto Sans](https://notofonts.github.io/), [Noto Sans KR](https://github.com/notofonts/noto-cjk) 글꼴, **SIL Open Font License 1.1**(`fonts/OFL-*.md`).
493
+ - `scripts/vg-fx.mjs` 의 동작 도우미 일부는 [kstost/cokacmotion](https://github.com/kstost/cokacmotion) 의 aimotion 에서 옮긴 것, **MIT License**(`aimotion/LICENSE.md`).
494
+
495
+ 코드로 포함(재배포)하는 서드파티는 `humanizer`, `scroll-world`(`3d-intro-build`), `omc_hud`(`setup-omc-hud`), PptxGenJS(`wide-pptx`), CanvasKit 과 h264-mp4-encoder 와 aimotion 도우미(`video-gen`)이고, 데이터로 포함하는 것은 `awesome-design-md`(`theme-selection`)와 Noto 글꼴(`video-gen`)입니다.\
484
496
  아래는 스킬이 **런타임에 의존하거나 연동**하는 외부 요소로, banker 가 재배포하지 않으며 각 라이선스·상표는 소유자에게 있습니다.
485
497
 
486
498
  **의존 라이브러리·도구 (사용 시 별도 설치, 라이선스는 각 프로젝트 소유)**
@@ -81,6 +81,9 @@
81
81
  { "name": "build-testbox", "type": "skill", "target": "both", "reason": "a test environment this machine builds from its own resources: a browser matrix (Playwright Chromium and WebKit, desktop and mobile device emulation) against a loopback URL and container OSes (Rocky Linux 8, 9; macOS only as a Tart VM on Apple Silicon) run in parallel, every requested cell kept as a pass, fail, unverified or unsupported row with a reason, results.json and summary.md; detect, run, setup; pure Node, no deps", "supportingFiles": ["scripts/testbox.mjs","scripts/args.mjs","scripts/detect.mjs","scripts/browsers.mjs","scripts/browser-cell.mjs","scripts/containers.mjs","scripts/setup.mjs","scripts/report.mjs","scripts/proc.mjs"], "caveat": "Playwright (a global install, or the project's with --playwright-from-project) and docker or podman are optional; a missing one leaves its cells unverified with the reason; run downloads nothing (a missing image or browser build is unverified, never pulled); setup only lists what it would fetch and its rough size, and fetches after the user confirms and it runs again with --yes (exit 4 and network needed when the sources are unreachable); macOS runs only as a Tart VM on an Apple Silicon host (other hosts are unsupported under the Apple SLA), and the skill never downloads or starts the VM; on Codex detect and run ask for sandbox_permissions require_escalated for the container engine and the headless browsers, the server under test on a 127.0.0.1 port is the user's own (approved where it is started), and setup --yes, or a container command that uses the network, asks for network access (--network host lifts that cell's isolation, and the user is told)" },
82
82
  { "name": "tune-tmux", "type": "skill", "target": "both", "reason": "adds or removes one marked block in the tmux or psmux config file so mouse drag copies to the OS clipboard and PageUp/PageDown scroll inside tmux, without taking keys or the mouse from full-screen apps; status shows the chosen file, the lines and why any are left out, conflicts in other files tmux reads, and per-app behavior (Claude Code, Codex); first original kept, off removes only the block, --reload applies it to a running server; pure Node, no deps, no network", "supportingFiles": ["scripts/tune-tmux.mjs","scripts/tmux-config.mjs","scripts/app-notes.mjs","scripts/marker-block.mjs","scripts/psmux-caps.json"], "caveat": "needs tmux or psmux (install with setup-tmux; status alone works without them); it writes the user's config file outside the workspace (~/.tmux.conf or the XDG tmux.conf, ~/.psmux.conf for psmux), keeping the first original as <conf>.tune-tmux.bak, so on Codex on, off and --reload ask for sandbox_permissions require_escalated (no --add-dir); a config file that is a symbolic link is refused unless --follow-symlink; psmux gets a block of zero lines today (its defaults give mouse, set-clipboard and wheel copy-mode; drag to the Windows clipboard and PageUp/PageDown inside full-screen apps are unverified; outside apps PageUp needs the prefix, PageDown does not leave copy-mode at the bottom and #{alternate_on} is always 0), so on reports the unverified and broken counts with exit 0 and only takes out an old tune-tmux block left in that file; inside full-screen apps (Claude Code fullscreen, Codex Fullscreen) the app keeps PageUp/PageDown and the mouse, and tmux copy-mode cannot scroll Codex history, a limit tmux config cannot fix; it never changes Claude Code or Codex settings" },
83
83
  { "name": "make-evidence", "type": "skill", "target": "both", "reason": "writes six evidence documents for a built service from real runs and commits them under docs/evidence/ (optimize, verify, flow, scale, decisions, trace) with scripts/evidence.mjs: run records each command (quoted command line, HEAD and dirty count, both streams with common secret forms masked, exit code passed through, stdin closed, a time limit that ends the process tree, no overwrite), measured numbers are METRIC name=value lines that check matches exactly against the log a document line names, room and collect give the oracle writer (a fresh-context sub-agent with a fixed prompt) a folder outside the repository holding only the requirement document and the owner facts, worktree and bug put each seeded bug (constraint, objective, permission) into a separate worktree of HEAD and judge it by ORACLE lines against a baseline (caught, missed, undecidable) while the user's work tree is left as it was, precheck stops on staged changes and asks about uncommitted ones and config hosts that are not this machine, commit takes only docs/evidence and tests/oracle (ignored logs included, hooks not skipped); --oracle-only writes the oracle before implementation; never edits the implementation, installs, downloads or pushes", "supportingFiles": ["scripts/evidence.mjs", "scripts/me-git.mjs", "scripts/me-run.mjs", "scripts/me-precheck.mjs", "scripts/me-check.mjs", "scripts/me-oracle.mjs", "scripts/me-commit.mjs"], "caveat": "the project supplies the server, its tests and the tools; a missing tool, a server that cannot be reached or a non-local config is written as unverified, never filled from unit tests; the sub-agent's list of files read is its own report, and context the runtime adds (the session folder's CLAUDE.md or AGENTS.md, memory) is written down as a limit; on Codex worktree, bug, commit, serve, stop and runs that reach a local server or DB ask for sandbox_permissions require_escalated" },
84
+ { "name": "wide-pptx", "type": "skill", "target": "both", "reason": "makes a 16:9 presentation from one deck (JSON) as PPTX and as one self-contained HTML deck with scripts/wide-pptx.mjs: title, section, bullets, two columns, table, chart (bar, line, pie), image, quote and closing slides with speaker notes, the same fixed layout in both (13.333 x 7.5 in, 1280 x 720 px); the PPTX comes from the bundled PptxGenJS 4.0.1 (vendor/pptxgen.bundle.js, MIT, loaded in a node:vm context of its own (a loading context, not a security boundary) because the browser bundle exports JSZip alone under require), then its theme is patched to Latin Noto Sans and Hangul Noto Sans KR and chart text from Arial to the same; the HTML has its own small script (arrows, space, Home/End, click, N for notes), inline SVG charts, data-URI images and 16:9 print pages; local PNG, JPEG and GIF images only (type from the first bytes); check warns where text may overflow its box; existing outputs are kept unless --force; no install, no download", "supportingFiles": ["scripts/wide-pptx.mjs", "scripts/wp-model.mjs", "scripts/wp-pptx.mjs", "scripts/wp-html.mjs", "scripts/wp-svg.mjs", "assets/example.json", "vendor/pptxgen.bundle.js", "vendor/LICENSE-pptxgenjs.md", "vendor/LICENSE-jszip.md", "vendor/LICENSE-pako.md", "vendor/THIRD-PARTY-NOTICES.md", "vendor/README.md"], "caveat": "no font file is embedded, so a viewer without Noto Sans and Noto Sans KR shows other fonts and wraps lines differently; text longer than its box overflows (check warns, the skill splits the slide); A4 portrait print documents belong to vertical-pptx" },
85
+ { "name": "video-gen", "type": "skill", "target": "both", "reason": "shows what videos can be made, lets the user pick, interviews for missing content, then renders an H.264 MP4 with scripts/video-gen.mjs and its bundled engine: Skia CanvasKit 0.42.0 (WASM, BSD-3), h264-mp4-encoder 1.0.12 (WASM; minih264 public domain, libmp4v2 MPL 1.1 with its source kept in third_party/ and named in vendor/README.md) and Noto Sans / Noto Sans KR (OFL), so no Chrome, ffmpeg, native module, install or network on any OS; built-in kinds title, kinetic type, slides (a wide-pptx deck through from-deck), chart (bar, line), counter, lower third, quote, image (zoom, pan) and credits with cut, fade, wipe and stripes transitions; text asks for Noto Sans first so Hangul falls to Noto Sans KR; every frame is a pure function of time (still renders any frame); motion helpers partly from aimotion (kstost/cokacmotion, MIT); HTML motion graphics, AI 3D intros and motion sites hand over to motion-graphic-make, 3d-intro-build and motion-sites; existing outputs are kept unless --force", "supportingFiles": ["scripts/video-gen.mjs", "scripts/vg-model.mjs", "scripts/vg-engine.mjs", "scripts/vg-draw.mjs", "scripts/vg-scenes.mjs", "scripts/vg-render.mjs", "scripts/vg-fx.mjs", "scripts/vg-deck.mjs", "scripts/vg-catalog.mjs", "assets/example.json", "vendor/README.md", "vendor/canvaskit/canvaskit.js", "vendor/canvaskit/canvaskit.wasm", "vendor/canvaskit/LICENSE.md", "vendor/canvaskit/THIRD-PARTY-NOTICES.md", "vendor/h264-mp4-encoder/h264-mp4-encoder.node.js", "vendor/h264-mp4-encoder/LICENSE.md", "vendor/h264-mp4-encoder/MPL-1.1.md", "vendor/fonts/NotoSans-Regular.ttf", "vendor/fonts/NotoSans-Bold.ttf", "vendor/fonts/NotoSansKR-Regular.otf", "vendor/fonts/NotoSansKR-Bold.otf", "vendor/fonts/OFL-noto-sans.md", "vendor/fonts/OFL-noto-sans-kr.md", "vendor/aimotion/LICENSE.md"], "caveat": "about 20 MB of vendored engine and fonts; rendering is on the CPU; no audio; images are local PNG, JPEG, GIF or WebP up to 20 MB" },
86
+ { "name": "wbs-gen", "type": "skill", "target": "both", "reason": "draws a WBS plan (JSON) as one Gantt sheet in XLSX and self-contained HTML with scripts/wbs-gen.mjs, pure Node with no dependency: working-day columns only (weekends and holidays left out), week headers, 8 fixed columns frozen with 3 header rows, bars as plain cell fills (no conditional formatting), part colours, diamonds for milestones and constraints, red gate lines, legend and notes, A3 landscape one page wide with print titles; the XLSX package (shared strings, styles, ZIP with its own CRC-32) is written by the helper; holidays come from Google's public Korean holiday calendar (holidays only, not observances) shown to the user to confirm, or from the user as M/D, M/D when the calendar cannot be reached; existing outputs are kept unless --force", "supportingFiles": ["scripts/wbs-gen.mjs", "scripts/wg-dates.mjs", "scripts/wg-plan.mjs", "scripts/wg-xlsx.mjs", "scripts/wg-zip.mjs", "scripts/wg-html.mjs", "scripts/wg-holidays.mjs", "assets/example.json"], "caveat": "on Codex the holidays command needs the network and asks for sandbox_permissions require_escalated; refused or offline means the user types the holidays; Hangul is set in Noto Sans KR and the rest in Noto Sans (XLSX rich-text runs per script, HTML font order), no font file is embedded, so a viewer without them shows another font; plans span at most five years, and a month/day that falls in two years of the range must be written as YYYY-MM-DD" },
84
87
 
85
88
  { "name": "front-qa", "type": "command", "target": "both", "reason": "ralplan->ralph frontend-QA pipeline; Claude=OMC, Codex=OMX", "supportingFiles": [] },
86
89
  { "name": "setup", "type": "command", "target": "both", "reason": "installer orchestrator; Claude AskUserQuestion multi-select, Codex prompt-based selection", "supportingFiles": [], "codexDescription": "구성요소와 의존성을 여러 개 골라 설치하는 오케스트레이터. 런타임(Node, Python, Java), LSP, tmux, MCP, 샌드박스, OMX, Playwright 등. 권한 확인 끄기는 따로 묻고 기본으로 고르지 않으며, 골라도 실행하지 않고 직접 입력할 명령만 안내." },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaydash9999/banker-plugins",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "banker — Claude Code + Codex CLI plugin (QA, audit, docs, architecture, wiki skills). Install via Claude Code marketplace, or `npm i -g @kaydash9999/banker-plugins` then `banker setup`.",
5
5
  "bin": {
6
6
  "banker": "bin/banker.js"
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: video-gen
3
+ description: "만들 수 있는 영상 목록을 보여 주고 고르게 한 뒤, 내용을 받지 않았으면 인터뷰해서 영상을 만듦. 내장 종류는 타이틀, 키네틱 타이포, 슬라이드 영상, 차트, 카운터, 이름 자막, 인용, 사진, 크레딧. 스킬 안의 WASM 엔진과 Noto 글꼴로 설치와 내려받기 없이 MP4 를 만듦. HTML 모션 그래픽, AI 3D 인트로, 모션 웹사이트는 해당 banker 스킬로 넘김. 'video-gen'/'영상 만들어'/'동영상 생성'/'소개 영상'/'모션 영상' 시 사용."
4
+ argument-hint: "[<종류>] [--dir <폴더>] [--scene <scene.json>] [--deck <deck.json>] [--size 1280x720|1920x1080|1080x1920|1080x1080]"
5
+ ---
6
+
7
+ # video-gen: 영상 목록, 인터뷰, MP4 생성
8
+
9
+ 만들 수 있는 영상을 보여 주고, 고른 종류에 맞는 내용을 받아 MP4 를 만든다. 답변은 한글.
10
+
11
+ ## 원칙
12
+
13
+ - **내장 종류는 설치와 내려받기 없이 모든 OS 에서 만든다.** 렌더 엔진(Skia CanvasKit WASM), H.264 MP4 인코더(WASM), 글꼴(Noto Sans, Noto Sans KR)이 모두 `vendor/` 에 있다. Chrome, ffmpeg, 네이티브 모듈, 인터넷을 쓰지 않는다.
14
+ - **글꼴은 한글 Noto Sans KR, 그 밖(영문, 숫자, 기호) Noto Sans 다.** 엔진이 글자마다 고른다. 글꼴이 파일 안에 있어 어느 PC 에서나 같게 나온다.
15
+ - **프레임은 시간만의 함수다.** 같은 장면 파일은 같은 영상이 되고, 정지 화면(`still`)은 `--at` 에 가장 가까운 영상 프레임과 같다(출력의 `FRAME` 줄이 그 번호).
16
+ - 사용자가 주지 않은 수치, 이름, 인용을 지어내지 않는다. 모자라면 묻는다. 물을 수 없으면 `[확인 필요]` 로 두고 보고한다.
17
+ - 있는 파일을 덮어쓰지 않는다. 같은 이름이 있으면 묻고, 허락을 받은 뒤에만 `--force` 를 준다.
18
+
19
+ ## 런타임
20
+
21
+ | 항목 | Claude Code | Codex |
22
+ |---|---|---|
23
+ | 스킬 디렉터리 `<S>` | 스킬 맨 위 "Base directory for this skill:" 경로 | 이 SKILL.md 의 폴더. npm 설치는 `~/.codex/skills/banker-video-gen/`, 플러그인 설치는 `~/.codex/plugins/cache/<마켓플레이스>/banker/<판>/skills/video-gen/`. 절대경로로 씀 |
24
+ | 부르기 | `/banker:video-gen` | `$banker-video-gen`, 플러그인 `$banker:video-gen` |
25
+ | 확인 질문 | `AskUserQuestion` | `request_user_input`. 없으면 번호 붙인 평문 선택지 |
26
+ | 샌드박스 | 없음 | 도우미는 작업 폴더 안에서만 읽고 써서 승인이 필요 없음. 작업 폴더 밖 사진은 `sandbox_permissions: "require_escalated"` 로 승인을 청하거나 작업 폴더로 복사해 씀 |
27
+ | 긴 렌더 | Bash 도구 `timeout` 을 넉넉히(최대 600000), 더 길면 `run_in_background` | `timeout_ms` 를 같은 값으로 |
28
+
29
+ 물을 수 없는 실행(`codex exec`, 다른 스킬의 연쇄)에서는 목록과 인터뷰를 건너뛰고, 받은 자료로 고를 수 있는 종류 하나를 정해 만든다.
30
+
31
+ ## 인자
32
+
33
+ | 인자 | 뜻 |
34
+ |---|---|
35
+ | `<종류>` | 목록의 종류 id(예: `kinetic`, `slides`). 없으면 목록을 보여 주고 고르게 함 |
36
+ | `--dir <폴더>` | 출력 폴더. 없으면 지금 작업 폴더. 도우미의 `--out <파일>` 과 다름 |
37
+ | `--scene <scene.json>` | 이미 있는 장면 파일을 씀 |
38
+ | `--deck <deck.json>` | wide-pptx 덱을 슬라이드 영상으로 바꿈 |
39
+ | `--size` | 화면 크기. 기본 `1280x720`. 세로 영상은 `1080x1920` |
40
+
41
+ ## 도우미
42
+
43
+ `G="<S>/scripts/video-gen.mjs"`. 머리 주석이 전체 사용법이다.
44
+
45
+ | 명령 | 하는 일 | 종료 코드 |
46
+ |---|---|---|
47
+ | `node "$G" list` | 영상 목록(종류, 만드는 곳, 설명, 필요한 것) | 0 |
48
+ | `node "$G" example` | 예시 장면 파일(JSON). 틀로 씀 | 0 |
49
+ | `node "$G" from-deck --deck <deck.json>` | wide-pptx 덱을 장면 파일로 바꿔 stdout 에 냄. 원 차트는 막대로 바꾸고 경고 | 0, 파일 오류 2 |
50
+ | `node "$G" check --scene <scene.json>` | 검사하고 `OK 장면 N, 길이, 크기, fps, 프레임` 을 냄. 그림은 엔진으로 실제로 풀어 보고, 글은 내장 글꼴로 재서 화면을 넘을 곳을 `경고:` 로 냄 | 0, 장면 오류 1 |
51
+ | `node "$G" still --scene <scene.json> --at <초> --out <파일.png>` | 그 시각에 가장 가까운 영상 프레임 한 장. `--at` 이 영상 길이 이상이면 오류 | 0, 1, 2 |
52
+ | `node "$G" render --scene <scene.json> --out <파일.mp4>` | MP4 를 만듦. 진행은 stderr 에 1초마다. `--quality <10-51>`(기본 20, 작을수록 고화질) | 0, 1, 2 |
53
+
54
+ - 렌더는 CPU 로 한다. 1920x1080 은 1280x720 보다 두 배 넘게 걸린다. 처음 몇 초의 진행 줄로 남은 시간을 어림해 사용자에게 알린다.
55
+
56
+ ## 영상 목록
57
+
58
+ `node "$G" list` 가 같은 표를 낸다.
59
+
60
+ | 종류 | 만드는 곳 | 필요한 것 |
61
+ |---|---|---|
62
+ | `title` 모션 타이틀 | 내장 | 제목, 부제 |
63
+ | `kinetic` 키네틱 타이포 | 내장 | 문장 1~6줄 |
64
+ | `slides` 슬라이드 영상 | 내장(`from-deck` 또는 장면별 글머리) | 덱 파일 또는 제목과 글머리 |
65
+ | `chart` 데이터 차트 | 내장 | 항목, 계열 값, 단위 |
66
+ | `counter` 숫자 카운터 | 내장 | 시작 값, 끝 값, 단위, 설명 |
67
+ | `lowerthird` 이름 자막 | 내장 | 이름, 직함, 배경 사진(선택) |
68
+ | `quote` 인용 | 내장 | 인용문, 출처 |
69
+ | `image` 사진 장면 | 내장 | 로컬 사진(PNG, JPEG, GIF, WebP), 캡션 |
70
+ | `credits` 엔딩 크레딧 | 내장 | 제목, 줄 목록 |
71
+ | `motion-graphic` HTML 모션 그래픽 | `motion-graphic-make` 스킬 | HyperFrames, Chrome, ffmpeg 가 있는 PC |
72
+ | `3d-intro` AI 3D 인트로 | `3d-intro-build` 스킬 | Azure 키(유료), 인터넷 |
73
+ | `motion-site` 모션 웹사이트 | `motion-sites` 스킬 | 주제와 내용 |
74
+
75
+ 한 영상에 여러 종류를 장면으로 이어 붙일 수 있다(예: 타이틀, 차트, 크레딧).
76
+
77
+ ## 장면 파일(scene.json)
78
+
79
+ | 칸 | 뜻 |
80
+ |---|---|
81
+ | `title` | 영상 제목(보고용) |
82
+ | `size` | `1280x720`(기본), `1920x1080`, `1080x1920`, `1080x1080` |
83
+ | `fps` | 12~60 정수, 기본 30 |
84
+ | `theme` | `bg`(바탕), `fg`(글), `accent`(강조), `muted`(보조 글), `panel`, `ink`(자막 띠). 6자리 16진수 |
85
+ | `scenes` | 장면 목록. 모두 `duration`(0.5~60초, 기본 4)과 `transition`(`cut`, `fade`(기본), `wipe`, `stripes`)을 받음. 전체 600초까지 |
86
+
87
+ | type | 칸 |
88
+ |---|---|
89
+ | `title` | `title`, `subtitle` |
90
+ | `kinetic` | `lines`(1~6줄) |
91
+ | `bullets` | `title`, `bullets`(7개까지 권장) |
92
+ | `chart` | `title`, `chart`(`kind`: bar, line / `labels` / `series`: `[{ "name", "values" }]` / `unit`). 값은 숫자만 |
93
+ | `counter` | `label`, `from`(기본 0), `to`, `unit` |
94
+ | `lowerthird` | `name`, `role`, `image`(배경, 선택) |
95
+ | `quote` | `quote`, `by` |
96
+ | `image` | `image`, `caption`, `motion`(`zoom` 기본, `pan`) |
97
+ | `credits` | `title`, `lines` |
98
+
99
+ 사진 경로는 장면 파일 폴더 기준이다. URL 은 받지 않는다. 그림은 한 변 16384, 50MP 까지이고, 잘린 파일은 오류다.
100
+ 들어오는 효과의 간격은 장면 길이에 맞춰 줄어, 장면이 끝나기 0.3초 전에는 모두 보인다. 빈 글 항목은 빼고 경고한다.
101
+
102
+ ## 절차
103
+
104
+ ### 1. 종류 고르기
105
+ - 인자에 종류가 없으면 `node "$G" list` 를 돌려 표를 보여 주고 확인 질문으로 고르게 한다. 질문 하나에 선택지는 4개까지라, 사용자의 말에 맞는 종류 3개와 "다른 종류" 를 낸다. 여러 종류를 이은 영상도 고를 수 있다고 알린다.
106
+ - 고른 것이 다른 스킬 종류(`motion-graphic`, `3d-intro`, `motion-site`)면 그 스킬로 넘기고 이 스킬은 끝낸다. `motion-graphic` 은 렌더 엔진이 없으면 내장 종류로 비슷하게 만들 수 있다고 함께 알린다.
107
+
108
+ ### 2. 인터뷰
109
+ - 고른 종류의 "필요한 것" 가운데 받지 않은 것만 한 번에 묻는다(확인 질문 하나에 최대 4문항). 목적, 길이(초), 화면 크기(가로, 세로)도 정해지지 않았으면 함께 묻는다.
110
+ - 색과 장면 전환은 묻지 않고 기본값을 쓴다. 사용자가 색을 말하면 `theme` 에 넣는다.
111
+ - `slides` 에 덱 파일이 있으면 `from-deck` 로 바꾸고, 바뀐 장면 목록을 보여 준다.
112
+
113
+ ### 3. 장면 파일 쓰기
114
+ - 출력 폴더에 `<이름>-scene.json` 으로 쓴다. 같은 이름이 있으면 묻는다.
115
+ - 장면 길이는 글을 읽을 시간을 준다(글머리 하나에 1.2초 안팎, 제목 3~4초).
116
+ - `node "$G" check --scene <파일>` 이 0 이 될 때까지 고친다. `경고:` 는 나누거나 줄여서 없앤다.
117
+
118
+ ### 4. 미리 보기
119
+ - 장면마다 가운데 시각과 끝나기 0.1초 전 시각을 골라 `still` 로 PNG 를 만들고 본다(그림을 볼 수 있으면). 글이 넘치거나 겹치면 장면 파일을 고친다.
120
+ - 미리 보기 PNG 는 출력 폴더 안 `<이름>-preview/` 에 두고, 보고에 경로를 적는다.
121
+
122
+ ### 5. 렌더
123
+ - `node "$G" render --scene <파일> --out <이름>.mp4` 를 돈다. 오래 걸리면 백그라운드로 돌리고 진행 줄을 본다.
124
+ - 종료 코드 2 에 `--force` 안내가 나오면 덮어쓸지 묻고, 허락을 받은 뒤에만 `--force` 를 더한다.
125
+ - 출력의 `OK ...` 줄에서 프레임 수가 장면 길이 x fps 와 같은지 본다.
126
+
127
+ ## 보고
128
+
129
+ - 만든 MP4 와 미리 보기 PNG 의 절대경로, 길이, 크기, fps, 파일 크기
130
+ - 장면 목록(종류와 길이)
131
+ - 확인하지 못한 것(재생기로 직접 보지 않음 등), `[확인 필요]` 자리
132
+ - 다음 행동이 있으면 마지막 줄에. 예: "고칠 곳은 `<이름>-scene.json` 을 고치고 다시 부르십시오."
133
+
134
+ ## 함정
135
+
136
+ - 소리는 넣지 않는다. 배경 음악은 영상 편집기에서 더한다.
137
+ - 사진은 20MB 까지, PNG, JPEG, GIF(첫 프레임), WebP 만. 휴대폰 사진의 회전 정보(EXIF)는 엔진이 적용한다.
138
+ - 엔딩 크레딧은 장면 끝에서 화면 위로 다 빠져나간다. 마지막 장면이면 영상 끝은 바탕색이다.
139
+ - 내장 글꼴에 없는 글자(일부 이모지, 드문 한자)는 빈 네모로 나온다.
140
+ - `vendor/` 의 파일은 고치지 않는다. 시험이 sha256 을 대조한다.
141
+ - 키네틱 기법 일부는 aimotion(kstost/cokacmotion, MIT)의 도우미 코드를 옮겨 썼다. 고지는 `vendor/aimotion/LICENSE.md`, 출처는 `scripts/vg-fx.mjs` 머리에 있다.
@@ -0,0 +1,36 @@
1
+ {
2
+ "title": "샘플 대시보드 2차 개발 소개",
3
+ "size": "1280x720",
4
+ "fps": 30,
5
+ "theme": { "bg": "1F3864", "accent": "2E86C1" },
6
+ "scenes": [
7
+ { "type": "title", "duration": 3.5, "title": "샘플 대시보드 2차 개발", "subtitle": "요건 확정부터 운영 배포까지", "transition": "cut" },
8
+ { "type": "kinetic", "duration": 3.5, "lines": ["작은 개선이", "큰 차이를 만든다"], "transition": "stripes" },
9
+ {
10
+ "type": "bullets",
11
+ "duration": 5,
12
+ "title": "이번 개발의 범위",
13
+ "bullets": ["요건과 UI 확정", "API 리팩터링과 대시보드 웹", "계열사 지표(선택)"],
14
+ "transition": "fade"
15
+ },
16
+ {
17
+ "type": "chart",
18
+ "duration": 5,
19
+ "title": "파트별 투입 영업일",
20
+ "chart": {
21
+ "kind": "bar",
22
+ "unit": "영업일",
23
+ "labels": ["기획", "데이터", "백엔드", "프론트", "AI"],
24
+ "series": [
25
+ { "name": "필수", "values": [6, 4, 9, 9, 7] },
26
+ { "name": "선택", "values": [0, 5, 0, 5, 0] }
27
+ ]
28
+ },
29
+ "transition": "wipe"
30
+ },
31
+ { "type": "counter", "duration": 3, "label": "2차 개발 영업일", "from": 0, "to": 27, "unit": "일", "transition": "fade" },
32
+ { "type": "lowerthird", "duration": 3.5, "name": "홍길동", "role": "기획팀장", "transition": "fade" },
33
+ { "type": "quote", "duration": 4, "quote": "요건 확정 전에는 요건에 기대지 않는 일부터 한다", "by": "프로젝트 운영 원칙", "transition": "fade" },
34
+ { "type": "credits", "duration": 5, "title": "함께한 사람들", "lines": ["기획 홍길동", "데이터 김철수", "엔지니어링 이영희", "백엔드 박민수", "프론트엔드 최지우", "AI 에이전트 정하늘"], "transition": "fade" }
35
+ ]
36
+ }
@@ -0,0 +1,23 @@
1
+ // vg-catalog.mjs: what video-gen can make. Built-in kinds render here with the bundled WASM engine; the others
2
+ // hand over to another banker skill. `video-gen.mjs list` prints this table.
3
+
4
+ export const CATALOG = [
5
+ { id: "title", name: "모션 타이틀", how: "내장", what: "제목과 부제가 강조 막대와 함께 들어오는 짧은 오프닝", needs: "제목, 부제(선택)" },
6
+ { id: "kinetic", name: "키네틱 타이포", how: "내장", what: "글자가 한 자씩 튀어 오르며 문장이 완성되는 장면", needs: "문장 1~6줄" },
7
+ { id: "slides", name: "슬라이드 영상", how: "내장", what: "wide-pptx 덱이나 글머리 목록을 장면으로 바꾼 설명 영상", needs: "덱 파일 또는 장면별 제목과 글머리" },
8
+ { id: "chart", name: "데이터 차트", how: "내장", what: "막대가 자라거나 꺾은선이 그려지는 수치 영상", needs: "항목 이름, 계열 값, 단위" },
9
+ { id: "counter", name: "숫자 카운터", how: "내장", what: "큰 숫자가 올라가며 강조되는 장면", needs: "시작 값, 끝 값, 단위, 설명" },
10
+ { id: "lowerthird", name: "이름 자막", how: "내장", what: "인물 이름과 직함 띠가 들어왔다 나가는 장면(배경 그림 선택)", needs: "이름, 직함, 배경 그림(선택)" },
11
+ { id: "quote", name: "인용", how: "내장", what: "따옴표와 인용문이 떠오르는 장면", needs: "인용문, 출처" },
12
+ { id: "image", name: "사진 장면", how: "내장", what: "사진을 천천히 확대하거나 옆으로 흘리며 캡션을 붙인 장면", needs: "로컬 사진(PNG, JPEG, GIF, WebP), 캡션" },
13
+ { id: "credits", name: "엔딩 크레딧", how: "내장", what: "제목과 이름이 아래에서 위로 흐르는 마무리", needs: "제목, 줄 목록" },
14
+ { id: "motion-graphic", name: "HTML 모션 그래픽", how: "motion-graphic-make", what: "HyperFrames(HTML, CSS, GSAP) 블록으로 만드는 풍부한 모션 그래픽", needs: "HyperFrames 와 Chrome, ffmpeg 가 설치된 PC" },
15
+ { id: "3d-intro", name: "AI 3D 인트로", how: "3d-intro-build", what: "Azure 영상 생성 모델로 만드는 3D 인트로", needs: "Azure 키(유료), 인터넷" },
16
+ { id: "motion-site", name: "모션 웹사이트", how: "motion-sites", what: "영상이 아니라 스크롤로 움직이는 웹 페이지", needs: "주제와 내용" },
17
+ ];
18
+
19
+ /** The catalog as a text table for the terminal. */
20
+ export function catalogText() {
21
+ const rows = CATALOG.map((c) => `${c.id.padEnd(15)} ${c.how.padEnd(20)} ${c.name} - ${c.what} (필요: ${c.needs})`);
22
+ return `${"종류".padEnd(15)} ${"만드는 곳".padEnd(20)} 설명\n${rows.join("\n")}\n`;
23
+ }
@@ -0,0 +1,72 @@
1
+ // vg-deck.mjs: turns a wide-pptx deck (JSON) into a video-gen scene file, one scene per slide, so a presentation
2
+ // can also become a video. Slides that have no scene of their own become the closest one; nothing is invented.
3
+ import { isAbsolute, resolve, win32 } from "node:path";
4
+
5
+ const obj = (v) => (v && typeof v === "object" && !Array.isArray(v) ? v : {});
6
+ const str = (v) => (typeof v === "string" ? v : typeof v === "number" ? String(v) : "");
7
+ const bulletText = (b) => str(typeof b === "object" && b ? b.text : b);
8
+ const HEX = /^#?[0-9A-Fa-f]{6}$/;
9
+
10
+ function columns(s) {
11
+ return [obj(s.left), obj(s.right)].flatMap((c) => {
12
+ const items = (Array.isArray(c.bullets) ? c.bullets : []).map(bulletText).filter(Boolean);
13
+ return c.heading ? items.map((x) => `${str(c.heading)}: ${x}`) : items;
14
+ });
15
+ }
16
+
17
+ function tableRows(s) {
18
+ const head = Array.isArray(s.header) ? s.header.map(str) : [];
19
+ const rows = (Array.isArray(s.rows) ? s.rows : []).map((r) => (Array.isArray(r) ? r.map(str) : []));
20
+ return rows.map((r) => (head.length ? r.map((c, i) => (c && head[i] ? `${head[i]} ${c}` : c)) : r).filter(Boolean).join(" | ")).filter(Boolean);
21
+ }
22
+
23
+ const bulletsScene = (title, items) => ({ type: "bullets", title, bullets: items, duration: Math.min(20, 2 + 1.2 * items.length) });
24
+
25
+ function chartScene(s, skipped, i) {
26
+ const c = obj(s.chart);
27
+ if (c.kind === "pie") skipped.push(`slides[${i}]: 원 차트는 막대 차트로 바꿈`);
28
+ return { type: "chart", title: str(s.title), chart: { kind: c.kind === "line" ? "line" : "bar", labels: c.labels, series: c.series, unit: c.unit }, duration: 6 };
29
+ }
30
+
31
+ function imageScene(s, base) {
32
+ const p = str(s.image);
33
+ const abs = isAbsolute(p) || win32.isAbsolute(p) ? p : resolve(base, p);
34
+ return { type: "image", image: abs, caption: str(s.caption) || str(s.title), duration: 5 };
35
+ }
36
+
37
+ const MAP = {
38
+ title: (s) => ({ type: "title", title: str(s.title), subtitle: str(s.subtitle) || [str(s.presenter), str(s.date)].filter(Boolean).join(" | "), duration: 4 }),
39
+ section: (s) => ({ type: "title", title: str(s.title), subtitle: str(s.subtitle), duration: 3 }),
40
+ bullets: (s) => bulletsScene(str(s.title), (Array.isArray(s.bullets) ? s.bullets : []).map(bulletText).filter(Boolean)),
41
+ two: (s) => bulletsScene(str(s.title), columns(s)),
42
+ table: (s) => bulletsScene(str(s.title), tableRows(s)),
43
+ chart: chartScene,
44
+ image: (s, ...rest) => imageScene(s, rest[2]),
45
+ quote: (s) => ({ type: "quote", quote: str(s.quote), by: str(s.by), duration: 5 }),
46
+ closing: (s) => ({ type: "title", title: str(s.title), subtitle: str(s.subtitle), duration: 4 }),
47
+ };
48
+
49
+ function themeOf(t) {
50
+ const pick = (k, d) => (HEX.test(str(t[k])) ? str(t[k]).replace(/^#/, "").toUpperCase() : d);
51
+ return { bg: pick("primary", "1F3864"), accent: pick("accent", "2E86C1"), ink: pick("dark", "1B2631"), panel: pick("light", "F4F6F7"), fg: "FFFFFF", muted: "D6EAF8" };
52
+ }
53
+
54
+ const blank = (x) => !String(x ?? "").trim();
55
+ const emptyScene = (s) => ({ bullets: () => !s.bullets.length, quote: () => blank(s.quote), title: () => blank(s.title) }[s.type]?.() ?? false);
56
+
57
+ /** Returns { scenes: <scene file object>, skipped: [notes] }. base is the deck's folder (image paths). */
58
+ export function deckToScenes(deck, base = process.cwd()) {
59
+ const d = obj(deck);
60
+ const skipped = [];
61
+ const scenes = (Array.isArray(d.slides) ? d.slides : []).map((raw, i) => {
62
+ const s = obj(raw);
63
+ const f = Object.prototype.hasOwnProperty.call(MAP, s.type) ? MAP[s.type] : null;
64
+ if (!f) {
65
+ skipped.push(`slides[${i}]: 알 수 없는 type(${str(s.type)}) 은 뺌`);
66
+ return null;
67
+ }
68
+ const scene = { ...f(s, skipped, i, base), transition: i ? "fade" : "cut" };
69
+ return emptyScene(scene) ? (skipped.push(`slides[${i}]: 영상에 쓸 내용이 없어 뺌`), null) : scene;
70
+ }).filter(Boolean);
71
+ return { scenes: { title: str(d.title), size: "1280x720", fps: 30, theme: themeOf(obj(d.theme)), scenes }, skipped };
72
+ }