kasaframe 0.0.0-stage → 0.1.3
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.
- package/LICENSE +21 -0
- package/NOTICE +148 -0
- package/README.md +92 -2
- package/app/package.json +12 -0
- package/app/server/engine.ts +533 -0
- package/app/server/main.ts +209 -0
- package/app/web/env.d.ts +2 -0
- package/app/web/icons.ts +31 -0
- package/app/web/index.html +21 -0
- package/app/web/main.ts +1195 -0
- package/app/web/style.css +463 -0
- package/bin/hooks.mjs +64 -0
- package/bin/kf.mjs +32 -0
- package/docs/AGENTS.md +286 -0
- package/music/README.md +37 -0
- package/package.json +44 -4
- package/packages/adapters/package.json +36 -0
- package/packages/adapters/src/css.ts +11 -0
- package/packages/adapters/src/gsap.ts +26 -0
- package/packages/adapters/src/index.ts +9 -0
- package/packages/adapters/src/lottie.ts +22 -0
- package/packages/adapters/src/media.ts +59 -0
- package/packages/adapters/src/page.ts +229 -0
- package/packages/adapters/src/project.ts +214 -0
- package/packages/adapters/src/react.ts +36 -0
- package/packages/adapters/src/svelte.ts +22 -0
- package/packages/adapters/src/three.ts +18 -0
- package/packages/adapters/src/vue.ts +27 -0
- package/packages/check/package.json +19 -0
- package/packages/check/src/check.ts +280 -0
- package/packages/check/src/cli.ts +70 -0
- package/packages/check/src/image.ts +146 -0
- package/packages/check/src/index.ts +9 -0
- package/packages/check/src/ocr.swift +37 -0
- package/packages/check/src/probe.ts +328 -0
- package/packages/check/src/report.ts +44 -0
- package/packages/check/src/rules/assets.ts +45 -0
- package/packages/check/src/rules/beats.ts +212 -0
- package/packages/check/src/rules/camera.ts +217 -0
- package/packages/check/src/rules/captions.ts +49 -0
- package/packages/check/src/rules/flash.ts +235 -0
- package/packages/check/src/rules/frames.ts +136 -0
- package/packages/check/src/rules/layout.ts +281 -0
- package/packages/check/src/rules/page.ts +87 -0
- package/packages/check/src/rules/runs.ts +20 -0
- package/packages/check/src/rules/text.ts +326 -0
- package/packages/check/src/scan.ts +240 -0
- package/packages/check/src/serve.ts +67 -0
- package/packages/check/src/types.ts +80 -0
- package/packages/check/src/video.ts +137 -0
- package/packages/cli/package.json +30 -0
- package/packages/cli/src/blur.ts +80 -0
- package/packages/cli/src/browser.ts +203 -0
- package/packages/cli/src/command.ts +44 -0
- package/packages/cli/src/commands/app.ts +25 -0
- package/packages/cli/src/commands/beats.ts +36 -0
- package/packages/cli/src/commands/bench.ts +123 -0
- package/packages/cli/src/commands/blender.ts +293 -0
- package/packages/cli/src/commands/check.ts +25 -0
- package/packages/cli/src/commands/direct.ts +210 -0
- package/packages/cli/src/commands/doctor.ts +30 -0
- package/packages/cli/src/commands/gen.ts +173 -0
- package/packages/cli/src/commands/look.ts +46 -0
- package/packages/cli/src/commands/lyrics.ts +157 -0
- package/packages/cli/src/commands/make.ts +1121 -0
- package/packages/cli/src/commands/music.ts +78 -0
- package/packages/cli/src/commands/narrate.ts +238 -0
- package/packages/cli/src/commands/new.ts +185 -0
- package/packages/cli/src/commands/preview.ts +43 -0
- package/packages/cli/src/commands/render.ts +250 -0
- package/packages/cli/src/commands/series.ts +110 -0
- package/packages/cli/src/commands/setup.ts +102 -0
- package/packages/cli/src/commands/sheet.ts +114 -0
- package/packages/cli/src/commands/skill.ts +43 -0
- package/packages/cli/src/commands/still.ts +40 -0
- package/packages/cli/src/commands/theme.ts +172 -0
- package/packages/cli/src/commands/transitions.ts +40 -0
- package/packages/cli/src/deps.ts +122 -0
- package/packages/cli/src/ffmpeg.ts +81 -0
- package/packages/cli/src/index.ts +8 -0
- package/packages/cli/src/kf.ts +64 -0
- package/packages/cli/src/lock.ts +72 -0
- package/packages/cli/src/mix.ts +131 -0
- package/packages/cli/src/out.ts +13 -0
- package/packages/cli/src/pool.ts +34 -0
- package/packages/cli/src/segments.ts +402 -0
- package/packages/cli/src/serve.ts +124 -0
- package/packages/clock/package.json +14 -0
- package/packages/clock/src/index.ts +25 -0
- package/packages/clock/src/install.ts +351 -0
- package/packages/clock/src/types.ts +45 -0
- package/packages/core/package.json +9 -0
- package/packages/core/src/beats.ts +283 -0
- package/packages/core/src/ease.ts +87 -0
- package/packages/core/src/frame.ts +99 -0
- package/packages/core/src/index.ts +27 -0
- package/packages/core/src/project.ts +157 -0
- package/packages/core/src/rand.ts +56 -0
- package/packages/core/src/spring.ts +52 -0
- package/packages/core/src/style.ts +100 -0
- package/packages/core/src/time.ts +88 -0
- package/packages/director/package.json +23 -0
- package/packages/director/src/assemble.ts +361 -0
- package/packages/director/src/brief.ts +122 -0
- package/packages/director/src/catalog.ts +49 -0
- package/packages/director/src/content.ts +343 -0
- package/packages/director/src/fallback.ts +58 -0
- package/packages/director/src/index.ts +13 -0
- package/packages/director/src/pattern.ts +90 -0
- package/packages/director/src/patterns/fill/cells.ts +115 -0
- package/packages/director/src/patterns/formula/stack.ts +93 -0
- package/packages/director/src/patterns/util.ts +58 -0
- package/packages/director/src/scene.ts +62 -0
- package/packages/director/src/select.ts +163 -0
- package/packages/director/src/transitions.ts +115 -0
- package/packages/gen/PROVIDERS.md +90 -0
- package/packages/gen/package.json +9 -0
- package/packages/gen/src/ask.ts +132 -0
- package/packages/gen/src/audio.ts +91 -0
- package/packages/gen/src/blender.ts +54 -0
- package/packages/gen/src/capabilities.ts +151 -0
- package/packages/gen/src/generate.ts +206 -0
- package/packages/gen/src/image/codex.ts +117 -0
- package/packages/gen/src/image/og.ts +133 -0
- package/packages/gen/src/index.ts +26 -0
- package/packages/gen/src/keys.ts +86 -0
- package/packages/gen/src/media.ts +150 -0
- package/packages/gen/src/music/elevenlabs.ts +41 -0
- package/packages/gen/src/music/index.ts +120 -0
- package/packages/gen/src/music/library.ts +73 -0
- package/packages/gen/src/music/lyria.ts +52 -0
- package/packages/gen/src/music/types.ts +28 -0
- package/packages/gen/src/plan.ts +106 -0
- package/packages/gen/src/registry.ts +54 -0
- package/packages/gen/src/seam.ts +103 -0
- package/packages/gen/src/tts/dashscope.ts +64 -0
- package/packages/gen/src/tts/elevenlabs.ts +84 -0
- package/packages/gen/src/tts/gemini.ts +73 -0
- package/packages/gen/src/tts/index.ts +241 -0
- package/packages/gen/src/tts/local.ts +42 -0
- package/packages/gen/src/tts/types.ts +44 -0
- package/packages/gen/src/types.ts +90 -0
- package/packages/gen/src/video/fal.ts +140 -0
- package/packages/gen/src/video/h3.ts +112 -0
- package/packages/gen/src/video/http.ts +44 -0
- package/packages/gen/src/video/ltx.ts +60 -0
- package/packages/gen/src/video/minimax.ts +55 -0
- package/packages/gen/src/video/veo.ts +71 -0
- package/packages/jizura/package.json +16 -0
- package/packages/jizura/src/deny.ts +73 -0
- package/packages/jizura/src/index.ts +7 -0
- package/packages/jizura/src/install.ts +269 -0
- package/packages/jizura/src/layer.ts +325 -0
- package/packages/jizura/src/lyrics.ts +81 -0
- package/packages/jizura/src/pin.ts +8 -0
- package/packages/jizura/src/vendor.ts +140 -0
- package/packages/jizura/src/vite.ts +63 -0
- package/packages/jizura/vendor/JIZURA_LICENSE.txt +21 -0
- package/packages/jizura/vendor/NOTICE +43 -0
- package/packages/jizura/vendor/engine.json +47 -0
- package/packages/jizura/vendor/fonts/BlackHanSans-Regular.woff2 +0 -0
- package/packages/jizura/vendor/fonts/DotGothic16-Regular.woff2 +0 -0
- package/packages/jizura/vendor/fonts/GowunBatang-Bold.woff2 +0 -0
- package/packages/jizura/vendor/fonts/IBMPlexMono-Medium.ttf +0 -0
- package/packages/jizura/vendor/fonts/IBMPlexMono-SemiBold.ttf +0 -0
- package/packages/jizura/vendor/fonts/NotoSansKR-VF.woff2 +0 -0
- package/packages/jizura/vendor/fonts/NotoSerifKR-VF.woff2 +0 -0
- package/packages/jizura/vendor/fonts/OFL-blackhansans.txt +93 -0
- package/packages/jizura/vendor/fonts/OFL-dotgothic16.txt +93 -0
- package/packages/jizura/vendor/fonts/OFL-gowunbatang.txt +94 -0
- package/packages/jizura/vendor/fonts/OFL-ibmplexmono.txt +93 -0
- package/packages/jizura/vendor/fonts/OFL-notosanskr.txt +93 -0
- package/packages/jizura/vendor/fonts/OFL-notoserifkr.txt +94 -0
- package/packages/jizura/vendor/fonts/fonts.json +52 -0
- package/packages/jizura/vendor/jizura_engine.js +35024 -0
- package/packages/motion/README.md +153 -0
- package/packages/motion/package.json +30 -0
- package/packages/motion/src/camera.ts +97 -0
- package/packages/motion/src/captions.ts +487 -0
- package/packages/motion/src/enter.ts +128 -0
- package/packages/motion/src/hangul.ts +129 -0
- package/packages/motion/src/impact.ts +100 -0
- package/packages/motion/src/index.ts +17 -0
- package/packages/motion/src/moves/brushWipe.ts +103 -0
- package/packages/motion/src/moves/cloneArray.ts +111 -0
- package/packages/motion/src/moves/curtains.ts +81 -0
- package/packages/motion/src/moves/dress.ts +191 -0
- package/packages/motion/src/moves/echoStack.ts +70 -0
- package/packages/motion/src/moves/fit.ts +70 -0
- package/packages/motion/src/moves/flood.ts +61 -0
- package/packages/motion/src/moves/ghostStack.ts +88 -0
- package/packages/motion/src/moves/gridFloor.ts +100 -0
- package/packages/motion/src/moves/imageSwarm.ts +113 -0
- package/packages/motion/src/moves/index.ts +38 -0
- package/packages/motion/src/moves/irisBlades.ts +113 -0
- package/packages/motion/src/moves/karaokeLine.ts +108 -0
- package/packages/motion/src/moves/ledBoard.ts +94 -0
- package/packages/motion/src/moves/liquidTab.ts +72 -0
- package/packages/motion/src/moves/markerWrite.ts +63 -0
- package/packages/motion/src/moves/menu.ts +138 -0
- package/packages/motion/src/moves/morphBox.ts +96 -0
- package/packages/motion/src/moves/neonSign.ts +78 -0
- package/packages/motion/src/moves/panelPop.ts +78 -0
- package/packages/motion/src/moves/paperTear.ts +75 -0
- package/packages/motion/src/moves/path.ts +64 -0
- package/packages/motion/src/moves/pathText.ts +107 -0
- package/packages/motion/src/moves/pointSphere.ts +109 -0
- package/packages/motion/src/moves/ransomLetters.ts +73 -0
- package/packages/motion/src/moves/shapeMorph.ts +143 -0
- package/packages/motion/src/moves/slamWords.ts +96 -0
- package/packages/motion/src/moves/sparkTrail.ts +130 -0
- package/packages/motion/src/moves/speedLines.ts +91 -0
- package/packages/motion/src/moves/splitFlap.ts +149 -0
- package/packages/motion/src/moves/stepWords.ts +128 -0
- package/packages/motion/src/moves/strikeOut.ts +98 -0
- package/packages/motion/src/moves/sunburst.ts +58 -0
- package/packages/motion/src/moves/tickerRows.ts +91 -0
- package/packages/motion/src/moves/tokenPicker.ts +115 -0
- package/packages/motion/src/moves/truchet.ts +85 -0
- package/packages/motion/src/moves/wordWall.ts +78 -0
- package/packages/motion/src/moves/worldRoll.ts +32 -0
- package/packages/motion/src/particles.ts +102 -0
- package/packages/motion/src/react/index.tsx +21 -0
- package/packages/motion/src/react/parts.tsx +431 -0
- package/packages/motion/src/react/time.tsx +97 -0
- package/packages/motion/src/text.ts +103 -0
- package/packages/motion/src/transition.ts +82 -0
- package/packages/motion/src/transition3d/cards.ts +65 -0
- package/packages/motion/src/transition3d/chain.ts +84 -0
- package/packages/motion/src/transition3d/dive.ts +181 -0
- package/packages/motion/src/transition3d/fold.ts +110 -0
- package/packages/motion/src/transition3d/gl.ts +219 -0
- package/packages/motion/src/transition3d/index.ts +235 -0
- package/packages/motion/src/transition3d/live.ts +70 -0
- package/packages/motion/src/transition3d/portal.ts +115 -0
- package/packages/motion/src/transition3d/react.tsx +29 -0
- package/packages/motion/src/transition3d/rig.ts +600 -0
- package/packages/motion/src/transition3d/shatter.ts +104 -0
- package/packages/motion/src/transition3d/space.ts +173 -0
- package/packages/motion/src/transition3d/whip.ts +78 -0
- package/packages/motion/src/transition3d/world.ts +737 -0
- package/packages/motion/src/transition3d/zoomOut.ts +114 -0
- package/packages/motion/src/transitions2d/catalog.ts +127 -0
- package/packages/motion/src/transitions2d/css.d.ts +2 -0
- package/packages/motion/src/transitions2d/cult-ui/LICENSE.md +9 -0
- package/packages/motion/src/transitions2d/cult-ui/RollingNumber.tsx +43 -0
- package/packages/motion/src/transitions2d/gl-transitions/LICENSE +25 -0
- package/packages/motion/src/transitions2d/gl-transitions/shaders.ts +1931 -0
- package/packages/motion/src/transitions2d/index.ts +2 -0
- package/packages/motion/src/transitions2d/kokonutui/LICENSE +21 -0
- package/packages/motion/src/transitions2d/kokonutui/MatrixText.css +16 -0
- package/packages/motion/src/transitions2d/kokonutui/MatrixText.tsx +94 -0
- package/packages/motion/src/transitions2d/magicui/HyperText.css +15 -0
- package/packages/motion/src/transitions2d/magicui/HyperText.tsx +115 -0
- package/packages/motion/src/transitions2d/magicui/LICENSE.md +21 -0
- package/packages/motion/src/transitions2d/magicui/MorphingText.css +25 -0
- package/packages/motion/src/transitions2d/magicui/MorphingText.tsx +130 -0
- package/packages/motion/src/transitions2d/magicui/WordRotate.tsx +42 -0
- package/packages/motion/src/transitions2d/react.ts +13 -0
- package/packages/motion/src/transitions2d/skiper-ui/ClipDiv.css +39 -0
- package/packages/motion/src/transitions2d/skiper-ui/ClipDiv.tsx +32 -0
- package/packages/motion/src/transitions2d/smoothui/LICENSE +21 -0
- package/packages/motion/src/transitions2d/smoothui/SharedAxisY.tsx +50 -0
- package/packages/motion/src/transitions2d/smoothui/TextMorph.tsx +90 -0
- package/packages/motion/src/transitions2d/smoothui/shaders.ts +223 -0
- package/packages/motion/src/transitions2d/unlumen/LICENSE +21 -0
- package/packages/motion/src/transitions2d/unlumen/ScrambleText.tsx +114 -0
- package/packages/motion/src/transitions2d/vengeance-ui/LICENSE +21 -0
- package/packages/motion/src/transitions2d/vengeance-ui/MorphText.css +69 -0
- package/packages/motion/src/transitions2d/vengeance-ui/MorphText.tsx +45 -0
- package/packages/motion/src/type.ts +131 -0
- package/packages/motion/src/ui.ts +172 -0
- package/packages/patterns/package.json +15 -0
- package/packages/patterns/src/bars/rank.ts +119 -0
- package/packages/patterns/src/before-after/shrink.ts +127 -0
- package/packages/patterns/src/before-after/strike.ts +125 -0
- package/packages/patterns/src/code/terminal.ts +133 -0
- package/packages/patterns/src/compare/bars.ts +142 -0
- package/packages/patterns/src/compare/duel.ts +103 -0
- package/packages/patterns/src/end/lockup.ts +85 -0
- package/packages/patterns/src/end/slam.ts +91 -0
- package/packages/patterns/src/flow/graph.ts +250 -0
- package/packages/patterns/src/hook-number/counter.ts +101 -0
- package/packages/patterns/src/hook-number/roll.ts +179 -0
- package/packages/patterns/src/hook-number/slam.ts +91 -0
- package/packages/patterns/src/index.ts +38 -0
- package/packages/patterns/src/kit.ts +449 -0
- package/packages/patterns/src/limit/gauge.ts +117 -0
- package/packages/patterns/src/list/cards.ts +131 -0
- package/packages/patterns/src/list/cycle.ts +22 -0
- package/packages/patterns/src/media/panels.ts +100 -0
- package/packages/patterns/src/objects.ts +234 -0
- package/packages/patterns/src/quote/karaoke.ts +126 -0
- package/packages/patterns/src/quote/slam.ts +22 -0
- package/packages/patterns/src/screen/focus.ts +85 -0
- package/packages/patterns/src/steps/path.ts +137 -0
- package/packages/patterns/src/steps/stack.ts +111 -0
- package/packages/patterns/src/term-reveal/chips.ts +92 -0
- package/packages/patterns/src/term-reveal/expand.ts +127 -0
- package/packages/patterns/src/timeline/axis.ts +144 -0
- package/packages/patterns/src/title/mask.ts +85 -0
- package/packages/patterns/src/title/slam.ts +23 -0
- package/packages/patterns/src/toggle-sim/switch.ts +92 -0
- package/packages/patterns/src/trend/columns.ts +108 -0
- package/packages/patterns/src/trend/draw.ts +140 -0
- package/packages/patterns/src/types.ts +67 -0
- package/packages/patterns/src/words/moves.ts +42 -0
- package/packages/patterns/src/words/slam.ts +4 -0
- package/packages/plan/package.json +15 -0
- package/packages/plan/src/asks.ts +256 -0
- package/packages/plan/src/brief.ts +383 -0
- package/packages/plan/src/captions.ts +78 -0
- package/packages/plan/src/detect.ts +93 -0
- package/packages/plan/src/index.ts +27 -0
- package/packages/plan/src/layout.ts +176 -0
- package/packages/plan/src/llm.ts +172 -0
- package/packages/plan/src/look.ts +222 -0
- package/packages/plan/src/plan.ts +179 -0
- package/packages/plan/src/request.ts +55 -0
- package/packages/plan/src/series.ts +76 -0
- package/packages/plan/src/studio.ts +53 -0
- package/packages/plan/src/templates.ts +42 -0
- package/packages/plan/src/themes.ts +48 -0
- package/packages/plan/src/types.ts +157 -0
- package/packages/studio/package.json +12 -0
- package/packages/studio/src/index.ts +1 -0
- package/packages/studio/src/plugin.ts +236 -0
- package/packages/studio/src/ui/main.ts +503 -0
- package/packages/studio/src/ui/studio.css +165 -0
- package/packages/studio/src/ui/timeline.ts +317 -0
- package/packages/themes/kit/THEME-MAKE.md +68 -0
- package/packages/themes/kit/THEME.md +30 -0
- package/packages/themes/kit/briefs/og-intro-15s/brief.json +16 -0
- package/packages/themes/kit/briefs/og-intro-15s/facts.ts +29 -0
- package/packages/themes/kit/briefs/og-intro-15s/logo.svg +12 -0
- package/packages/themes/kit/effects.ts +5 -0
- package/packages/themes/kit/sample/index.html +11 -0
- package/packages/themes/kit/sample/main.ts +9 -0
- package/packages/themes/kit/sample/scenes/scene.ts +15 -0
- package/packages/themes/package.json +19 -0
- package/packages/themes/src/factory.ts +296 -0
- package/packages/themes/src/fx.ts +14 -0
- package/packages/themes/src/index.ts +114 -0
- package/packages/themes/src/slotkit.ts +79 -0
- package/packages/themes/src/slots.ts +46 -0
- package/packages/themes/src/stage3d.ts +197 -0
- package/packages/themes/src/types.ts +58 -0
- package/presets/kawaii-pastel.json +94 -0
- package/presets/neutral-dark.json +82 -0
- package/presets/og.json +98 -0
- package/series/og-shorts.json +14 -0
- package/skills/kasaframe/SKILL.md +33 -0
- package/templates/_shared/project/index.html +11 -0
- package/templates/_shared/project/lib/react.ts +22 -0
- package/templates/_shared/project/lib/stage.ts +292 -0
- package/templates/_shared/project/main.ts +9 -0
- package/templates/_shared/scenes/default.ts +21 -0
- package/templates/_shared/scenes/drop.ts +33 -0
- package/templates/_shared/scenes/end.ts +26 -0
- package/templates/_shared/scenes/hook.ts +18 -0
- package/templates/_shared/scenes/seam.ts +41 -0
- package/templates/_shared/scenes/step.ts +49 -0
- package/templates/ad/preview.png +0 -0
- package/templates/ad/template.json +151 -0
- package/templates/demo/preview.png +0 -0
- package/templates/demo/template.json +141 -0
- package/templates/explainer/preview.png +0 -0
- package/templates/explainer/template.json +193 -0
- package/templates/launch/preview.png +0 -0
- package/templates/launch/template.json +163 -0
- package/templates/mv/preview.png +0 -0
- package/templates/mv/scenes/default.ts +98 -0
- package/templates/mv/template.json +178 -0
- package/templates/promo/preview.png +0 -0
- package/templates/promo/template.json +185 -0
- package/templates/shorts/preview.png +0 -0
- package/templates/shorts/scenes/hook.ts +37 -0
- package/templates/shorts/template.json +196 -0
- package/templates/square/preview.png +0 -0
- package/templates/square/template.json +133 -0
- package/themes/debug-hud/THEME.md +39 -0
- package/themes/debug-hud/effects.ts +389 -0
- package/themes/debug-hud/sample/assets/og/logo.svg +12 -0
- package/themes/debug-hud/sample/beats.json +1 -0
- package/themes/debug-hud/sample/index.html +11 -0
- package/themes/debug-hud/sample/kf.json +59 -0
- package/themes/debug-hud/sample/lib/hudkit.ts +49 -0
- package/themes/debug-hud/sample/lib/og.ts +29 -0
- package/themes/debug-hud/sample/main.ts +9 -0
- package/themes/debug-hud/sample/scenes/end.ts +62 -0
- package/themes/debug-hud/sample/scenes/gather.ts +67 -0
- package/themes/debug-hud/sample/scenes/models.ts +70 -0
- package/themes/debug-hud/sample/scenes/price.ts +79 -0
- package/themes/debug-hud/sample/style.json +91 -0
- package/themes/debug-hud/slots.ts +99 -0
- package/themes/debug-hud/still.png +0 -0
- package/themes/debug-hud/style.json +91 -0
- package/themes/debug-hud/theme.json +68 -0
- package/themes/og-measure/THEME.md +47 -0
- package/themes/og-measure/effects.ts +432 -0
- package/themes/og-measure/sample/assets/brand/og-logo-full.svg +12 -0
- package/themes/og-measure/sample/assets/brand/og-logo.svg +12 -0
- package/themes/og-measure/sample/assets/data/measure.json +353 -0
- package/themes/og-measure/sample/beats.json +1 -0
- package/themes/og-measure/sample/index.html +11 -0
- package/themes/og-measure/sample/kf.json +66 -0
- package/themes/og-measure/sample/lib/data.ts +62 -0
- package/themes/og-measure/sample/main.ts +9 -0
- package/themes/og-measure/sample/measure.ts +78 -0
- package/themes/og-measure/sample/scenes/end.ts +47 -0
- package/themes/og-measure/sample/scenes/gather.ts +51 -0
- package/themes/og-measure/sample/scenes/models.ts +34 -0
- package/themes/og-measure/sample/scenes/one.ts +39 -0
- package/themes/og-measure/sample/scenes/price.ts +56 -0
- package/themes/og-measure/sample/style.json +97 -0
- package/themes/og-measure/slots.ts +88 -0
- package/themes/og-measure/still.png +0 -0
- package/themes/og-measure/style.json +97 -0
- package/themes/og-measure/theme.json +79 -0
- package/themes/riso-zine/THEME.md +43 -0
- package/themes/riso-zine/effects.ts +321 -0
- package/themes/riso-zine/sample/assets/og/logo.svg +12 -0
- package/themes/riso-zine/sample/beats.json +1 -0
- package/themes/riso-zine/sample/index.html +11 -0
- package/themes/riso-zine/sample/kf.json +59 -0
- package/themes/riso-zine/sample/lib/og.ts +29 -0
- package/themes/riso-zine/sample/lib/shot.ts +86 -0
- package/themes/riso-zine/sample/lib/zine.ts +42 -0
- package/themes/riso-zine/sample/main.ts +9 -0
- package/themes/riso-zine/sample/scenes/end.ts +61 -0
- package/themes/riso-zine/sample/scenes/gather.ts +62 -0
- package/themes/riso-zine/sample/scenes/models.ts +52 -0
- package/themes/riso-zine/sample/scenes/price.ts +82 -0
- package/themes/riso-zine/sample/style.json +99 -0
- package/themes/riso-zine/slots.ts +81 -0
- package/themes/riso-zine/still.png +0 -0
- package/themes/riso-zine/style.json +99 -0
- package/themes/riso-zine/theme.json +75 -0
- package/tools/beats/beats.py +372 -0
- package/tools/beats/requirements.txt +3 -0
- package/tools/lyrics/align.py +164 -0
- package/tools/lyrics/requirements.txt +9 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 kokonutUI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.matrix-text {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.matrix-text-char {
|
|
9
|
+
display: inline-block;
|
|
10
|
+
width: 1ch;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
13
|
+
font-size: 44px;
|
|
14
|
+
font-variant-numeric: tabular-nums;
|
|
15
|
+
text-align: center;
|
|
16
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// KokonutUI Matrix Text(MIT, @dorianbaffier, vendor/transitions/kokonutui/matrix-text.json)를 Tailwind 없이 옮긴 판.
|
|
4
|
+
// 원본과 다른 곳: 화면 높이(min-h-screen)를 차지하던 바깥 틀을 걷고 글자 줄만 남겼다. 0·1 색은 accent 로 받는다.
|
|
5
|
+
|
|
6
|
+
import { motion } from 'motion/react';
|
|
7
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
8
|
+
import './MatrixText.css';
|
|
9
|
+
|
|
10
|
+
type LetterState = { char: string; isMatrix: boolean; isSpace: boolean };
|
|
11
|
+
|
|
12
|
+
type MatrixTextProps = {
|
|
13
|
+
text?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
initialDelay?: number;
|
|
16
|
+
letterAnimationDuration?: number;
|
|
17
|
+
letterInterval?: number;
|
|
18
|
+
accent?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function MatrixText({ text = 'HelloWorld!', className, initialDelay = 200, letterAnimationDuration = 500, letterInterval = 100, accent = '#00ff00' }: MatrixTextProps) {
|
|
22
|
+
const [letters, setLetters] = useState<LetterState[]>(() => text.split('').map((char) => ({ char, isMatrix: false, isSpace: char === ' ' })));
|
|
23
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
24
|
+
|
|
25
|
+
const getRandomChar = useCallback(() => (Math.random() > 0.5 ? '1' : '0'), []);
|
|
26
|
+
|
|
27
|
+
const animateLetter = useCallback(
|
|
28
|
+
(index: number) => {
|
|
29
|
+
if (index >= text.length) return;
|
|
30
|
+
|
|
31
|
+
requestAnimationFrame(() => {
|
|
32
|
+
setLetters((prev) => {
|
|
33
|
+
const next = [...prev];
|
|
34
|
+
if (!next[index].isSpace) next[index] = { ...next[index], char: getRandomChar(), isMatrix: true };
|
|
35
|
+
return next;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
setLetters((prev) => {
|
|
40
|
+
const next = [...prev];
|
|
41
|
+
next[index] = { ...next[index], char: text[index], isMatrix: false };
|
|
42
|
+
return next;
|
|
43
|
+
});
|
|
44
|
+
}, letterAnimationDuration);
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
[getRandomChar, text, letterAnimationDuration],
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const startAnimation = useCallback(() => {
|
|
51
|
+
if (isAnimating) return;
|
|
52
|
+
|
|
53
|
+
setIsAnimating(true);
|
|
54
|
+
let currentIndex = 0;
|
|
55
|
+
|
|
56
|
+
const animate = () => {
|
|
57
|
+
if (currentIndex >= text.length) {
|
|
58
|
+
setIsAnimating(false);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
animateLetter(currentIndex);
|
|
62
|
+
currentIndex++;
|
|
63
|
+
setTimeout(animate, letterInterval);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
animate();
|
|
67
|
+
}, [animateLetter, text, isAnimating, letterInterval]);
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
const timer = setTimeout(startAnimation, initialDelay);
|
|
71
|
+
return () => clearTimeout(timer);
|
|
72
|
+
// 원본처럼 처음 한 번만 돈다.
|
|
73
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
74
|
+
}, []);
|
|
75
|
+
|
|
76
|
+
const motionVariants = useMemo(() => ({ matrix: { color: accent, textShadow: `0 2px 4px ${accent}80` } }), [accent]);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div aria-label={text} className={className ? `matrix-text ${className}` : 'matrix-text'}>
|
|
80
|
+
{letters.map((letter, index) => (
|
|
81
|
+
<motion.div
|
|
82
|
+
animate={letter.isMatrix ? 'matrix' : 'normal'}
|
|
83
|
+
className="matrix-text-char"
|
|
84
|
+
initial="initial"
|
|
85
|
+
key={`${index}-${letter.char}`}
|
|
86
|
+
transition={{ duration: 0.1, ease: 'easeInOut' }}
|
|
87
|
+
variants={motionVariants}
|
|
88
|
+
>
|
|
89
|
+
{letter.isSpace ? ' ' : letter.char}
|
|
90
|
+
</motion.div>
|
|
91
|
+
))}
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.hyper-text {
|
|
2
|
+
overflow: hidden;
|
|
3
|
+
padding: 8px 0;
|
|
4
|
+
font-size: 36px;
|
|
5
|
+
font-weight: 700;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.hyper-text-char {
|
|
9
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.hyper-text-char.is-space {
|
|
13
|
+
display: inline-block;
|
|
14
|
+
width: 12px;
|
|
15
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// Magic UI Hyper Text(MIT, vendor/transitions/magicui/hyper-text.json)를 Tailwind 없이 옮긴 판.
|
|
4
|
+
// 원본과 다른 곳: 글자를 motion.span 으로 감쌌지만 움직임이 없어 그냥 span 으로, as 는 태그 이름 그대로.
|
|
5
|
+
// 대문자로 바꾸기(toUpperCase)는 한글엔 뜻이 없어 그대로 두었다.
|
|
6
|
+
|
|
7
|
+
import { useEffect, useRef, useState, type ElementType, type HTMLAttributes } from 'react';
|
|
8
|
+
import './HyperText.css';
|
|
9
|
+
|
|
10
|
+
type CharacterSet = string[] | readonly string[];
|
|
11
|
+
|
|
12
|
+
type HyperTextProps = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
|
|
13
|
+
children: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
/** 섞였다 풀리는 데 걸리는 ms */
|
|
16
|
+
duration?: number;
|
|
17
|
+
delay?: number;
|
|
18
|
+
as?: ElementType;
|
|
19
|
+
startOnView?: boolean;
|
|
20
|
+
animateOnHover?: boolean;
|
|
21
|
+
characterSet?: CharacterSet;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const DEFAULT_CHARACTER_SET = Object.freeze('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')) as readonly string[];
|
|
25
|
+
|
|
26
|
+
const getRandomInt = (max: number): number => Math.floor(Math.random() * max);
|
|
27
|
+
|
|
28
|
+
export function HyperText({
|
|
29
|
+
children,
|
|
30
|
+
className,
|
|
31
|
+
duration = 800,
|
|
32
|
+
delay = 0,
|
|
33
|
+
as: Component = 'div',
|
|
34
|
+
startOnView = false,
|
|
35
|
+
animateOnHover = true,
|
|
36
|
+
characterSet = DEFAULT_CHARACTER_SET,
|
|
37
|
+
...props
|
|
38
|
+
}: HyperTextProps) {
|
|
39
|
+
const [displayText, setDisplayText] = useState<string[]>(() => children.split(''));
|
|
40
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
41
|
+
const iterationCount = useRef(0);
|
|
42
|
+
const elementRef = useRef<HTMLElement | null>(null);
|
|
43
|
+
|
|
44
|
+
const handleAnimationTrigger = () => {
|
|
45
|
+
if (animateOnHover && !isAnimating) {
|
|
46
|
+
iterationCount.current = 0;
|
|
47
|
+
setIsAnimating(true);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!startOnView) {
|
|
53
|
+
const startTimeout = setTimeout(() => setIsAnimating(true), delay);
|
|
54
|
+
return () => clearTimeout(startTimeout);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const observer = new IntersectionObserver(
|
|
58
|
+
([entry]) => {
|
|
59
|
+
if (entry.isIntersecting) {
|
|
60
|
+
setTimeout(() => setIsAnimating(true), delay);
|
|
61
|
+
observer.disconnect();
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
{ threshold: 0.1, rootMargin: '-30% 0px -30% 0px' },
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (elementRef.current) observer.observe(elementRef.current);
|
|
68
|
+
|
|
69
|
+
return () => observer.disconnect();
|
|
70
|
+
}, [delay, startOnView]);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
let animationFrameId: number | null = null;
|
|
74
|
+
|
|
75
|
+
if (isAnimating) {
|
|
76
|
+
const maxIterations = children.length;
|
|
77
|
+
const startTime = performance.now();
|
|
78
|
+
|
|
79
|
+
const animate = (currentTime: number) => {
|
|
80
|
+
const elapsed = currentTime - startTime;
|
|
81
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
82
|
+
|
|
83
|
+
iterationCount.current = progress * maxIterations;
|
|
84
|
+
|
|
85
|
+
setDisplayText(() =>
|
|
86
|
+
children
|
|
87
|
+
.split('')
|
|
88
|
+
.map((letter, index) => (letter === ' ' ? letter : index <= iterationCount.current ? children[index] : characterSet[getRandomInt(characterSet.length)])),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (progress < 1) {
|
|
92
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
93
|
+
} else {
|
|
94
|
+
setIsAnimating(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return () => {
|
|
102
|
+
if (animationFrameId !== null) cancelAnimationFrame(animationFrameId);
|
|
103
|
+
};
|
|
104
|
+
}, [children, duration, isAnimating, characterSet]);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<Component ref={elementRef} className={className ? `hyper-text ${className}` : 'hyper-text'} onMouseEnter={handleAnimationTrigger} {...props}>
|
|
108
|
+
{displayText.map((letter, index) => (
|
|
109
|
+
<span key={index} className={letter === ' ' ? 'hyper-text-char is-space' : 'hyper-text-char'}>
|
|
110
|
+
{letter}
|
|
111
|
+
</span>
|
|
112
|
+
))}
|
|
113
|
+
</Component>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Magic UI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.morphing-text {
|
|
2
|
+
position: relative;
|
|
3
|
+
width: 100%;
|
|
4
|
+
max-width: 48rem;
|
|
5
|
+
height: 1.1em;
|
|
6
|
+
margin: 0 auto;
|
|
7
|
+
font-size: 56px;
|
|
8
|
+
font-weight: 700;
|
|
9
|
+
line-height: 1;
|
|
10
|
+
text-align: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.morphing-text-line {
|
|
14
|
+
position: absolute;
|
|
15
|
+
inset: 0 0 auto;
|
|
16
|
+
display: inline-block;
|
|
17
|
+
width: 100%;
|
|
18
|
+
margin: auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.morphing-text-filters {
|
|
22
|
+
position: fixed;
|
|
23
|
+
width: 0;
|
|
24
|
+
height: 0;
|
|
25
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// Magic UI Morphing Text(MIT, vendor/transitions/magicui/morphing-text.json)를 Tailwind 없이 옮긴 판.
|
|
4
|
+
// 두 줄을 서로 반대로 흐리게·투명하게 하고 위에 문턱 필터(feColorMatrix)를 걸어 글자가 녹아 붙는 것처럼 보이게 한다.
|
|
5
|
+
// 원본과 다른 곳: 문턱 필터 id 를 컴포넌트마다 따로 둔다(한 화면에 여럿 놓아도 서로의 defs 를 밟지 않게).
|
|
6
|
+
|
|
7
|
+
import { useCallback, useEffect, useId, useRef } from 'react';
|
|
8
|
+
import './MorphingText.css';
|
|
9
|
+
|
|
10
|
+
const morphTime = 1.5;
|
|
11
|
+
const cooldownTime = 0.5;
|
|
12
|
+
|
|
13
|
+
const useMorphingText = (texts: string[]) => {
|
|
14
|
+
const textIndexRef = useRef(0);
|
|
15
|
+
const morphRef = useRef(0);
|
|
16
|
+
const cooldownRef = useRef(0);
|
|
17
|
+
const timeRef = useRef(new Date());
|
|
18
|
+
|
|
19
|
+
const text1Ref = useRef<HTMLSpanElement>(null);
|
|
20
|
+
const text2Ref = useRef<HTMLSpanElement>(null);
|
|
21
|
+
|
|
22
|
+
const setStyles = useCallback(
|
|
23
|
+
(fraction: number) => {
|
|
24
|
+
const [current1, current2] = [text1Ref.current, text2Ref.current];
|
|
25
|
+
if (!current1 || !current2) return;
|
|
26
|
+
|
|
27
|
+
current2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
|
|
28
|
+
current2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
|
|
29
|
+
|
|
30
|
+
const invertedFraction = 1 - fraction;
|
|
31
|
+
current1.style.filter = `blur(${Math.min(8 / invertedFraction - 8, 100)}px)`;
|
|
32
|
+
current1.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`;
|
|
33
|
+
|
|
34
|
+
current1.textContent = texts[textIndexRef.current % texts.length];
|
|
35
|
+
current2.textContent = texts[(textIndexRef.current + 1) % texts.length];
|
|
36
|
+
},
|
|
37
|
+
[texts],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const doMorph = useCallback(() => {
|
|
41
|
+
morphRef.current -= cooldownRef.current;
|
|
42
|
+
cooldownRef.current = 0;
|
|
43
|
+
|
|
44
|
+
let fraction = morphRef.current / morphTime;
|
|
45
|
+
|
|
46
|
+
if (fraction > 1) {
|
|
47
|
+
cooldownRef.current = cooldownTime;
|
|
48
|
+
fraction = 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setStyles(fraction);
|
|
52
|
+
|
|
53
|
+
if (fraction === 1) {
|
|
54
|
+
textIndexRef.current++;
|
|
55
|
+
}
|
|
56
|
+
}, [setStyles]);
|
|
57
|
+
|
|
58
|
+
const doCooldown = useCallback(() => {
|
|
59
|
+
morphRef.current = 0;
|
|
60
|
+
const [current1, current2] = [text1Ref.current, text2Ref.current];
|
|
61
|
+
if (current1 && current2) {
|
|
62
|
+
current2.style.filter = 'none';
|
|
63
|
+
current2.style.opacity = '100%';
|
|
64
|
+
current1.style.filter = 'none';
|
|
65
|
+
current1.style.opacity = '0%';
|
|
66
|
+
}
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
let animationFrameId: number;
|
|
71
|
+
|
|
72
|
+
const animate = () => {
|
|
73
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
74
|
+
|
|
75
|
+
const newTime = new Date();
|
|
76
|
+
const dt = (newTime.getTime() - timeRef.current.getTime()) / 1000;
|
|
77
|
+
timeRef.current = newTime;
|
|
78
|
+
|
|
79
|
+
cooldownRef.current -= dt;
|
|
80
|
+
|
|
81
|
+
if (cooldownRef.current <= 0) doMorph();
|
|
82
|
+
else doCooldown();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
animate();
|
|
86
|
+
return () => {
|
|
87
|
+
cancelAnimationFrame(animationFrameId);
|
|
88
|
+
};
|
|
89
|
+
}, [doMorph, doCooldown]);
|
|
90
|
+
|
|
91
|
+
return { text1Ref, text2Ref };
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type MorphingTextProps = {
|
|
95
|
+
className?: string;
|
|
96
|
+
texts: string[];
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function Texts({ texts }: Pick<MorphingTextProps, 'texts'>) {
|
|
100
|
+
const { text1Ref, text2Ref } = useMorphingText(texts);
|
|
101
|
+
return (
|
|
102
|
+
<>
|
|
103
|
+
<span className="morphing-text-line" ref={text1Ref} />
|
|
104
|
+
<span className="morphing-text-line" ref={text2Ref} />
|
|
105
|
+
</>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function MorphingText({ texts, className }: MorphingTextProps) {
|
|
110
|
+
const id = `threshold-${useId().replace(/:/g, '')}`;
|
|
111
|
+
return (
|
|
112
|
+
<div className={className ? `morphing-text ${className}` : 'morphing-text'} style={{ filter: `url(#${id}) blur(0.6px)` }}>
|
|
113
|
+
<Texts texts={texts} />
|
|
114
|
+
<svg className="morphing-text-filters" preserveAspectRatio="xMidYMid slice" aria-hidden>
|
|
115
|
+
<defs>
|
|
116
|
+
<filter id={id}>
|
|
117
|
+
<feColorMatrix
|
|
118
|
+
in="SourceGraphic"
|
|
119
|
+
type="matrix"
|
|
120
|
+
values="1 0 0 0 0
|
|
121
|
+
0 1 0 0 0
|
|
122
|
+
0 0 1 0 0
|
|
123
|
+
0 0 0 255 -140"
|
|
124
|
+
/>
|
|
125
|
+
</filter>
|
|
126
|
+
</defs>
|
|
127
|
+
</svg>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// Magic UI Word Rotate(MIT, vendor/transitions/magicui/word-rotate.json)를 Tailwind 없이 옮긴 판. 원본과 같은 동작.
|
|
4
|
+
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
import { AnimatePresence, motion, type MotionProps } from 'motion/react';
|
|
7
|
+
|
|
8
|
+
type WordRotateProps = {
|
|
9
|
+
words: string[];
|
|
10
|
+
duration?: number;
|
|
11
|
+
motionProps?: MotionProps;
|
|
12
|
+
className?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function WordRotate({
|
|
16
|
+
words,
|
|
17
|
+
duration = 2500,
|
|
18
|
+
motionProps = {
|
|
19
|
+
initial: { opacity: 0, y: -50 },
|
|
20
|
+
animate: { opacity: 1, y: 0 },
|
|
21
|
+
exit: { opacity: 0, y: 50 },
|
|
22
|
+
transition: { duration: 0.25, ease: 'easeOut' },
|
|
23
|
+
},
|
|
24
|
+
className,
|
|
25
|
+
}: WordRotateProps) {
|
|
26
|
+
const [index, setIndex] = useState(0);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const interval = setInterval(() => setIndex((prevIndex) => (prevIndex + 1) % words.length), duration);
|
|
30
|
+
return () => clearInterval(interval);
|
|
31
|
+
}, [words, duration]);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div style={{ overflow: 'hidden', padding: '8px 0' }}>
|
|
35
|
+
<AnimatePresence mode="wait">
|
|
36
|
+
<motion.h1 key={words[index]} className={className} {...motionProps}>
|
|
37
|
+
{words[index]}
|
|
38
|
+
</motion.h1>
|
|
39
|
+
</AnimatePresence>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// 허브 판 React 부품(geono-hub src/transitions 에서 LICENSE 째 옮김). 시계가 step 인 것은 kf.json 의 mode 를 "step" 으로
|
|
2
|
+
export { RollingNumber } from "./cult-ui/RollingNumber.tsx";
|
|
3
|
+
export { MatrixText } from "./kokonutui/MatrixText.tsx";
|
|
4
|
+
export { HyperText } from "./magicui/HyperText.tsx";
|
|
5
|
+
export { MorphingText as MagicMorphingText } from "./magicui/MorphingText.tsx";
|
|
6
|
+
export { WordRotate } from "./magicui/WordRotate.tsx";
|
|
7
|
+
export { ClipDiv } from "./skiper-ui/ClipDiv.tsx";
|
|
8
|
+
export { SharedAxisY } from "./smoothui/SharedAxisY.tsx";
|
|
9
|
+
export { TextMorph } from "./smoothui/TextMorph.tsx";
|
|
10
|
+
export type { TextMorphAlign, TextMorphMode } from "./smoothui/TextMorph.tsx";
|
|
11
|
+
export { ScrambleText } from "./unlumen/ScrambleText.tsx";
|
|
12
|
+
export type { ScrambleTextHandle } from "./unlumen/ScrambleText.tsx";
|
|
13
|
+
export { MorphText } from "./vengeance-ui/MorphText.tsx";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.clip-div-defs {
|
|
2
|
+
position: absolute;
|
|
3
|
+
inset: 0;
|
|
4
|
+
width: 0;
|
|
5
|
+
height: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.clip-div {
|
|
9
|
+
position: relative;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
aspect-ratio: 16 / 9;
|
|
14
|
+
width: 100%;
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.clip-div-img {
|
|
19
|
+
position: absolute;
|
|
20
|
+
inset: 0;
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: 100%;
|
|
23
|
+
object-fit: cover;
|
|
24
|
+
transition: all 400ms ease-in-out;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.clip-div:hover .clip-div-img {
|
|
28
|
+
transform: scale(1.1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.clip-div-shade {
|
|
32
|
+
position: absolute;
|
|
33
|
+
inset: 0;
|
|
34
|
+
background: rgb(0 0 0 / 0.15);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.clip-div-body {
|
|
38
|
+
position: absolute;
|
|
39
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Clip div — Skiper UI skiper66(https://skiper-ui.com/v1/skiper66)을 Tailwind 없이 옮긴 판.
|
|
5
|
+
* Skiper UI 무료판은 출처 표기가 조건이다(이 머리와 레포 루트 NOTICE). 원본은 vendor/transitions/skiper-ui/skiper66.json.
|
|
6
|
+
* 손으로 그린 듯한 테두리 SVG clipPath 안에 그림을 넣고, 올리면 그림이 커진다.
|
|
7
|
+
* 원본과 다른 곳: clipPath id 를 컴포넌트마다 따로 둔다(원본은 customMask001 하나라 여럿 놓으면 겹친다), 예시 화면(Skiper66)은 뺐다.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useId, type ReactNode } from 'react';
|
|
11
|
+
import './ClipDiv.css';
|
|
12
|
+
|
|
13
|
+
const PATH =
|
|
14
|
+
'M457.525 1.148c-20.789-3.198-193.979 1.16-283.854 2.496 11.104-.178 1.297-2.868-81.146-2.496-103.5.468-86 102.499-86 109.999s-7 524.5-6.5 547.5 10 59 6.5 99c-2.8 32-1.167 234.667 0 332.003.5 75 62.5 66.5 67 68.5s38.5 0 81.5 0 436 6 526 10.5 438.995-.5 505.495 0 330.01-12.5 417.51-12.5 230.99 2 270.99 0 40.5-16 51-31.5 12.5-61 12.5-105.5c0-44.503 7.01-274.504 7.01-348.004s-3.51-159.998-7.01-230.998 0-256.002 0-318.002 7.01-92.998-22.5-110.999c-18.79-11.471-81.99-9.999-133.49-9.999H853.525c-29 0-370 4-396 0Z';
|
|
15
|
+
|
|
16
|
+
export function ClipDiv({ children, imgSrc, className }: { children?: ReactNode; imgSrc: string; className?: string }) {
|
|
17
|
+
const id = `clip-${useId().replace(/:/g, '')}`;
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 1836 1053" className="clip-div-defs" aria-hidden>
|
|
21
|
+
<clipPath id={id} clipPathUnits="objectBoundingBox">
|
|
22
|
+
<path fill="currentColor" d={PATH} transform="scale(0.0005139987561, 0.0008543065594)" />
|
|
23
|
+
</clipPath>
|
|
24
|
+
</svg>
|
|
25
|
+
<div style={{ clipPath: `url(#${id})` }} className={className ? `clip-div ${className}` : 'clip-div'}>
|
|
26
|
+
<img src={imgSrc} alt="" className="clip-div-img" />
|
|
27
|
+
<div className="clip-div-shade" />
|
|
28
|
+
{children && <div className="clip-div-body">{children}</div>}
|
|
29
|
+
</div>
|
|
30
|
+
</>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Eduardo Calvo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
// SmoothUI Shared Axis Y(MIT, vendor/transitions/smoothui/shared-axis-y.tsx)를 Tailwind 없이 옮긴 판. 원본과 같은 동작.
|
|
4
|
+
// 낱말마다 계단처럼 끊어서 나가고 들어온다(움직임 없이 0초 전환 + 낱말 지연).
|
|
5
|
+
|
|
6
|
+
import { AnimatePresence, motion, useReducedMotion } from 'motion/react';
|
|
7
|
+
import { useEffect, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
type SharedAxisYProps = {
|
|
10
|
+
className?: string;
|
|
11
|
+
/** 문구가 바뀌는 간격(ms) */
|
|
12
|
+
interval?: number;
|
|
13
|
+
phrases: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const STAGGER_S = 0.078;
|
|
17
|
+
const ROW = { display: 'inline-flex', flexWrap: 'wrap', columnGap: '0.25em' } as const;
|
|
18
|
+
|
|
19
|
+
export function SharedAxisY({ phrases, className, interval = 2500 }: SharedAxisYProps) {
|
|
20
|
+
const [index, setIndex] = useState(0);
|
|
21
|
+
const shouldReduceMotion = useReducedMotion();
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const id = setInterval(() => setIndex((prev) => (prev + 1) % phrases.length), interval);
|
|
25
|
+
return () => clearInterval(id);
|
|
26
|
+
}, [interval, phrases.length]);
|
|
27
|
+
|
|
28
|
+
const words = (phrases[index] ?? '').split(' ');
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<span aria-live="polite" className={className} style={ROW}>
|
|
32
|
+
<AnimatePresence mode="wait">
|
|
33
|
+
<motion.span style={ROW} key={index}>
|
|
34
|
+
{words.map((word, i) => (
|
|
35
|
+
<motion.span
|
|
36
|
+
animate={{ opacity: 1 }}
|
|
37
|
+
exit={shouldReduceMotion ? { opacity: 0, transition: { duration: 0 } } : { opacity: 0, transition: { delay: i * STAGGER_S, duration: 0 } }}
|
|
38
|
+
initial={shouldReduceMotion ? { opacity: 1 } : { opacity: 0 }}
|
|
39
|
+
key={i}
|
|
40
|
+
style={{ display: 'inline-block' }}
|
|
41
|
+
transition={shouldReduceMotion ? { duration: 0 } : { delay: i * STAGGER_S, duration: 0 }}
|
|
42
|
+
>
|
|
43
|
+
{word}
|
|
44
|
+
</motion.span>
|
|
45
|
+
))}
|
|
46
|
+
</motion.span>
|
|
47
|
+
</AnimatePresence>
|
|
48
|
+
</span>
|
|
49
|
+
);
|
|
50
|
+
}
|