dsh-remotion 0.2.0 → 0.3.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.
- package/README.en.md +7 -5
- package/README.md +3 -3
- package/lib/index.d.ts +2 -2
- package/lib/index.js +15 -2
- package/package.json +1 -1
- package/skills/remotion-best-practices/SKILL.md +59 -0
- package/skills/remotion-best-practices/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-captions/SKILL.md +36 -0
- package/skills/remotion-best-practices/remotion-captions/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-captions/assets/remotion-icon.png +0 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-captions}/display-captions.md +9 -3
- package/skills/{remotion/rules → remotion-best-practices/remotion-captions}/import-srt-captions.md +5 -1
- package/skills/remotion-best-practices/remotion-create/SKILL.md +68 -0
- package/skills/remotion-best-practices/remotion-create/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-create/assets/remotion-icon.png +0 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-create}/tailwind.md +1 -1
- package/skills/remotion-best-practices/remotion-create/video-layout.md +9 -0
- package/skills/remotion-best-practices/remotion-docs/SKILL.md +46 -0
- package/skills/remotion-best-practices/remotion-docs/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-docs/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-interactivity/SKILL.md +247 -0
- package/skills/remotion-best-practices/remotion-interactivity/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-interactivity/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-maps/SKILL.md +36 -0
- package/skills/remotion-best-practices/remotion-maps/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-maps/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
- package/skills/remotion-best-practices/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
- package/skills/remotion-best-practices/remotion-markup/SKILL.md +365 -0
- package/skills/remotion-best-practices/remotion-markup/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-markup/assets/remotion-icon.png +0 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/audio.md +4 -2
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/calculate-metadata.md +4 -2
- package/skills/remotion-best-practices/remotion-markup/compositions.md +117 -0
- package/skills/remotion-best-practices/remotion-markup/cropping.md +34 -0
- package/skills/remotion-best-practices/remotion-markup/effects.md +251 -0
- package/skills/{remotion/rules/videos.md → remotion-best-practices/remotion-markup/embedding-videos.md} +6 -4
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/ffmpeg.md +5 -1
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/gifs.md +55 -9
- package/skills/remotion-best-practices/remotion-markup/google-fonts.md +76 -0
- package/skills/remotion-best-practices/remotion-markup/html-in-canvas.md +128 -0
- package/skills/remotion-best-practices/remotion-markup/images.md +73 -0
- package/skills/remotion-best-practices/remotion-markup/light-leaks.md +106 -0
- package/skills/remotion-best-practices/remotion-markup/local-fonts.md +69 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/lottie.md +4 -1
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/measuring-dom-nodes.md +5 -1
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/measuring-text.md +8 -2
- package/skills/remotion-best-practices/remotion-markup/multi-scene-video.md +81 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/parameters.md +3 -1
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/SKILL.md +36 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
- package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/sequencing.md +63 -12
- package/skills/remotion-best-practices/remotion-markup/sfx.md +51 -0
- package/skills/remotion-best-practices/remotion-markup/text-highlights.md +56 -0
- package/skills/remotion-best-practices/remotion-markup/timing.md +111 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/transitions.md +49 -7
- package/skills/remotion-best-practices/remotion-markup/video-editing.md +90 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/voiceover.md +2 -2
- package/skills/remotion-best-practices/remotion-multimedia/SKILL.md +20 -0
- package/skills/remotion-best-practices/remotion-multimedia/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-multimedia/assets/remotion-icon.png +0 -0
- package/skills/{remotion/rules → remotion-best-practices/remotion-multimedia}/get-audio-duration.md +1 -3
- package/skills/{remotion/rules → remotion-best-practices/remotion-multimedia}/get-video-dimensions.md +1 -3
- package/skills/{remotion/rules → remotion-best-practices/remotion-multimedia}/get-video-duration.md +1 -3
- package/skills/remotion-best-practices/remotion-render/SKILL.md +27 -0
- package/skills/remotion-best-practices/remotion-render/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-render/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-saas/SKILL.md +33 -0
- package/skills/remotion-best-practices/remotion-saas/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-saas/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-saas/framework.md +21 -0
- package/skills/remotion-best-practices/remotion-saas/player.md +33 -0
- package/skills/remotion-best-practices/remotion-saas/rendering.md +69 -0
- package/skills/remotion-best-practices/remotion-studio/SKILL.md +24 -0
- package/skills/remotion-best-practices/remotion-studio/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-studio/assets/remotion-icon.png +0 -0
- package/skills/remotion-best-practices/remotion-upgrade/SKILL.md +31 -0
- package/skills/remotion-best-practices/remotion-upgrade/agents/openai.yaml +7 -0
- package/skills/remotion-best-practices/remotion-upgrade/assets/remotion-icon.png +0 -0
- package/skills/remotion-captions/SKILL.md +36 -0
- package/skills/remotion-captions/agents/openai.yaml +7 -0
- package/skills/remotion-captions/assets/remotion-icon.png +0 -0
- package/skills/remotion-captions/display-captions.md +190 -0
- package/skills/remotion-captions/import-srt-captions.md +73 -0
- package/skills/remotion-captions/transcribe-captions.md +70 -0
- package/skills/remotion-create/SKILL.md +68 -0
- package/skills/remotion-create/agents/openai.yaml +7 -0
- package/skills/remotion-create/assets/remotion-icon.png +0 -0
- package/skills/remotion-create/tailwind.md +11 -0
- package/skills/remotion-create/video-layout.md +9 -0
- package/skills/remotion-docs/SKILL.md +46 -0
- package/skills/remotion-docs/agents/openai.yaml +7 -0
- package/skills/remotion-docs/assets/remotion-icon.png +0 -0
- package/skills/remotion-interactivity/SKILL.md +247 -0
- package/skills/remotion-interactivity/agents/openai.yaml +7 -0
- package/skills/remotion-interactivity/assets/remotion-icon.png +0 -0
- package/skills/remotion-maps/SKILL.md +36 -0
- package/skills/remotion-maps/agents/openai.yaml +7 -0
- package/skills/remotion-maps/assets/remotion-icon.png +0 -0
- package/skills/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
- package/skills/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
- package/skills/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
- package/skills/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
- package/skills/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
- package/skills/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
- package/skills/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
- package/skills/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
- package/skills/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
- package/skills/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
- package/skills/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
- package/skills/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
- package/skills/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
- package/skills/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
- package/skills/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
- package/skills/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
- package/skills/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
- package/skills/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
- package/skills/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
- package/skills/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
- package/skills/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
- package/skills/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
- package/skills/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
- package/skills/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
- package/skills/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
- package/skills/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
- package/skills/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
- package/skills/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
- package/skills/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
- package/skills/remotion-markup/3d.md +86 -0
- package/skills/remotion-markup/SKILL.md +365 -0
- package/skills/remotion-markup/agents/openai.yaml +7 -0
- package/skills/remotion-markup/assets/remotion-icon.png +0 -0
- package/skills/remotion-markup/audio-visualization.md +198 -0
- package/skills/remotion-markup/audio.md +171 -0
- package/skills/remotion-markup/calculate-metadata.md +136 -0
- package/skills/remotion-markup/compositions.md +117 -0
- package/skills/remotion-markup/cropping.md +34 -0
- package/skills/remotion-markup/effects.md +251 -0
- package/skills/remotion-markup/embedding-videos.md +173 -0
- package/skills/remotion-markup/ffmpeg.md +38 -0
- package/skills/remotion-markup/gifs.md +187 -0
- package/skills/remotion-markup/google-fonts.md +76 -0
- package/skills/remotion-markup/html-in-canvas.md +128 -0
- package/skills/remotion-markup/images.md +73 -0
- package/skills/remotion-markup/light-leaks.md +106 -0
- package/skills/remotion-markup/local-fonts.md +69 -0
- package/skills/remotion-markup/lottie.md +73 -0
- package/skills/remotion-markup/measuring-dom-nodes.md +38 -0
- package/skills/remotion-markup/measuring-text.md +146 -0
- package/skills/remotion-markup/multi-scene-video.md +81 -0
- package/skills/remotion-markup/parameters.md +111 -0
- package/skills/remotion-markup/remotion-maps/SKILL.md +36 -0
- package/skills/remotion-markup/remotion-maps/agents/openai.yaml +7 -0
- package/skills/remotion-markup/remotion-maps/assets/remotion-icon.png +0 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
- package/skills/remotion-markup/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
- package/skills/remotion-markup/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
- package/skills/remotion-markup/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
- package/skills/remotion-markup/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
- package/skills/remotion-markup/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
- package/skills/remotion-markup/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
- package/skills/remotion-markup/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
- package/skills/remotion-markup/sequencing.md +169 -0
- package/skills/remotion-markup/sfx.md +51 -0
- package/skills/remotion-markup/silence-detection.md +71 -0
- package/skills/remotion-markup/text-highlights.md +56 -0
- package/skills/remotion-markup/timing.md +111 -0
- package/skills/remotion-markup/transitions.md +239 -0
- package/skills/remotion-markup/video-editing.md +90 -0
- package/skills/remotion-markup/voiceover.md +99 -0
- package/skills/remotion-multimedia/SKILL.md +20 -0
- package/skills/remotion-multimedia/agents/openai.yaml +7 -0
- package/skills/remotion-multimedia/assets/remotion-icon.png +0 -0
- package/skills/remotion-multimedia/get-audio-duration.md +56 -0
- package/skills/remotion-multimedia/get-video-dimensions.md +66 -0
- package/skills/remotion-multimedia/get-video-duration.md +58 -0
- package/skills/remotion-render/SKILL.md +27 -0
- package/skills/remotion-render/agents/openai.yaml +7 -0
- package/skills/remotion-render/assets/remotion-icon.png +0 -0
- package/skills/remotion-render/transparent-videos.md +106 -0
- package/skills/remotion-saas/SKILL.md +33 -0
- package/skills/remotion-saas/agents/openai.yaml +7 -0
- package/skills/remotion-saas/assets/remotion-icon.png +0 -0
- package/skills/remotion-saas/framework.md +21 -0
- package/skills/remotion-saas/player.md +33 -0
- package/skills/remotion-saas/rendering.md +69 -0
- package/skills/remotion-studio/SKILL.md +24 -0
- package/skills/remotion-studio/agents/openai.yaml +7 -0
- package/skills/remotion-studio/assets/remotion-icon.png +0 -0
- package/skills/remotion-upgrade/SKILL.md +31 -0
- package/skills/remotion-upgrade/agents/openai.yaml +7 -0
- package/skills/remotion-upgrade/assets/remotion-icon.png +0 -0
- package/skills/remotion/SKILL.md +0 -95
- package/skills/remotion/rules/animations.md +0 -31
- package/skills/remotion/rules/assets.md +0 -78
- package/skills/remotion/rules/can-decode.md +0 -81
- package/skills/remotion/rules/charts.md +0 -120
- package/skills/remotion/rules/compositions.md +0 -154
- package/skills/remotion/rules/extract-frames.md +0 -229
- package/skills/remotion/rules/fonts.md +0 -152
- package/skills/remotion/rules/images.md +0 -134
- package/skills/remotion/rules/light-leaks.md +0 -73
- package/skills/remotion/rules/maps.md +0 -412
- package/skills/remotion/rules/sfx.md +0 -30
- package/skills/remotion/rules/subtitles.md +0 -36
- package/skills/remotion/rules/text-animations.md +0 -20
- package/skills/remotion/rules/timing.md +0 -136
- package/skills/remotion/rules/trimming.md +0 -51
- /package/skills/{remotion/rules → remotion-best-practices/remotion-captions}/transcribe-captions.md +0 -0
- /package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/3d.md +0 -0
- /package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/audio-visualization.md +0 -0
- /package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/silence-detection.md +0 -0
- /package/skills/{remotion/rules → remotion-best-practices/remotion-render}/transparent-videos.md +0 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: remotion-interactivity
|
|
3
|
+
description: Structure Remotion markup for interactivity
|
|
4
|
+
version: 4.0.519
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
By writing Remotion markup in a specific way, the Remotion Studio is able to recognize the structure of the code and makes it interactive:
|
|
8
|
+
|
|
9
|
+
- Allowing items to be selected by clicking on them
|
|
10
|
+
- Allowing drag+drop, resizing and rotation
|
|
11
|
+
- Editing the CSS styles
|
|
12
|
+
- Making keyframes and easing values editable
|
|
13
|
+
|
|
14
|
+
If the markup is too complex for the Studio to make it interactive, then the values become grayed out.
|
|
15
|
+
|
|
16
|
+
## Make an HTML element interactive using `Interactive`
|
|
17
|
+
|
|
18
|
+
Every HTML and SVG element (except `<Img>`, it already is interactive) such as `<div>` can be turned interactive using `Interactive`:
|
|
19
|
+
|
|
20
|
+
```tsx title="Interactive elements"
|
|
21
|
+
<Interactive.Div
|
|
22
|
+
name="Greeting card"
|
|
23
|
+
style={{fontSize: 80, padding: 24}}
|
|
24
|
+
>
|
|
25
|
+
Hello
|
|
26
|
+
</Interactive.Div>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This allows styles and keyframes to be set in the Studio. Be sensible, if a component has many elements, the timeline might get messy.
|
|
30
|
+
|
|
31
|
+
## Prefer inline text
|
|
32
|
+
|
|
33
|
+
If text is fixed and only used once, write it directly inside the interactive element instead of extracting it into a constant.
|
|
34
|
+
|
|
35
|
+
```tsx title="Inline text"
|
|
36
|
+
// 👍 Fixed copy stays editable
|
|
37
|
+
<Interactive.Div name="Title">
|
|
38
|
+
Remotion Best Practices
|
|
39
|
+
</Interactive.Div>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use a prop or variable only when the text is dynamic or reused.
|
|
43
|
+
|
|
44
|
+
## Give interactive elements a descriptive name
|
|
45
|
+
|
|
46
|
+
Add a `name` prop to elements to make them easily identifyable.
|
|
47
|
+
Avoid computed names, hardcode them.
|
|
48
|
+
|
|
49
|
+
```tsx title="Interactive names"
|
|
50
|
+
<>
|
|
51
|
+
<Interactive.Div name="Hero title" style={{fontSize: 80}}>
|
|
52
|
+
Launch day
|
|
53
|
+
</Interactive.Div>
|
|
54
|
+
<Img name="Avatar" src="https://remotion.media/image.jpeg" />
|
|
55
|
+
<Video name="Background" src="https://remotion.media/video.mp4" />
|
|
56
|
+
<Sequence name="Title">
|
|
57
|
+
Launch day
|
|
58
|
+
</Sequence>
|
|
59
|
+
</>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Keep all CSS styles inline
|
|
63
|
+
|
|
64
|
+
The best way is to just pass a plain object to `style` - no referring to constants, no object spreading, no math.
|
|
65
|
+
|
|
66
|
+
```tsx title="Interactive example"
|
|
67
|
+
<Interactive.Div
|
|
68
|
+
style={{
|
|
69
|
+
fontSize: 80,
|
|
70
|
+
color: 'red',
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
Hello World!
|
|
74
|
+
</Interactive.Div>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```tsx title="❌ Bad for interactivity"
|
|
78
|
+
const baseStyle = useMemo(() => {
|
|
79
|
+
return {
|
|
80
|
+
fontSize: 12 // ❌ Non-inline styles are not supported
|
|
81
|
+
}
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
<Interactive.Div
|
|
85
|
+
style={{
|
|
86
|
+
...baseStyle, // ❌ Spreading is not supported
|
|
87
|
+
color: RED, // ❌ Referring to constants is not supported
|
|
88
|
+
scale: frame * 10 // ❌ Math is not supported
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
Hello World!
|
|
92
|
+
</Interactive.Div>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Animate using `interpolate()`
|
|
96
|
+
|
|
97
|
+
Write animations as inline `interpolate()` calls on the property that changes.
|
|
98
|
+
The output range, easing, extrapolation and `output` property should use hardcoded values.
|
|
99
|
+
|
|
100
|
+
The input range may additionally use `durationInFrames`, `fps`, `width` and `height` destructured directly from `useVideoConfig()`. Bare identifiers such as `durationInFrames`, multiplication with a number such as `2 * fps` or `fps * 2`, and subtraction of a number such as `durationInFrames - 1` are supported.
|
|
101
|
+
|
|
102
|
+
```tsx title="Inline values"
|
|
103
|
+
const {fps, durationInFrames} = useVideoConfig();
|
|
104
|
+
|
|
105
|
+
// 👍 Inline values can be standardized and keyframed
|
|
106
|
+
<Interactive.Div
|
|
107
|
+
name="Product card"
|
|
108
|
+
style={{
|
|
109
|
+
color: 'white',
|
|
110
|
+
fontSize: 80,
|
|
111
|
+
scale: interpolate(frame, [0, fps], [0, 1], {
|
|
112
|
+
easing: Easing.spring({damping: 200}),
|
|
113
|
+
output: 'perceptual-scale',
|
|
114
|
+
extrapolateLeft: 'clamp',
|
|
115
|
+
extrapolateRight: 'clamp'
|
|
116
|
+
}),
|
|
117
|
+
rotate: interpolate(frame, [0, 1 * fps], ['0deg', '20deg'], {
|
|
118
|
+
easing: Easing.spring({damping: 200}),
|
|
119
|
+
extrapolateLeft: 'clamp',
|
|
120
|
+
extrapolateRight: 'clamp'
|
|
121
|
+
}),
|
|
122
|
+
translate: interpolate(
|
|
123
|
+
frame,
|
|
124
|
+
[durationInFrames - 30, durationInFrames],
|
|
125
|
+
['0px 0px', '0px 120px'],
|
|
126
|
+
{
|
|
127
|
+
easing: Easing.spring({damping: 200}),
|
|
128
|
+
output: 'perceptual-scale',
|
|
129
|
+
extrapolateLeft: 'clamp',
|
|
130
|
+
extrapolateRight: 'clamp'
|
|
131
|
+
}
|
|
132
|
+
),
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```tsx title="❌ Bad interactivity"
|
|
138
|
+
const translateY = interpolate(frame, [0, 30], [0, 120]); // ❌ Math should be directly in the markup
|
|
139
|
+
|
|
140
|
+
<Interactive.Div
|
|
141
|
+
name="Product card"
|
|
142
|
+
style={{
|
|
143
|
+
translate: translateY, // ❌ Only inline interpolate() calls are supported,
|
|
144
|
+
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Cannot use math with arbitrary variables, cannot use constants
|
|
145
|
+
scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Can only interpret the `frame` variable.
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Use `scale`, `translate`, `rotate` CSS properties
|
|
151
|
+
|
|
152
|
+
Avoid the `transform` CSS property.
|
|
153
|
+
If possible, use `scale`, `rotate` and `translate` instead because only they are interactively editable.
|
|
154
|
+
|
|
155
|
+
## Keep composition metadata inline
|
|
156
|
+
|
|
157
|
+
When scaffolding a composition, keep `width`, `height`, `fps`, `durationInFrames` and `defaultProps` inline and make no type assertions.
|
|
158
|
+
|
|
159
|
+
The Props editor can save visual edits back to your code when `defaultProps` is an inline object literal on `<Composition>` or `<Still>`.
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
// 👍 Static values are in <Composition>, dynamic values are in calculateMetadata()
|
|
163
|
+
const calculateMetadata = useMemo(async () => {
|
|
164
|
+
const dimensions = await getDimensions(); // just an example
|
|
165
|
+
return {width: dimensions.width, height: dimensions.height};
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
<Composition
|
|
169
|
+
id="my-video"
|
|
170
|
+
component={MyComponent}
|
|
171
|
+
durationInFrames={150}
|
|
172
|
+
fps={30}
|
|
173
|
+
calculateMetadata={calculateMetadata}
|
|
174
|
+
defaultProps={{title: 'Hello', color: '#0b84ff'}}
|
|
175
|
+
/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```tsx title="Negative examples"
|
|
179
|
+
const defaultProps = {title: 'Hello', color: '#0b84ff'}; // ❌ Don't extract defaultProps, must be inline
|
|
180
|
+
const calculateMetadata = useMemo(() => {
|
|
181
|
+
// ❌ Unnecessary because no calculation is being done,
|
|
182
|
+
return {durationInFrames: 150, fps: 30, width: 1920, height: 1080};
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
<Composition
|
|
186
|
+
id="my-video"
|
|
187
|
+
component={MyComponent}
|
|
188
|
+
calculateMetadata={calculateMetadata}
|
|
189
|
+
defaultProps={{
|
|
190
|
+
title: 'Hello',
|
|
191
|
+
} as Props} // ❌ Don't have type assertions, instead type MyComponent correctly
|
|
192
|
+
/>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Use only `calculateMetadata()` for the part of the metadata that is dynamic.
|
|
196
|
+
|
|
197
|
+
## Effects should be inline too
|
|
198
|
+
|
|
199
|
+
The effects array should not be computed.
|
|
200
|
+
The same rules for setting keyframes as `interpolate()` apply too here: All values should also be hardcoded: Input range, output range, easing, extrapolation, `output` property.
|
|
201
|
+
|
|
202
|
+
```tsx title="Effects"
|
|
203
|
+
// 👍 Parameters are inline and the array shape is stable
|
|
204
|
+
<CanvasImage
|
|
205
|
+
src={src}
|
|
206
|
+
width={1280}
|
|
207
|
+
height={720}
|
|
208
|
+
effects={[
|
|
209
|
+
radialProgressiveBlur({
|
|
210
|
+
center: [0.5, 0.5],
|
|
211
|
+
width: 1.2,
|
|
212
|
+
height: 0.8,
|
|
213
|
+
start: 0.2,
|
|
214
|
+
disabled: true,
|
|
215
|
+
rotation: interpolate(frame, [0, 120], [0, 180]),
|
|
216
|
+
}),
|
|
217
|
+
]}
|
|
218
|
+
/>
|
|
219
|
+
|
|
220
|
+
const center = [0.5, 0.5] as const;
|
|
221
|
+
const rotation = frame * 1.5;
|
|
222
|
+
|
|
223
|
+
<CanvasImage
|
|
224
|
+
src={src}
|
|
225
|
+
width={1280}
|
|
226
|
+
height={720}
|
|
227
|
+
// ❌ Conditional effect is not animateable
|
|
228
|
+
effects={enabled ? [
|
|
229
|
+
radialProgressiveBlur({
|
|
230
|
+
// ❌ Not inline
|
|
231
|
+
center,
|
|
232
|
+
rotation,
|
|
233
|
+
}),
|
|
234
|
+
] : []}
|
|
235
|
+
/>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Render separate elements if one version should have effects and another should not.
|
|
239
|
+
|
|
240
|
+
## Making your own component interactive
|
|
241
|
+
|
|
242
|
+
To make a custom userland component interactive, use:
|
|
243
|
+
[Make a component interactive](https://www.remotion.dev/docs/studio/make-component-interactive.md)
|
|
244
|
+
|
|
245
|
+
## Video editing
|
|
246
|
+
|
|
247
|
+
If a Remotion component mainly consists of video and audio clips, see [Video editing](../remotion-markup/video-editing.md) for best practices on how to structure Remotion markup so the clips are interactively editable in the timeline.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: '/remotion-interactivity'
|
|
3
|
+
short_description: 'Make compositions editable in Remotion Studio'
|
|
4
|
+
icon_small: './assets/remotion-icon.png'
|
|
5
|
+
icon_large: './assets/remotion-icon.png'
|
|
6
|
+
brand_color: '#0B84F3'
|
|
7
|
+
default_prompt: '$remotion-interactivity: Make the markup in MyComp.tsx interactive'
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: remotion-maps
|
|
3
|
+
description: Remotion Map animation knowledge
|
|
4
|
+
version: 4.0.519
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Remotion Maps
|
|
8
|
+
|
|
9
|
+
Choose exactly one technique from the intended shot, then load only that technique's `TECHNIQUE.md`.
|
|
10
|
+
Every technique directory is self-contained and may be removed without breaking the others.
|
|
11
|
+
|
|
12
|
+
## [Static map](techniques/static-map/TECHNIQUE.md)
|
|
13
|
+
|
|
14
|
+
- Requires you grab a satellite image and mount it in a `<Img>` tag, and animate on top
|
|
15
|
+
|
|
16
|
+
## [Mapbox](techniques/mapbox/TECHNIQUE.md)
|
|
17
|
+
|
|
18
|
+
- Requires a Mapbox key
|
|
19
|
+
- Nicer styles by default
|
|
20
|
+
- Map can display a round globe when zoomed out
|
|
21
|
+
- Includes nice 3D buildings such as the Eiffel tower
|
|
22
|
+
|
|
23
|
+
## [MapLibre](techniques/maplibre/TECHNIQUE.md)
|
|
24
|
+
|
|
25
|
+
- Requires no API key, fully free
|
|
26
|
+
- Does not include 3D building
|
|
27
|
+
|
|
28
|
+
## [MapTiler](techniques/maptiler/TECHNIQUE.md)
|
|
29
|
+
|
|
30
|
+
- Uses MapTiler
|
|
31
|
+
- Annotations can be drawn on top of geographic features: borders, rivers, labels
|
|
32
|
+
|
|
33
|
+
## [CesiumJS](techniques/cesium/TECHNIQUE.md)
|
|
34
|
+
|
|
35
|
+
- Flythroughs through terrain and mountains
|
|
36
|
+
- "Flight simulator" perspective
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: '/remotion-maps'
|
|
3
|
+
short_description: 'Create animated maps in Remotion videos'
|
|
4
|
+
icon_small: './assets/remotion-icon.png'
|
|
5
|
+
icon_large: './assets/remotion-icon.png'
|
|
6
|
+
brand_color: '#0B84F3'
|
|
7
|
+
default_prompt: '$remotion-maps: Animate a dot from Zurich to New York.'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# CesiumJS — 3D flyovers in Remotion
|
|
2
|
+
|
|
3
|
+
Instructions for achieving map animations with "flight-simulator" perspective in Remotion.
|
|
4
|
+
|
|
5
|
+
## Modes
|
|
6
|
+
|
|
7
|
+
| Mode | Data | Use for |
|
|
8
|
+
| ----------- | ----------------------------------------------------- | ------------------------------------------------------ |
|
|
9
|
+
| `landscape` | MapTiler `terrain-quantized-mesh-v2` + `satellite-v2` | Mountains, gorges, rivers, coastlines and rural routes |
|
|
10
|
+
| `city` | Google Photorealistic 3D Tiles | Cities, architecture and recognizable landmarks |
|
|
11
|
+
|
|
12
|
+
Do not use footprint extrusions for city flyovers. They produce crude building blocks rather than
|
|
13
|
+
textured architecture.
|
|
14
|
+
|
|
15
|
+
## Credentials
|
|
16
|
+
|
|
17
|
+
For `landscape`, set:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
REMOTION_MAPTILER_KEY=...
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Create a MapTiler key at https://cloud.maptiler.com/account/keys/.
|
|
24
|
+
|
|
25
|
+
For `city`, set:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
REMOTION_GOOGLE_MAPS_API_KEY=...
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Create a billing-enabled Google Map Tiles API key by following
|
|
32
|
+
https://developers.google.com/maps/documentation/tile/get-api-key. Enable the **Map Tiles API** and
|
|
33
|
+
restrict the key to that API. Ensure its application restriction permits local headless Remotion
|
|
34
|
+
requests.
|
|
35
|
+
|
|
36
|
+
## Build the flight
|
|
37
|
+
|
|
38
|
+
1. Copy `assets/CesiumFlythrough.tsx`, a path JSON and `assets/example-Root.tsx` into the Remotion
|
|
39
|
+
project, or import the component directly.
|
|
40
|
+
2. Supply the camera route as `[longitude, latitude][]`. Use only meaningful control points; do not hand-author dozens of tiny corrections.
|
|
41
|
+
3. Leave `pathSmoothingPasses={3}` initially. The component applies repeated Chaikin corner cutting, turning straight-then-corner input into a continuous swerve. Increase to `4` for a softer route or reduce to `2` when the camera must follow a tight corridor.
|
|
42
|
+
4. Set absolute camera altitudes for the location. City cameras normally fly lower than landscape
|
|
43
|
+
cameras.
|
|
44
|
+
5. Render a middle-frame still before rendering the full video.
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
<CesiumFlythrough
|
|
48
|
+
mode="city"
|
|
49
|
+
path={cameraPath}
|
|
50
|
+
pathSmoothingPasses={3}
|
|
51
|
+
altitudeStart={700}
|
|
52
|
+
altitudeEnd={500}
|
|
53
|
+
lookAheadKm={0.7}
|
|
54
|
+
travelKm={4.5}
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Camera behavior
|
|
59
|
+
|
|
60
|
+
Walk the smoothed curve by arc length for constant ground speed. Aim at a real point farther along
|
|
61
|
+
the curve rather than its next vertex. Derive roll from the change in look-ahead bearing so the
|
|
62
|
+
camera banks into a turn instead of twitching left and right.
|
|
63
|
+
|
|
64
|
+
For landscape routes, `scripts/prep-cesium-path.mjs` also clips, resamples, smooths and dampens a
|
|
65
|
+
GeoJSON centerline before the component applies its final curve smoothing.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Mechanics
|
|
69
|
+
|
|
70
|
+
- Set `viewer.useDefaultRenderLoop = false`.
|
|
71
|
+
- Call `viewer.render()`, never `scene.render()`, while settling.
|
|
72
|
+
- Use `preserveDrawingBuffer: true`.
|
|
73
|
+
- Gate initialization and every frame with `delayRender`.
|
|
74
|
+
- Drive camera animation from `useCurrentFrame()`; do not use CSS transitions or browser-timed animation.
|
|
75
|
+
- Settle landscapes on `globe.tilesLoaded` and cities on `tileset.tilesLoaded`.
|
|
76
|
+
- Keep all provider attribution visible.
|
|
77
|
+
- Record the source and effective date of custom or disputed geography.
|
|
78
|
+
- Inspect rendered pixels, not only Studio playback, at every required aspect ratio.
|
|
79
|
+
- Read `references/3d-flyover-architecture.md` for camera math, `references/3d-data-sources.md` for provider details, and `references/3d-troubleshooting.md` for blank, coarse, unauthorized or timed-out renders.
|
|
80
|
+
|
|
81
|
+
## Files
|
|
82
|
+
|
|
83
|
+
- `assets/CesiumFlythrough.tsx` — reusable two-mode component.
|
|
84
|
+
- `assets/flight-path.ts` — dependency-free Chaikin route smoothing.
|
|
85
|
+
- `assets/example-Root.tsx` — landscape and city compositions.
|
|
86
|
+
- `assets/cesium-path.json` — sample landscape route.
|
|
87
|
+
- `assets/city-path.json` — sample city route.
|
|
88
|
+
- `assets/sample-river.geojson` — sample path-preparation input.
|
|
89
|
+
- `scripts/prep-cesium-path.mjs` — dependency-free landscape route preparation.
|
package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import React, {useEffect, useMemo, useRef, useState} from 'react';
|
|
2
|
+
import {
|
|
3
|
+
AbsoluteFill,
|
|
4
|
+
cancelRender,
|
|
5
|
+
continueRender,
|
|
6
|
+
delayRender,
|
|
7
|
+
useCurrentFrame,
|
|
8
|
+
useVideoConfig,
|
|
9
|
+
} from 'remotion';
|
|
10
|
+
import terrainPath from './cesium-path.json';
|
|
11
|
+
import {smoothFlightPath, type LngLat} from './flight-path';
|
|
12
|
+
|
|
13
|
+
export type FlyoverMode = 'landscape' | 'city';
|
|
14
|
+
export type {LngLat} from './flight-path';
|
|
15
|
+
|
|
16
|
+
export type CesiumFlythroughProps = {
|
|
17
|
+
mode?: FlyoverMode;
|
|
18
|
+
path?: LngLat[];
|
|
19
|
+
pathSmoothingPasses?: number;
|
|
20
|
+
altitudeStart?: number;
|
|
21
|
+
altitudeEnd?: number;
|
|
22
|
+
lookAheadKm?: number;
|
|
23
|
+
travelKm?: number;
|
|
24
|
+
pitchFromNadir?: number;
|
|
25
|
+
verticalExaggeration?: number;
|
|
26
|
+
maximumScreenSpaceError?: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const MAPTILER_KEY = process.env.REMOTION_MAPTILER_KEY;
|
|
30
|
+
const GOOGLE_MAPS_API_KEY = process.env.REMOTION_GOOGLE_MAPS_API_KEY;
|
|
31
|
+
const CESIUM_VER = '1.143';
|
|
32
|
+
const CDN = `https://cesium.com/downloads/cesiumjs/releases/${CESIUM_VER}/Build/Cesium/`;
|
|
33
|
+
const R = 6371;
|
|
34
|
+
const MAX_BANK = 0.13;
|
|
35
|
+
const BANK_GAIN = 0.6;
|
|
36
|
+
|
|
37
|
+
const havKm = (a: number[], b: number[]) => {
|
|
38
|
+
const r = Math.PI / 180;
|
|
39
|
+
const dLat = (b[1] - a[1]) * r;
|
|
40
|
+
const dLng = (b[0] - a[0]) * r;
|
|
41
|
+
const h =
|
|
42
|
+
Math.sin(dLat / 2) ** 2 +
|
|
43
|
+
Math.cos(a[1] * r) * Math.cos(b[1] * r) * Math.sin(dLng / 2) ** 2;
|
|
44
|
+
return 2 * R * Math.asin(Math.sqrt(h));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const makePathWalker = (path: LngLat[]) => {
|
|
48
|
+
if (path.length < 2)
|
|
49
|
+
throw new Error('Flyover path needs at least two points');
|
|
50
|
+
const cumulative = [0];
|
|
51
|
+
for (let i = 1; i < path.length; i++) {
|
|
52
|
+
cumulative.push(cumulative[i - 1] + havKm(path[i - 1], path[i]));
|
|
53
|
+
}
|
|
54
|
+
const lengthKm = cumulative[cumulative.length - 1];
|
|
55
|
+
const along = (km: number): LngLat => {
|
|
56
|
+
const d = Math.max(0, Math.min(lengthKm, km));
|
|
57
|
+
let i = 1;
|
|
58
|
+
while (i < cumulative.length && cumulative[i] < d) i++;
|
|
59
|
+
if (i >= cumulative.length) return path[path.length - 1];
|
|
60
|
+
const segmentLength = cumulative[i] - cumulative[i - 1] || 1;
|
|
61
|
+
const t = (d - cumulative[i - 1]) / segmentLength;
|
|
62
|
+
return [
|
|
63
|
+
path[i - 1][0] + (path[i][0] - path[i - 1][0]) * t,
|
|
64
|
+
path[i - 1][1] + (path[i][1] - path[i - 1][1]) * t,
|
|
65
|
+
];
|
|
66
|
+
};
|
|
67
|
+
return {along, lengthKm};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const bearing = (a: number[], b: number[]) => {
|
|
71
|
+
const r = Math.PI / 180;
|
|
72
|
+
const y = Math.sin((b[0] - a[0]) * r) * Math.cos(b[1] * r);
|
|
73
|
+
const x =
|
|
74
|
+
Math.cos(a[1] * r) * Math.sin(b[1] * r) -
|
|
75
|
+
Math.sin(a[1] * r) * Math.cos(b[1] * r) * Math.cos((b[0] - a[0]) * r);
|
|
76
|
+
return Math.atan2(y, x);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const lerp = (a: number, b: number, t: number) => a + (b - a) * t;
|
|
80
|
+
const clamp = (v: number, lo: number, hi: number) =>
|
|
81
|
+
Math.max(lo, Math.min(hi, v));
|
|
82
|
+
|
|
83
|
+
const loadCesium = () =>
|
|
84
|
+
new Promise<any>((resolve, reject) => {
|
|
85
|
+
if ((window as any).Cesium) return resolve((window as any).Cesium);
|
|
86
|
+
(window as any).CESIUM_BASE_URL = CDN;
|
|
87
|
+
const css = document.createElement('link');
|
|
88
|
+
css.rel = 'stylesheet';
|
|
89
|
+
css.href = `${CDN}Widgets/widgets.css`;
|
|
90
|
+
document.head.appendChild(css);
|
|
91
|
+
const script = document.createElement('script');
|
|
92
|
+
script.src = `${CDN}Cesium.js`;
|
|
93
|
+
script.onload = () => resolve((window as any).Cesium);
|
|
94
|
+
script.onerror = () =>
|
|
95
|
+
reject(new Error(`Failed to load CesiumJS ${CESIUM_VER}`));
|
|
96
|
+
document.head.appendChild(script);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export const CesiumFlythrough: React.FC<CesiumFlythroughProps> = ({
|
|
100
|
+
mode = 'landscape',
|
|
101
|
+
path = terrainPath as LngLat[],
|
|
102
|
+
pathSmoothingPasses = 3,
|
|
103
|
+
altitudeStart = 4600,
|
|
104
|
+
altitudeEnd = 4300,
|
|
105
|
+
lookAheadKm = 1.5,
|
|
106
|
+
travelKm = 13,
|
|
107
|
+
pitchFromNadir = 76,
|
|
108
|
+
verticalExaggeration = 1.1,
|
|
109
|
+
maximumScreenSpaceError = 8,
|
|
110
|
+
}) => {
|
|
111
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
112
|
+
const started = useRef(false);
|
|
113
|
+
const viewerRef = useRef<any>(null);
|
|
114
|
+
const tilesetRef = useRef<any>(null);
|
|
115
|
+
const frame = useCurrentFrame();
|
|
116
|
+
const {durationInFrames, fps, width, height} = useVideoConfig();
|
|
117
|
+
const [ready, setReady] = useState(false);
|
|
118
|
+
const [handle] = useState(() =>
|
|
119
|
+
delayRender(`cesium init: ${mode}`, {timeoutInMilliseconds: 120000}),
|
|
120
|
+
);
|
|
121
|
+
const walker = useMemo(
|
|
122
|
+
() => makePathWalker(smoothFlightPath(path, pathSmoothingPasses)),
|
|
123
|
+
[path, pathSmoothingPasses],
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const setCamera = (C: any, viewer: any, progress: number) => {
|
|
127
|
+
const maxTravel = Math.max(0, walker.lengthKm - lookAheadKm * 2);
|
|
128
|
+
const cameraDistance = Math.min(travelKm, maxTravel) * progress;
|
|
129
|
+
const camera = walker.along(cameraDistance);
|
|
130
|
+
const aim = walker.along(cameraDistance + lookAheadKm);
|
|
131
|
+
const aim2 = walker.along(cameraDistance + lookAheadKm * 2);
|
|
132
|
+
const heading = bearing(camera, aim);
|
|
133
|
+
let headingDelta = bearing(aim, aim2) - heading;
|
|
134
|
+
while (headingDelta > Math.PI) headingDelta -= 2 * Math.PI;
|
|
135
|
+
while (headingDelta < -Math.PI) headingDelta += 2 * Math.PI;
|
|
136
|
+
viewer.camera.setView({
|
|
137
|
+
destination: C.Cartesian3.fromDegrees(
|
|
138
|
+
camera[0],
|
|
139
|
+
camera[1],
|
|
140
|
+
lerp(altitudeStart, altitudeEnd, progress),
|
|
141
|
+
),
|
|
142
|
+
orientation: {
|
|
143
|
+
heading,
|
|
144
|
+
pitch: C.Math.toRadians(-(90 - pitchFromNadir)),
|
|
145
|
+
roll: clamp(headingDelta * BANK_GAIN, -MAX_BANK, MAX_BANK),
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const tilesAreLoaded = (viewer: any) => {
|
|
151
|
+
if (mode === 'landscape') return viewer.scene.globe.tilesLoaded;
|
|
152
|
+
return Boolean(tilesetRef.current?.tilesLoaded);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const settle = (viewer: any) =>
|
|
156
|
+
new Promise<void>((resolve) => {
|
|
157
|
+
let stable = 0;
|
|
158
|
+
let ticks = 0;
|
|
159
|
+
const tick = () => {
|
|
160
|
+
viewer.render();
|
|
161
|
+
ticks++;
|
|
162
|
+
stable = tilesAreLoaded(viewer) ? stable + 1 : 0;
|
|
163
|
+
if (stable > 8 || ticks > 600) {
|
|
164
|
+
viewer.render();
|
|
165
|
+
resolve();
|
|
166
|
+
} else {
|
|
167
|
+
setTimeout(tick, 8);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
tick();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
if (started.current) return;
|
|
175
|
+
started.current = true;
|
|
176
|
+
(async () => {
|
|
177
|
+
if (mode === 'landscape' && !MAPTILER_KEY) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
'Set REMOTION_MAPTILER_KEY. Create a key at https://cloud.maptiler.com/account/keys/',
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (mode === 'city' && !GOOGLE_MAPS_API_KEY) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
'Set REMOTION_GOOGLE_MAPS_API_KEY. Create a Map Tiles API key at https://developers.google.com/maps/documentation/tile/get-api-key',
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
if (mode === 'city' && durationInFrames / fps > 30) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
'Google Photorealistic 3D Tiles compositions must not exceed 30 seconds',
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const C = await loadCesium();
|
|
194
|
+
const viewer = new C.Viewer(containerRef.current, {
|
|
195
|
+
baseLayer: false,
|
|
196
|
+
baseLayerPicker: false,
|
|
197
|
+
geocoder: false,
|
|
198
|
+
homeButton: false,
|
|
199
|
+
sceneModePicker: false,
|
|
200
|
+
navigationHelpButton: false,
|
|
201
|
+
animation: false,
|
|
202
|
+
timeline: false,
|
|
203
|
+
fullscreenButton: false,
|
|
204
|
+
infoBox: false,
|
|
205
|
+
selectionIndicator: false,
|
|
206
|
+
contextOptions: {webgl: {preserveDrawingBuffer: true}},
|
|
207
|
+
});
|
|
208
|
+
if (mode === 'landscape') {
|
|
209
|
+
viewer.imageryLayers.addImageryProvider(
|
|
210
|
+
new C.UrlTemplateImageryProvider({
|
|
211
|
+
url: `https://api.maptiler.com/tiles/satellite-v2/{z}/{x}/{y}.jpg?key=${MAPTILER_KEY}`,
|
|
212
|
+
maximumLevel: 20,
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
215
|
+
viewer.terrainProvider = await C.CesiumTerrainProvider.fromUrl(
|
|
216
|
+
`https://api.maptiler.com/tiles/terrain-quantized-mesh-v2/?key=${MAPTILER_KEY}`,
|
|
217
|
+
{requestVertexNormals: true},
|
|
218
|
+
);
|
|
219
|
+
viewer.creditDisplay.addStaticCredit(
|
|
220
|
+
new C.Credit(
|
|
221
|
+
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a>',
|
|
222
|
+
true,
|
|
223
|
+
),
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
if (mode === 'city') {
|
|
227
|
+
viewer.scene.globe.show = false;
|
|
228
|
+
const tileset = await C.Cesium3DTileset.fromUrl(
|
|
229
|
+
`https://tile.googleapis.com/v1/3dtiles/root.json?key=${GOOGLE_MAPS_API_KEY}`,
|
|
230
|
+
{
|
|
231
|
+
showCreditsOnScreen: true,
|
|
232
|
+
maximumScreenSpaceError,
|
|
233
|
+
},
|
|
234
|
+
);
|
|
235
|
+
viewer.scene.primitives.add(tileset);
|
|
236
|
+
tilesetRef.current = tileset;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
viewer.useDefaultRenderLoop = false;
|
|
240
|
+
viewer.scene.skyAtmosphere.show = true;
|
|
241
|
+
viewer.scene.fog.enabled = true;
|
|
242
|
+
viewer.scene.globe.enableLighting = false;
|
|
243
|
+
viewer.scene.verticalExaggeration = verticalExaggeration;
|
|
244
|
+
(window as any).__CESIUM_FLYOVER__ = {C, mode};
|
|
245
|
+
viewerRef.current = viewer;
|
|
246
|
+
setCamera(C, viewer, 0);
|
|
247
|
+
await settle(viewer);
|
|
248
|
+
setReady(true);
|
|
249
|
+
continueRender(handle);
|
|
250
|
+
})().catch((error) => cancelRender(error));
|
|
251
|
+
}, [durationInFrames, fps, handle, mode]);
|
|
252
|
+
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
if (!ready) return;
|
|
255
|
+
const frameHandle = delayRender(`cesium ${mode} frame ${frame}`, {
|
|
256
|
+
timeoutInMilliseconds: 60000,
|
|
257
|
+
});
|
|
258
|
+
const C = (window as any).__CESIUM_FLYOVER__.C;
|
|
259
|
+
const viewer = viewerRef.current;
|
|
260
|
+
const progress = durationInFrames <= 1 ? 0 : frame / (durationInFrames - 1);
|
|
261
|
+
setCamera(C, viewer, progress);
|
|
262
|
+
settle(viewer).then(() => continueRender(frameHandle));
|
|
263
|
+
}, [ready, frame, durationInFrames, mode]);
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<AbsoluteFill style={{backgroundColor: '#000'}}>
|
|
267
|
+
<div ref={containerRef} style={{width, height, position: 'absolute'}} />
|
|
268
|
+
{mode === 'city' ? (
|
|
269
|
+
<div
|
|
270
|
+
style={{
|
|
271
|
+
position: 'absolute',
|
|
272
|
+
top: 20,
|
|
273
|
+
right: 24,
|
|
274
|
+
color: 'white',
|
|
275
|
+
font: '500 18px/1.2 sans-serif',
|
|
276
|
+
textShadow: '0 1px 4px black',
|
|
277
|
+
}}
|
|
278
|
+
>
|
|
279
|
+
For promotional purposes only
|
|
280
|
+
</div>
|
|
281
|
+
) : null}
|
|
282
|
+
</AbsoluteFill>
|
|
283
|
+
);
|
|
284
|
+
};
|