kasaframe 0.0.0-stage → 0.1.1

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 (338) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +146 -0
  3. package/README.md +77 -2
  4. package/app/package.json +12 -0
  5. package/app/server/engine.ts +415 -0
  6. package/app/server/main.ts +205 -0
  7. package/app/web/env.d.ts +2 -0
  8. package/app/web/icons.ts +31 -0
  9. package/app/web/index.html +21 -0
  10. package/app/web/main.ts +1013 -0
  11. package/app/web/style.css +430 -0
  12. package/bin/hooks.mjs +51 -0
  13. package/bin/kf.mjs +14 -0
  14. package/docs/AGENTS.md +238 -0
  15. package/music/README.md +13 -0
  16. package/package.json +44 -4
  17. package/packages/adapters/package.json +36 -0
  18. package/packages/adapters/src/css.ts +11 -0
  19. package/packages/adapters/src/gsap.ts +26 -0
  20. package/packages/adapters/src/index.ts +9 -0
  21. package/packages/adapters/src/lottie.ts +22 -0
  22. package/packages/adapters/src/media.ts +59 -0
  23. package/packages/adapters/src/page.ts +229 -0
  24. package/packages/adapters/src/project.ts +214 -0
  25. package/packages/adapters/src/react.ts +36 -0
  26. package/packages/adapters/src/svelte.ts +22 -0
  27. package/packages/adapters/src/three.ts +18 -0
  28. package/packages/adapters/src/vue.ts +27 -0
  29. package/packages/check/package.json +19 -0
  30. package/packages/check/src/check.ts +273 -0
  31. package/packages/check/src/cli.ts +70 -0
  32. package/packages/check/src/image.ts +146 -0
  33. package/packages/check/src/index.ts +9 -0
  34. package/packages/check/src/ocr.swift +37 -0
  35. package/packages/check/src/probe.ts +328 -0
  36. package/packages/check/src/report.ts +44 -0
  37. package/packages/check/src/rules/assets.ts +42 -0
  38. package/packages/check/src/rules/beats.ts +212 -0
  39. package/packages/check/src/rules/camera.ts +217 -0
  40. package/packages/check/src/rules/captions.ts +49 -0
  41. package/packages/check/src/rules/flash.ts +235 -0
  42. package/packages/check/src/rules/frames.ts +135 -0
  43. package/packages/check/src/rules/layout.ts +257 -0
  44. package/packages/check/src/rules/page.ts +87 -0
  45. package/packages/check/src/rules/runs.ts +20 -0
  46. package/packages/check/src/rules/text.ts +326 -0
  47. package/packages/check/src/scan.ts +240 -0
  48. package/packages/check/src/serve.ts +67 -0
  49. package/packages/check/src/types.ts +80 -0
  50. package/packages/check/src/video.ts +137 -0
  51. package/packages/cli/package.json +29 -0
  52. package/packages/cli/src/blur.ts +68 -0
  53. package/packages/cli/src/browser.ts +203 -0
  54. package/packages/cli/src/command.ts +44 -0
  55. package/packages/cli/src/commands/app.ts +25 -0
  56. package/packages/cli/src/commands/beats.ts +36 -0
  57. package/packages/cli/src/commands/blender.ts +270 -0
  58. package/packages/cli/src/commands/check.ts +25 -0
  59. package/packages/cli/src/commands/doctor.ts +22 -0
  60. package/packages/cli/src/commands/gen.ts +173 -0
  61. package/packages/cli/src/commands/look.ts +39 -0
  62. package/packages/cli/src/commands/lyrics.ts +111 -0
  63. package/packages/cli/src/commands/make.ts +542 -0
  64. package/packages/cli/src/commands/new.ts +176 -0
  65. package/packages/cli/src/commands/preview.ts +43 -0
  66. package/packages/cli/src/commands/render.ts +216 -0
  67. package/packages/cli/src/commands/setup.ts +63 -0
  68. package/packages/cli/src/commands/sheet.ts +114 -0
  69. package/packages/cli/src/commands/skill.ts +43 -0
  70. package/packages/cli/src/commands/still.ts +40 -0
  71. package/packages/cli/src/commands/theme.ts +85 -0
  72. package/packages/cli/src/commands/transitions.ts +40 -0
  73. package/packages/cli/src/deps.ts +122 -0
  74. package/packages/cli/src/ffmpeg.ts +81 -0
  75. package/packages/cli/src/index.ts +8 -0
  76. package/packages/cli/src/kf.ts +53 -0
  77. package/packages/cli/src/lock.ts +72 -0
  78. package/packages/cli/src/out.ts +13 -0
  79. package/packages/cli/src/serve.ts +124 -0
  80. package/packages/clock/package.json +14 -0
  81. package/packages/clock/src/index.ts +25 -0
  82. package/packages/clock/src/install.ts +351 -0
  83. package/packages/clock/src/types.ts +45 -0
  84. package/packages/core/package.json +9 -0
  85. package/packages/core/src/beats.ts +283 -0
  86. package/packages/core/src/ease.ts +87 -0
  87. package/packages/core/src/frame.ts +99 -0
  88. package/packages/core/src/index.ts +27 -0
  89. package/packages/core/src/project.ts +146 -0
  90. package/packages/core/src/rand.ts +56 -0
  91. package/packages/core/src/spring.ts +52 -0
  92. package/packages/core/src/style.ts +100 -0
  93. package/packages/core/src/time.ts +88 -0
  94. package/packages/gen/PROVIDERS.md +55 -0
  95. package/packages/gen/package.json +9 -0
  96. package/packages/gen/src/generate.ts +204 -0
  97. package/packages/gen/src/image/og.ts +133 -0
  98. package/packages/gen/src/index.ts +18 -0
  99. package/packages/gen/src/keys.ts +60 -0
  100. package/packages/gen/src/media.ts +150 -0
  101. package/packages/gen/src/plan.ts +106 -0
  102. package/packages/gen/src/registry.ts +51 -0
  103. package/packages/gen/src/seam.ts +103 -0
  104. package/packages/gen/src/types.ts +86 -0
  105. package/packages/gen/src/video/fal.ts +140 -0
  106. package/packages/gen/src/video/h3.ts +107 -0
  107. package/packages/gen/src/video/http.ts +44 -0
  108. package/packages/gen/src/video/ltx.ts +60 -0
  109. package/packages/gen/src/video/minimax.ts +55 -0
  110. package/packages/gen/src/video/veo.ts +71 -0
  111. package/packages/jizura/package.json +16 -0
  112. package/packages/jizura/src/deny.ts +73 -0
  113. package/packages/jizura/src/index.ts +7 -0
  114. package/packages/jizura/src/install.ts +226 -0
  115. package/packages/jizura/src/layer.ts +282 -0
  116. package/packages/jizura/src/lyrics.ts +81 -0
  117. package/packages/jizura/src/pin.ts +5 -0
  118. package/packages/jizura/src/vite.ts +36 -0
  119. package/packages/motion/README.md +142 -0
  120. package/packages/motion/package.json +29 -0
  121. package/packages/motion/src/camera.ts +97 -0
  122. package/packages/motion/src/captions.ts +479 -0
  123. package/packages/motion/src/enter.ts +128 -0
  124. package/packages/motion/src/hangul.ts +129 -0
  125. package/packages/motion/src/impact.ts +100 -0
  126. package/packages/motion/src/index.ts +17 -0
  127. package/packages/motion/src/moves/brushWipe.ts +90 -0
  128. package/packages/motion/src/moves/cloneArray.ts +111 -0
  129. package/packages/motion/src/moves/curtains.ts +81 -0
  130. package/packages/motion/src/moves/echoStack.ts +70 -0
  131. package/packages/motion/src/moves/fit.ts +34 -0
  132. package/packages/motion/src/moves/flood.ts +61 -0
  133. package/packages/motion/src/moves/ghostStack.ts +79 -0
  134. package/packages/motion/src/moves/gridFloor.ts +100 -0
  135. package/packages/motion/src/moves/imageSwarm.ts +109 -0
  136. package/packages/motion/src/moves/index.ts +19 -0
  137. package/packages/motion/src/moves/irisBlades.ts +113 -0
  138. package/packages/motion/src/moves/karaokeLine.ts +94 -0
  139. package/packages/motion/src/moves/ledBoard.ts +94 -0
  140. package/packages/motion/src/moves/liquidTab.ts +72 -0
  141. package/packages/motion/src/moves/markerWrite.ts +63 -0
  142. package/packages/motion/src/moves/morphBox.ts +96 -0
  143. package/packages/motion/src/moves/neonSign.ts +77 -0
  144. package/packages/motion/src/moves/panelPop.ts +78 -0
  145. package/packages/motion/src/moves/paperTear.ts +75 -0
  146. package/packages/motion/src/moves/path.ts +64 -0
  147. package/packages/motion/src/moves/pathText.ts +107 -0
  148. package/packages/motion/src/moves/pointSphere.ts +109 -0
  149. package/packages/motion/src/moves/ransomLetters.ts +73 -0
  150. package/packages/motion/src/moves/shapeMorph.ts +143 -0
  151. package/packages/motion/src/moves/slamWords.ts +89 -0
  152. package/packages/motion/src/moves/sparkTrail.ts +114 -0
  153. package/packages/motion/src/moves/speedLines.ts +91 -0
  154. package/packages/motion/src/moves/splitFlap.ts +147 -0
  155. package/packages/motion/src/moves/stepWords.ts +117 -0
  156. package/packages/motion/src/moves/strikeOut.ts +98 -0
  157. package/packages/motion/src/moves/sunburst.ts +58 -0
  158. package/packages/motion/src/moves/tickerRows.ts +87 -0
  159. package/packages/motion/src/moves/tokenPicker.ts +114 -0
  160. package/packages/motion/src/moves/truchet.ts +85 -0
  161. package/packages/motion/src/moves/wordWall.ts +76 -0
  162. package/packages/motion/src/moves/worldRoll.ts +31 -0
  163. package/packages/motion/src/particles.ts +102 -0
  164. package/packages/motion/src/react/index.tsx +21 -0
  165. package/packages/motion/src/react/parts.tsx +431 -0
  166. package/packages/motion/src/react/time.tsx +97 -0
  167. package/packages/motion/src/text.ts +103 -0
  168. package/packages/motion/src/transition.ts +82 -0
  169. package/packages/motion/src/transition3d/cards.ts +65 -0
  170. package/packages/motion/src/transition3d/chain.ts +84 -0
  171. package/packages/motion/src/transition3d/dive.ts +181 -0
  172. package/packages/motion/src/transition3d/fold.ts +110 -0
  173. package/packages/motion/src/transition3d/gl.ts +219 -0
  174. package/packages/motion/src/transition3d/index.ts +228 -0
  175. package/packages/motion/src/transition3d/live.ts +70 -0
  176. package/packages/motion/src/transition3d/portal.ts +115 -0
  177. package/packages/motion/src/transition3d/react.tsx +29 -0
  178. package/packages/motion/src/transition3d/rig.ts +502 -0
  179. package/packages/motion/src/transition3d/shatter.ts +101 -0
  180. package/packages/motion/src/transition3d/whip.ts +65 -0
  181. package/packages/motion/src/transition3d/world.ts +683 -0
  182. package/packages/motion/src/transition3d/zoomOut.ts +114 -0
  183. package/packages/motion/src/transitions2d/catalog.ts +127 -0
  184. package/packages/motion/src/transitions2d/css.d.ts +2 -0
  185. package/packages/motion/src/transitions2d/cult-ui/LICENSE.md +9 -0
  186. package/packages/motion/src/transitions2d/cult-ui/RollingNumber.tsx +43 -0
  187. package/packages/motion/src/transitions2d/gl-transitions/LICENSE +25 -0
  188. package/packages/motion/src/transitions2d/gl-transitions/shaders.ts +1931 -0
  189. package/packages/motion/src/transitions2d/index.ts +2 -0
  190. package/packages/motion/src/transitions2d/kokonutui/LICENSE +21 -0
  191. package/packages/motion/src/transitions2d/kokonutui/MatrixText.css +16 -0
  192. package/packages/motion/src/transitions2d/kokonutui/MatrixText.tsx +94 -0
  193. package/packages/motion/src/transitions2d/magicui/HyperText.css +15 -0
  194. package/packages/motion/src/transitions2d/magicui/HyperText.tsx +115 -0
  195. package/packages/motion/src/transitions2d/magicui/LICENSE.md +21 -0
  196. package/packages/motion/src/transitions2d/magicui/MorphingText.css +25 -0
  197. package/packages/motion/src/transitions2d/magicui/MorphingText.tsx +130 -0
  198. package/packages/motion/src/transitions2d/magicui/WordRotate.tsx +42 -0
  199. package/packages/motion/src/transitions2d/react.ts +13 -0
  200. package/packages/motion/src/transitions2d/skiper-ui/ClipDiv.css +39 -0
  201. package/packages/motion/src/transitions2d/skiper-ui/ClipDiv.tsx +32 -0
  202. package/packages/motion/src/transitions2d/smoothui/LICENSE +21 -0
  203. package/packages/motion/src/transitions2d/smoothui/SharedAxisY.tsx +50 -0
  204. package/packages/motion/src/transitions2d/smoothui/TextMorph.tsx +90 -0
  205. package/packages/motion/src/transitions2d/smoothui/shaders.ts +223 -0
  206. package/packages/motion/src/transitions2d/unlumen/LICENSE +21 -0
  207. package/packages/motion/src/transitions2d/unlumen/ScrambleText.tsx +114 -0
  208. package/packages/motion/src/transitions2d/vengeance-ui/LICENSE +21 -0
  209. package/packages/motion/src/transitions2d/vengeance-ui/MorphText.css +69 -0
  210. package/packages/motion/src/transitions2d/vengeance-ui/MorphText.tsx +45 -0
  211. package/packages/motion/src/type.ts +131 -0
  212. package/packages/motion/src/ui.ts +172 -0
  213. package/packages/plan/package.json +15 -0
  214. package/packages/plan/src/brief.ts +254 -0
  215. package/packages/plan/src/captions.ts +75 -0
  216. package/packages/plan/src/detect.ts +93 -0
  217. package/packages/plan/src/index.ts +23 -0
  218. package/packages/plan/src/layout.ts +176 -0
  219. package/packages/plan/src/llm.ts +110 -0
  220. package/packages/plan/src/look.ts +220 -0
  221. package/packages/plan/src/plan.ts +125 -0
  222. package/packages/plan/src/request.ts +55 -0
  223. package/packages/plan/src/studio.ts +53 -0
  224. package/packages/plan/src/templates.ts +42 -0
  225. package/packages/plan/src/themes.ts +48 -0
  226. package/packages/plan/src/types.ts +106 -0
  227. package/packages/studio/package.json +12 -0
  228. package/packages/studio/src/index.ts +1 -0
  229. package/packages/studio/src/plugin.ts +236 -0
  230. package/packages/studio/src/ui/main.ts +503 -0
  231. package/packages/studio/src/ui/studio.css +165 -0
  232. package/packages/studio/src/ui/timeline.ts +317 -0
  233. package/packages/themes/kit/THEME-MAKE.md +68 -0
  234. package/packages/themes/kit/THEME.md +30 -0
  235. package/packages/themes/kit/briefs/og-intro-15s/brief.json +16 -0
  236. package/packages/themes/kit/briefs/og-intro-15s/facts.ts +29 -0
  237. package/packages/themes/kit/briefs/og-intro-15s/logo.svg +12 -0
  238. package/packages/themes/kit/effects.ts +5 -0
  239. package/packages/themes/kit/sample/index.html +11 -0
  240. package/packages/themes/kit/sample/main.ts +9 -0
  241. package/packages/themes/kit/sample/scenes/scene.ts +15 -0
  242. package/packages/themes/package.json +16 -0
  243. package/packages/themes/src/factory.ts +296 -0
  244. package/packages/themes/src/fx.ts +14 -0
  245. package/packages/themes/src/index.ts +105 -0
  246. package/packages/themes/src/stage3d.ts +177 -0
  247. package/packages/themes/src/types.ts +58 -0
  248. package/presets/kawaii-pastel.json +94 -0
  249. package/presets/neutral-dark.json +82 -0
  250. package/presets/og.json +98 -0
  251. package/skills/kasaframe/SKILL.md +32 -0
  252. package/templates/_shared/project/index.html +11 -0
  253. package/templates/_shared/project/lib/react.ts +22 -0
  254. package/templates/_shared/project/lib/stage.ts +272 -0
  255. package/templates/_shared/project/main.ts +9 -0
  256. package/templates/_shared/scenes/default.ts +18 -0
  257. package/templates/_shared/scenes/drop.ts +30 -0
  258. package/templates/_shared/scenes/end.ts +23 -0
  259. package/templates/_shared/scenes/hook.ts +16 -0
  260. package/templates/_shared/scenes/seam.ts +41 -0
  261. package/templates/_shared/scenes/step.ts +40 -0
  262. package/templates/ad/preview.png +0 -0
  263. package/templates/ad/template.json +132 -0
  264. package/templates/demo/preview.png +0 -0
  265. package/templates/demo/template.json +130 -0
  266. package/templates/explainer/preview.png +0 -0
  267. package/templates/explainer/template.json +142 -0
  268. package/templates/launch/preview.png +0 -0
  269. package/templates/launch/template.json +130 -0
  270. package/templates/mv/preview.png +0 -0
  271. package/templates/mv/scenes/default.ts +95 -0
  272. package/templates/mv/template.json +176 -0
  273. package/templates/promo/preview.png +0 -0
  274. package/templates/promo/template.json +144 -0
  275. package/templates/shorts/preview.png +0 -0
  276. package/templates/shorts/scenes/hook.ts +34 -0
  277. package/templates/shorts/template.json +127 -0
  278. package/templates/square/preview.png +0 -0
  279. package/templates/square/template.json +113 -0
  280. package/themes/debug-hud/THEME.md +39 -0
  281. package/themes/debug-hud/effects.ts +389 -0
  282. package/themes/debug-hud/sample/assets/og/logo.svg +12 -0
  283. package/themes/debug-hud/sample/beats.json +1 -0
  284. package/themes/debug-hud/sample/index.html +11 -0
  285. package/themes/debug-hud/sample/kf.json +59 -0
  286. package/themes/debug-hud/sample/lib/hudkit.ts +49 -0
  287. package/themes/debug-hud/sample/lib/og.ts +29 -0
  288. package/themes/debug-hud/sample/main.ts +9 -0
  289. package/themes/debug-hud/sample/scenes/end.ts +62 -0
  290. package/themes/debug-hud/sample/scenes/gather.ts +67 -0
  291. package/themes/debug-hud/sample/scenes/models.ts +70 -0
  292. package/themes/debug-hud/sample/scenes/price.ts +79 -0
  293. package/themes/debug-hud/sample/style.json +91 -0
  294. package/themes/debug-hud/still.png +0 -0
  295. package/themes/debug-hud/style.json +91 -0
  296. package/themes/debug-hud/theme.json +68 -0
  297. package/themes/og-measure/THEME.md +47 -0
  298. package/themes/og-measure/effects.ts +432 -0
  299. package/themes/og-measure/sample/assets/brand/og-logo-full.svg +12 -0
  300. package/themes/og-measure/sample/assets/brand/og-logo.svg +12 -0
  301. package/themes/og-measure/sample/assets/data/measure.json +353 -0
  302. package/themes/og-measure/sample/beats.json +1 -0
  303. package/themes/og-measure/sample/index.html +11 -0
  304. package/themes/og-measure/sample/kf.json +66 -0
  305. package/themes/og-measure/sample/lib/data.ts +62 -0
  306. package/themes/og-measure/sample/main.ts +9 -0
  307. package/themes/og-measure/sample/measure.ts +78 -0
  308. package/themes/og-measure/sample/scenes/end.ts +47 -0
  309. package/themes/og-measure/sample/scenes/gather.ts +51 -0
  310. package/themes/og-measure/sample/scenes/models.ts +34 -0
  311. package/themes/og-measure/sample/scenes/one.ts +39 -0
  312. package/themes/og-measure/sample/scenes/price.ts +56 -0
  313. package/themes/og-measure/sample/style.json +97 -0
  314. package/themes/og-measure/still.png +0 -0
  315. package/themes/og-measure/style.json +97 -0
  316. package/themes/og-measure/theme.json +79 -0
  317. package/themes/riso-zine/THEME.md +43 -0
  318. package/themes/riso-zine/effects.ts +321 -0
  319. package/themes/riso-zine/sample/assets/og/logo.svg +12 -0
  320. package/themes/riso-zine/sample/beats.json +1 -0
  321. package/themes/riso-zine/sample/index.html +11 -0
  322. package/themes/riso-zine/sample/kf.json +59 -0
  323. package/themes/riso-zine/sample/lib/og.ts +29 -0
  324. package/themes/riso-zine/sample/lib/shot.ts +86 -0
  325. package/themes/riso-zine/sample/lib/zine.ts +42 -0
  326. package/themes/riso-zine/sample/main.ts +9 -0
  327. package/themes/riso-zine/sample/scenes/end.ts +61 -0
  328. package/themes/riso-zine/sample/scenes/gather.ts +62 -0
  329. package/themes/riso-zine/sample/scenes/models.ts +52 -0
  330. package/themes/riso-zine/sample/scenes/price.ts +82 -0
  331. package/themes/riso-zine/sample/style.json +99 -0
  332. package/themes/riso-zine/still.png +0 -0
  333. package/themes/riso-zine/style.json +99 -0
  334. package/themes/riso-zine/theme.json +75 -0
  335. package/tools/beats/beats.py +372 -0
  336. package/tools/beats/requirements.txt +3 -0
  337. package/tools/lyrics/align.py +164 -0
  338. package/tools/lyrics/requirements.txt +9 -0
@@ -0,0 +1,30 @@
1
+ import { applyStyle, combine, type SceneCtx } from "@kasaframe/core";
2
+ import { beatPulse, dropBurst, enter, type MoveName } from "@kasaframe/motion";
3
+ import { bigWord, makeStage } from "../lib/stage.ts";
4
+
5
+ const WORD = "{{word}}";
6
+ const MOVE: MoveName = "{{move}}";
7
+
8
+ // 장면 시작이 드롭에 붙어 있다(template anchor drop:k). 섬광·충격파·흔들림은 dropBurst 가 style.json 규칙(드롭 전용·maxPx)대로 내고
9
+ // window.__kf.events 에 남겨 검사가 센다 — 손으로 짜면 규칙 위반을 못 잡는다
10
+ export default {
11
+ build(root: HTMLElement, ctx: SceneCtx) {
12
+ const stage = makeStage(root, ctx);
13
+ const ring = document.createElement("div");
14
+ ring.style.cssText = "position:absolute;left:50%;top:50%;width:600px;height:600px;margin:-300px 0 0 -300px;border-radius:50%;border:12px solid var(--kf-accent)";
15
+ stage.box.insertBefore(ring, stage.cam);
16
+ const word = bigWord(WORD, stage, { weight: 900 });
17
+ const flash = document.createElement("div");
18
+ flash.style.cssText = "position:absolute;inset:0;background:var(--kf-accent)";
19
+ stage.box.append(flash);
20
+ const drop = ctx.beats.drops.findIndex((d) => d >= -0.05 && d < ctx.dur);
21
+ return (t: number) => {
22
+ stage.tick(t);
23
+ const b = drop >= 0 ? dropBurst(t, { beats: ctx.beats, drop, rules: ctx.style.motion, scene: ctx.id }) : null;
24
+ flash.style.opacity = String((b?.flash ?? 0) * 0.85);
25
+ applyStyle(ring, b ? { scale: b.ring.scale, opacity: b.ring.opacity } : { opacity: 0 });
26
+ const pulse = beatPulse(t, { beats: ctx.beats, rules: ctx.style.motion, scene: ctx.id, source: "drop-word" });
27
+ applyStyle(word, combine(enter(MOVE, t, { at: 0.02, scene: ctx.id }), b?.shake, b?.punch, pulse));
28
+ };
29
+ },
30
+ };
@@ -0,0 +1,23 @@
1
+ import { applyStyle, type SceneCtx } from "@kasaframe/core";
2
+ import { enter, type MoveName } from "@kasaframe/motion";
3
+ import { bigWord, fitPx, makeStage } from "../lib/stage.ts";
4
+
5
+ const NAME = "{{title}}";
6
+ const LINE = "{{line}}";
7
+ const MOVE: MoveName = "{{move}}";
8
+
9
+ export default {
10
+ build(root: HTMLElement, ctx: SceneCtx) {
11
+ const stage = makeStage(root, ctx);
12
+ const name = bigWord(NAME, stage);
13
+ const line = document.createElement("div");
14
+ line.textContent = LINE;
15
+ line.style.cssText = `position:relative;font-family:var(--kf-font-sans);font-size:${fitPx(LINE, stage.safeW, { share: 0.6, max: 64, min: 40 })}px;color:var(--kf-dim);word-break:keep-all;text-align:center`;
16
+ if (LINE) stage.cam.append(line);
17
+ return (t: number) => {
18
+ stage.tick(t);
19
+ applyStyle(name, enter(MOVE, t, { at: 0, scene: ctx.id }));
20
+ applyStyle(line, enter("fade", t, { at: 0.25, scene: ctx.id }));
21
+ };
22
+ },
23
+ };
@@ -0,0 +1,16 @@
1
+ import { applyStyle, clip, ease, type SceneCtx } from "@kasaframe/core";
2
+ import { bigWord, makeStage } from "../lib/stage.ts";
3
+
4
+ const WORD = "{{word}}";
5
+
6
+ // 훅은 첫 프레임부터 내용이 있어야 한다 — 페이드로 시작하면 썸네일·첫 화면이 빈다
7
+ export default {
8
+ build(root: HTMLElement, ctx: SceneCtx) {
9
+ const stage = makeStage(root, ctx);
10
+ const word = bigWord(WORD, stage, { color: "var(--kf-accent)", weight: 900 });
11
+ return (t: number) => {
12
+ stage.tick(t);
13
+ applyStyle(word, { scale: 1.12 - 0.12 * ease.outBack(clip(t, 0, 0.5).p) });
14
+ };
15
+ },
16
+ };
@@ -0,0 +1,41 @@
1
+ import type { SceneCtx } from "@kasaframe/core";
2
+ import { transition3d, type Transition3dName } from "@kasaframe/motion/transition3d";
3
+ import kf from "../kf.json";
4
+
5
+ // 앞·뒤 장면을 살아 있는 화면으로 넘긴다(전환 중에도 앞 장면이 계속 돈다). 그걸 못 하는 브라우저면 assets/seam 정지 그림
6
+ const scenes = import.meta.glob("./*.ts", { eager: true });
7
+
8
+ // 이음매 — 앞 장면 마지막 화면에서 뒤 장면 첫 화면으로 잇는 모션그래픽 전환. 앞뒤 화면 두 장(assets/seam/<id>-from·to.png)은
9
+ // kf make 가 장면을 다 쓴 뒤 찍어 넣고, 없으면 style 색 대체 화면으로 돈다. 종류: dive·portal·cards·shatter·zoomOut·fold
10
+ const KIND = "{{transition}}" as Transition3dName;
11
+
12
+ // 요청에 「영상 생성」을 적어 생성 영상(assets/gen/<id>.mp4)이 만들어졌으면 그걸 깐다 —
13
+ // 없는 <video> 를 넣으면 페이지 ready 가 loadeddata 를 끝없이 기다려서 먼저 있는지 본다
14
+ function exists(url: string): boolean {
15
+ const x = new XMLHttpRequest();
16
+ x.open("HEAD", url, false);
17
+ try {
18
+ x.send();
19
+ } catch {
20
+ return false;
21
+ }
22
+ return x.status === 200 && (x.getResponseHeader("content-type") ?? "").startsWith("video/");
23
+ }
24
+
25
+ export default {
26
+ build(root: HTMLElement, ctx: SceneCtx) {
27
+ const url = ctx.asset(`gen/${ctx.id}.mp4`);
28
+ if (exists(url)) {
29
+ const video = document.createElement("video");
30
+ video.src = url;
31
+ video.muted = true;
32
+ video.playsInline = true;
33
+ video.preload = "auto";
34
+ video.dataset.kfFrom = String(ctx.from);
35
+ video.style.cssText = "position:absolute;inset:0;width:100%;height:100%;object-fit:cover";
36
+ root.append(video);
37
+ return () => {};
38
+ }
39
+ return transition3d(root, ctx, { kind: KIND, live: { kf, scenes } });
40
+ },
41
+ };
@@ -0,0 +1,40 @@
1
+ import { applyStyle, type SceneCtx } from "@kasaframe/core";
2
+ import { cursor, enter, terminal, type MoveName } from "@kasaframe/motion";
3
+ import { makeStage } from "../lib/stage.ts";
4
+
5
+ const STEP = "{{word}}";
6
+ const MOVE: MoveName = "{{move}}";
7
+ const COMMANDS = [{ cmd: "kf new demo --template demo", out: ["장면 6개 · 60초"] }];
8
+
9
+ // 시연 한 단계 — 창(터미널) 하나 + 누를 자리로 다가가는 카메라 + 커서 + 단계 번호. 화면 녹화가 있으면 창 안을 <video data-kf-from> 로 바꾼다
10
+ export default {
11
+ build(root: HTMLElement, ctx: SceneCtx) {
12
+ // 흐르는 바탕·컷마다 바뀌는 판이 「쉬지 않기」를 진다 — 창은 가만히 서고, 카메라는 누른 뒤 한 번만 다가간다
13
+ const stage = makeStage(root, ctx);
14
+ const cam = document.createElement("div");
15
+ // 창이 바탕을 다 덮으면 흐르는 바탕이 안 보여 멈춘 화면이 된다 — 둘레를 남긴다
16
+ cam.style.cssText = "position:relative;width:min(1100px, 70%)";
17
+ const win = document.createElement("div");
18
+ win.style.cssText = "background:var(--kf-surface);border:1px solid var(--kf-line);border-radius:var(--kf-radius-lg);box-shadow:var(--kf-shadow-lift);padding:40px 48px;min-height:520px;font-family:var(--kf-font-mono);font-size:46px;line-height:1.6;color:var(--kf-ink)";
19
+ const badge = document.createElement("div");
20
+ badge.textContent = STEP;
21
+ badge.style.cssText = "position:absolute;left:-24px;top:-36px;background:var(--kf-accent);color:var(--kf-on-accent);font-family:var(--kf-font-display);font-weight:800;font-size:max(44px, var(--kf-size-body));padding:10px 22px;border-radius:var(--kf-radius-pill)";
22
+ const pointer = document.createElement("div");
23
+ pointer.innerHTML = '<svg width="44" height="44" viewBox="0 0 24 24"><path d="M4 2 L4 20 L9 15 L12.5 22 L15.5 20.5 L12 13.8 L19 13.8 Z" fill="currentColor" stroke="white" stroke-width="1.4" stroke-linejoin="round"/></svg>';
24
+ pointer.style.cssText = "position:absolute;left:0;top:0;color:var(--kf-ink);filter:drop-shadow(0 2px 4px rgba(0,0,0,.25))";
25
+ cam.append(win, badge, pointer);
26
+ stage.cam.append(cam);
27
+ const click = Math.min(1.2, ctx.dur * 0.3);
28
+ stage.camera.pushIn(click, { to: () => ({ x: cam.offsetLeft + 0.42 * cam.offsetWidth, y: cam.offsetTop + 0.45 * cam.offsetHeight }), scale: 1.12, dur: 1.2 });
29
+ return (t: number) => {
30
+ const st = terminal(t, COMMANDS, { at: 0.5, cps: 16 });
31
+ win.innerHTML = st.lines
32
+ .map((l) => `<div>${l.kind === "cmd" ? `<span style="color:var(--kf-accent)">${l.prompt} </span>` : ""}${l.text.replace(/</g, "&lt;")}${l.caret ? '<span style="display:inline-block;width:.55em;height:1.1em;vertical-align:-.2em;background:var(--kf-accent)"></span>' : ""}</div>`)
33
+ .join("");
34
+ const c = cursor(t, [{ t: 0, x: 900, y: 520 }, { t: click, x: 300, y: 120, click: true }, { t: ctx.dur, x: 360, y: 160 }]);
35
+ applyStyle(pointer, { x: c.x, y: c.y, scale: c.pressed ? 0.9 : 1 });
36
+ applyStyle(cam, enter(MOVE, t, { at: 0, scene: ctx.id }));
37
+ stage.tick(t);
38
+ };
39
+ },
40
+ };
Binary file
@@ -0,0 +1,132 @@
1
+ {
2
+ "id": "ad",
3
+ "label": "광고",
4
+ "summary": "광고 — 6·15·30초 고정, 브랜드는 첫 2초 안",
5
+ "aspect": "16:9",
6
+ "width": 1920,
7
+ "height": 1080,
8
+ "fps": 60,
9
+ "variants": {
10
+ "9:16": {
11
+ "width": 1080,
12
+ "height": 1920,
13
+ "safeArea": {
14
+ "top": 230,
15
+ "bottom": 460,
16
+ "left": 40,
17
+ "right": 40
18
+ }
19
+ },
20
+ "1:1": {
21
+ "width": 1080,
22
+ "height": 1080,
23
+ "safeArea": {
24
+ "top": 60,
25
+ "bottom": 60,
26
+ "left": 60,
27
+ "right": 60
28
+ }
29
+ }
30
+ },
31
+ "duration": {
32
+ "min": 6,
33
+ "max": 30,
34
+ "default": 15,
35
+ "allowed": [
36
+ 6,
37
+ 15,
38
+ 30
39
+ ]
40
+ },
41
+ "music": "optional",
42
+ "captions": "on",
43
+ "loop": false,
44
+ "style": "kasaterm",
45
+ "safeArea": {
46
+ "top": 60,
47
+ "bottom": 60,
48
+ "left": 80,
49
+ "right": 80
50
+ },
51
+ "text": {
52
+ "policy": "captions",
53
+ "maxOnScreen": 6,
54
+ "minPx": 56
55
+ },
56
+ "motion": {
57
+ "beatPulse": "drops-only",
58
+ "shake": {
59
+ "on": [],
60
+ "maxPerPhrase": 0,
61
+ "maxPx": 0
62
+ },
63
+ "cameraMove": "once-per-phrase",
64
+ "repeatSameMove": false,
65
+ "maxFreezeSec": 0.1,
66
+ "staticSec": {
67
+ "warn": 1.5,
68
+ "error": 3
69
+ },
70
+ "beatMove": "every-beat"
71
+ },
72
+ "scenes": [
73
+ {
74
+ "id": "brand",
75
+ "role": "brand",
76
+ "sec": 2,
77
+ "anchor": "start",
78
+ "idea": "브랜드 — 로고나 이름이 첫 2초 안에 또렷하게"
79
+ },
80
+ {
81
+ "id": "message",
82
+ "role": "message",
83
+ "weight": 1,
84
+ "snap": "beat",
85
+ "idea": "한 가지 약속 — 문장 하나, 그걸 보여 주는 그림 하나"
86
+ },
87
+ {
88
+ "id": "cta",
89
+ "role": "end",
90
+ "sec": 2,
91
+ "anchor": "end",
92
+ "idea": "행동 한 줄 — 주소·버튼·날짜. 로고 다시"
93
+ }
94
+ ],
95
+ "assets": {
96
+ "need": [
97
+ "logo"
98
+ ],
99
+ "want": [
100
+ "product-shots"
101
+ ],
102
+ "gen": [
103
+ "img:message-hero"
104
+ ]
105
+ },
106
+ "deliverables": [
107
+ "mp4",
108
+ "cover"
109
+ ],
110
+ "detect": {
111
+ "words": [
112
+ "광고",
113
+ "범퍼",
114
+ "범퍼 광고",
115
+ "CF",
116
+ "광고 영상",
117
+ "ad",
118
+ "advert",
119
+ "commercial",
120
+ "bumper"
121
+ ],
122
+ "hints": [
123
+ "6초",
124
+ "15초",
125
+ "30초",
126
+ "캠페인",
127
+ "campaign",
128
+ "cta"
129
+ ],
130
+ "aspect": "16:9"
131
+ }
132
+ }
Binary file
@@ -0,0 +1,130 @@
1
+ {
2
+ "id": "demo",
3
+ "label": "시연",
4
+ "summary": "시연 — 화면 녹화(또는 창)에 확대·커서·단계 번호",
5
+ "aspect": "16:9",
6
+ "width": 1920,
7
+ "height": 1080,
8
+ "fps": 60,
9
+ "duration": {
10
+ "min": 30,
11
+ "max": 180,
12
+ "default": 60
13
+ },
14
+ "music": "optional",
15
+ "captions": "off",
16
+ "loop": false,
17
+ "style": "neutral-dark",
18
+ "safeArea": {
19
+ "top": 60,
20
+ "bottom": 120,
21
+ "left": 80,
22
+ "right": 80
23
+ },
24
+ "text": {
25
+ "policy": "terms-only",
26
+ "maxOnScreen": 3,
27
+ "minPx": 40
28
+ },
29
+ "motion": {
30
+ "beatPulse": "off",
31
+ "shake": {
32
+ "on": [],
33
+ "maxPerPhrase": 0,
34
+ "maxPx": 0
35
+ },
36
+ "cameraMove": "free",
37
+ "repeatSameMove": true,
38
+ "maxFreezeSec": 0.1,
39
+ "staticSec": {
40
+ "warn": 5,
41
+ "error": 8
42
+ },
43
+ "beatMove": "drop-sections"
44
+ },
45
+ "scenes": [
46
+ {
47
+ "id": "intro",
48
+ "role": "intro",
49
+ "sec": 3,
50
+ "anchor": "start",
51
+ "idea": "무엇을 해낼지 한 줄 — 결과 화면을 먼저 잠깐"
52
+ },
53
+ {
54
+ "id": "step1",
55
+ "role": "step",
56
+ "weight": 2,
57
+ "snap": "none",
58
+ "idea": "1단계 — 화면 녹화(또는 터미널·창 부품) + 누를 곳으로 확대 + 커서 + 단계 번호"
59
+ },
60
+ {
61
+ "id": "step2",
62
+ "role": "step",
63
+ "weight": 2,
64
+ "snap": "none",
65
+ "idea": "2단계 — 같은 틀, 다른 자리 확대"
66
+ },
67
+ {
68
+ "id": "step3",
69
+ "role": "step",
70
+ "weight": 2,
71
+ "snap": "none",
72
+ "idea": "3단계 — 같은 틀, 결과가 나오는 순간을 확대"
73
+ },
74
+ {
75
+ "id": "result",
76
+ "role": "result",
77
+ "weight": 1,
78
+ "snap": "none",
79
+ "idea": "결과 — 확대를 풀어 전체 화면, 걸린 시간·숫자 하나"
80
+ },
81
+ {
82
+ "id": "end",
83
+ "role": "end",
84
+ "sec": 3,
85
+ "anchor": "end",
86
+ "idea": "이름과 주소"
87
+ }
88
+ ],
89
+ "assets": {
90
+ "need": [],
91
+ "want": [
92
+ "screen-recording",
93
+ "screens",
94
+ "logo"
95
+ ],
96
+ "gen": []
97
+ },
98
+ "deliverables": [
99
+ "mp4",
100
+ "cover",
101
+ "srt",
102
+ "vtt"
103
+ ],
104
+ "detect": {
105
+ "words": [
106
+ "시연",
107
+ "데모",
108
+ "사용법",
109
+ "따라하기",
110
+ "화면 녹화",
111
+ "튜토리얼",
112
+ "walkthrough",
113
+ "demo",
114
+ "tutorial",
115
+ "how to use",
116
+ "screencast"
117
+ ],
118
+ "hints": [
119
+ "단계",
120
+ "클릭",
121
+ "설치",
122
+ "step",
123
+ "녹화"
124
+ ],
125
+ "aspect": "16:9",
126
+ "assetKinds": [
127
+ "video"
128
+ ]
129
+ }
130
+ }
Binary file
@@ -0,0 +1,142 @@
1
+ {
2
+ "id": "explainer",
3
+ "label": "설명",
4
+ "summary": "원리 설명 — 도식 하나를 단계마다 키워 가며, 화면 글은 전문 낱말만, 자막 트랙",
5
+ "aspect": "16:9",
6
+ "width": 1920,
7
+ "height": 1080,
8
+ "fps": 60,
9
+ "variants": {
10
+ "9:16": {
11
+ "width": 1080,
12
+ "height": 1920,
13
+ "safeArea": {
14
+ "top": 230,
15
+ "bottom": 460,
16
+ "left": 40,
17
+ "right": 40
18
+ }
19
+ }
20
+ },
21
+ "duration": {
22
+ "min": 60,
23
+ "max": 120,
24
+ "default": 90
25
+ },
26
+ "music": "optional",
27
+ "captions": "off",
28
+ "loop": false,
29
+ "style": "og",
30
+ "safeArea": {
31
+ "top": 60,
32
+ "bottom": 160,
33
+ "left": 80,
34
+ "right": 80
35
+ },
36
+ "text": {
37
+ "policy": "terms-only",
38
+ "maxOnScreen": 3,
39
+ "minPx": 44
40
+ },
41
+ "motion": {
42
+ "beatPulse": "off",
43
+ "shake": {
44
+ "on": [],
45
+ "maxPerPhrase": 0,
46
+ "maxPx": 0
47
+ },
48
+ "cameraMove": "once-per-phrase",
49
+ "repeatSameMove": false,
50
+ "maxFreezeSec": 0.1,
51
+ "staticSec": {
52
+ "warn": 5,
53
+ "error": 8
54
+ },
55
+ "beatMove": "drop-sections"
56
+ },
57
+ "scenes": [
58
+ {
59
+ "id": "hook",
60
+ "role": "hook",
61
+ "sec": 3,
62
+ "anchor": "start",
63
+ "idea": "결과 그림 먼저 — 다 설명하고 나면 보일 화면을 3초 안에 보여 준다"
64
+ },
65
+ {
66
+ "id": "question",
67
+ "role": "setup",
68
+ "weight": 1,
69
+ "snap": "beat",
70
+ "idea": "질문 하나 — 왜 그런가. 낱말 하나와 도식의 빈자리"
71
+ },
72
+ {
73
+ "id": "mechanism",
74
+ "role": "explain",
75
+ "weight": 4,
76
+ "snap": "beat",
77
+ "idea": "원리 — 도식 하나(또는 3D 물체 하나)를 단계마다 자라게 한다. 새 도식으로 갈아 끼우지 말고 같은 도식을 변신"
78
+ },
79
+ {
80
+ "id": "example",
81
+ "role": "example",
82
+ "weight": 2,
83
+ "snap": "beat",
84
+ "idea": "실제 예 하나 — 숫자가 움직이며 원리를 확인시킨다"
85
+ },
86
+ {
87
+ "id": "recap",
88
+ "role": "recap",
89
+ "weight": 1,
90
+ "snap": "beat",
91
+ "idea": "정리 — hook 의 그림으로 돌아와 이제 읽히게"
92
+ },
93
+ {
94
+ "id": "end",
95
+ "role": "end",
96
+ "sec": 3,
97
+ "anchor": "end",
98
+ "idea": "로고와 출처 한 줄"
99
+ }
100
+ ],
101
+ "assets": {
102
+ "need": [],
103
+ "want": [
104
+ "data",
105
+ "logo"
106
+ ],
107
+ "gen": []
108
+ },
109
+ "deliverables": [
110
+ "mp4",
111
+ "cover",
112
+ "srt",
113
+ "vtt"
114
+ ],
115
+ "detect": {
116
+ "words": [
117
+ "설명",
118
+ "설명영상",
119
+ "해설",
120
+ "원리",
121
+ "가 뭔지",
122
+ "이 뭔지",
123
+ "란 무엇",
124
+ "어떻게 동작",
125
+ "어떻게 작동",
126
+ "explainer",
127
+ "explain",
128
+ "how it works",
129
+ "what is"
130
+ ],
131
+ "hints": [
132
+ "도식",
133
+ "다이어그램",
134
+ "3D",
135
+ "개념",
136
+ "왜",
137
+ "2분",
138
+ "90초"
139
+ ],
140
+ "aspect": "16:9"
141
+ }
142
+ }
Binary file