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.
Files changed (292) hide show
  1. package/README.en.md +7 -5
  2. package/README.md +3 -3
  3. package/lib/index.d.ts +2 -2
  4. package/lib/index.js +15 -2
  5. package/package.json +1 -1
  6. package/skills/remotion-best-practices/SKILL.md +59 -0
  7. package/skills/remotion-best-practices/agents/openai.yaml +7 -0
  8. package/skills/remotion-best-practices/assets/remotion-icon.png +0 -0
  9. package/skills/remotion-best-practices/remotion-captions/SKILL.md +36 -0
  10. package/skills/remotion-best-practices/remotion-captions/agents/openai.yaml +7 -0
  11. package/skills/remotion-best-practices/remotion-captions/assets/remotion-icon.png +0 -0
  12. package/skills/{remotion/rules → remotion-best-practices/remotion-captions}/display-captions.md +9 -3
  13. package/skills/{remotion/rules → remotion-best-practices/remotion-captions}/import-srt-captions.md +5 -1
  14. package/skills/remotion-best-practices/remotion-create/SKILL.md +68 -0
  15. package/skills/remotion-best-practices/remotion-create/agents/openai.yaml +7 -0
  16. package/skills/remotion-best-practices/remotion-create/assets/remotion-icon.png +0 -0
  17. package/skills/{remotion/rules → remotion-best-practices/remotion-create}/tailwind.md +1 -1
  18. package/skills/remotion-best-practices/remotion-create/video-layout.md +9 -0
  19. package/skills/remotion-best-practices/remotion-docs/SKILL.md +46 -0
  20. package/skills/remotion-best-practices/remotion-docs/agents/openai.yaml +7 -0
  21. package/skills/remotion-best-practices/remotion-docs/assets/remotion-icon.png +0 -0
  22. package/skills/remotion-best-practices/remotion-interactivity/SKILL.md +247 -0
  23. package/skills/remotion-best-practices/remotion-interactivity/agents/openai.yaml +7 -0
  24. package/skills/remotion-best-practices/remotion-interactivity/assets/remotion-icon.png +0 -0
  25. package/skills/remotion-best-practices/remotion-maps/SKILL.md +36 -0
  26. package/skills/remotion-best-practices/remotion-maps/agents/openai.yaml +7 -0
  27. package/skills/remotion-best-practices/remotion-maps/assets/remotion-icon.png +0 -0
  28. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
  29. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
  30. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
  31. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
  32. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
  33. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
  34. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
  35. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
  36. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
  37. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
  38. package/skills/remotion-best-practices/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
  39. package/skills/remotion-best-practices/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
  40. package/skills/remotion-best-practices/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
  41. package/skills/remotion-best-practices/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
  42. package/skills/remotion-best-practices/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
  43. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
  44. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
  45. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
  46. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
  47. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
  48. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
  49. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
  50. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
  51. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
  52. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
  53. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
  54. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
  55. package/skills/remotion-best-practices/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
  56. package/skills/remotion-best-practices/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
  57. package/skills/remotion-best-practices/remotion-markup/SKILL.md +365 -0
  58. package/skills/remotion-best-practices/remotion-markup/agents/openai.yaml +7 -0
  59. package/skills/remotion-best-practices/remotion-markup/assets/remotion-icon.png +0 -0
  60. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/audio.md +4 -2
  61. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/calculate-metadata.md +4 -2
  62. package/skills/remotion-best-practices/remotion-markup/compositions.md +117 -0
  63. package/skills/remotion-best-practices/remotion-markup/cropping.md +34 -0
  64. package/skills/remotion-best-practices/remotion-markup/effects.md +251 -0
  65. package/skills/{remotion/rules/videos.md → remotion-best-practices/remotion-markup/embedding-videos.md} +6 -4
  66. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/ffmpeg.md +5 -1
  67. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/gifs.md +55 -9
  68. package/skills/remotion-best-practices/remotion-markup/google-fonts.md +76 -0
  69. package/skills/remotion-best-practices/remotion-markup/html-in-canvas.md +128 -0
  70. package/skills/remotion-best-practices/remotion-markup/images.md +73 -0
  71. package/skills/remotion-best-practices/remotion-markup/light-leaks.md +106 -0
  72. package/skills/remotion-best-practices/remotion-markup/local-fonts.md +69 -0
  73. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/lottie.md +4 -1
  74. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/measuring-dom-nodes.md +5 -1
  75. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/measuring-text.md +8 -2
  76. package/skills/remotion-best-practices/remotion-markup/multi-scene-video.md +81 -0
  77. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/parameters.md +3 -1
  78. package/skills/remotion-best-practices/remotion-markup/remotion-maps/SKILL.md +36 -0
  79. package/skills/remotion-best-practices/remotion-markup/remotion-maps/agents/openai.yaml +7 -0
  80. package/skills/remotion-best-practices/remotion-markup/remotion-maps/assets/remotion-icon.png +0 -0
  81. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
  82. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
  83. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
  84. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
  85. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
  86. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
  87. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
  88. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
  89. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
  90. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
  91. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
  92. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
  93. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
  94. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
  95. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
  96. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
  97. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
  98. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
  99. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
  100. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
  101. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
  102. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
  103. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
  104. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
  105. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
  106. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
  107. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
  108. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
  109. package/skills/remotion-best-practices/remotion-markup/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
  110. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/sequencing.md +63 -12
  111. package/skills/remotion-best-practices/remotion-markup/sfx.md +51 -0
  112. package/skills/remotion-best-practices/remotion-markup/text-highlights.md +56 -0
  113. package/skills/remotion-best-practices/remotion-markup/timing.md +111 -0
  114. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/transitions.md +49 -7
  115. package/skills/remotion-best-practices/remotion-markup/video-editing.md +90 -0
  116. package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/voiceover.md +2 -2
  117. package/skills/remotion-best-practices/remotion-multimedia/SKILL.md +20 -0
  118. package/skills/remotion-best-practices/remotion-multimedia/agents/openai.yaml +7 -0
  119. package/skills/remotion-best-practices/remotion-multimedia/assets/remotion-icon.png +0 -0
  120. package/skills/{remotion/rules → remotion-best-practices/remotion-multimedia}/get-audio-duration.md +1 -3
  121. package/skills/{remotion/rules → remotion-best-practices/remotion-multimedia}/get-video-dimensions.md +1 -3
  122. package/skills/{remotion/rules → remotion-best-practices/remotion-multimedia}/get-video-duration.md +1 -3
  123. package/skills/remotion-best-practices/remotion-render/SKILL.md +27 -0
  124. package/skills/remotion-best-practices/remotion-render/agents/openai.yaml +7 -0
  125. package/skills/remotion-best-practices/remotion-render/assets/remotion-icon.png +0 -0
  126. package/skills/remotion-best-practices/remotion-saas/SKILL.md +33 -0
  127. package/skills/remotion-best-practices/remotion-saas/agents/openai.yaml +7 -0
  128. package/skills/remotion-best-practices/remotion-saas/assets/remotion-icon.png +0 -0
  129. package/skills/remotion-best-practices/remotion-saas/framework.md +21 -0
  130. package/skills/remotion-best-practices/remotion-saas/player.md +33 -0
  131. package/skills/remotion-best-practices/remotion-saas/rendering.md +69 -0
  132. package/skills/remotion-best-practices/remotion-studio/SKILL.md +24 -0
  133. package/skills/remotion-best-practices/remotion-studio/agents/openai.yaml +7 -0
  134. package/skills/remotion-best-practices/remotion-studio/assets/remotion-icon.png +0 -0
  135. package/skills/remotion-best-practices/remotion-upgrade/SKILL.md +31 -0
  136. package/skills/remotion-best-practices/remotion-upgrade/agents/openai.yaml +7 -0
  137. package/skills/remotion-best-practices/remotion-upgrade/assets/remotion-icon.png +0 -0
  138. package/skills/remotion-captions/SKILL.md +36 -0
  139. package/skills/remotion-captions/agents/openai.yaml +7 -0
  140. package/skills/remotion-captions/assets/remotion-icon.png +0 -0
  141. package/skills/remotion-captions/display-captions.md +190 -0
  142. package/skills/remotion-captions/import-srt-captions.md +73 -0
  143. package/skills/remotion-captions/transcribe-captions.md +70 -0
  144. package/skills/remotion-create/SKILL.md +68 -0
  145. package/skills/remotion-create/agents/openai.yaml +7 -0
  146. package/skills/remotion-create/assets/remotion-icon.png +0 -0
  147. package/skills/remotion-create/tailwind.md +11 -0
  148. package/skills/remotion-create/video-layout.md +9 -0
  149. package/skills/remotion-docs/SKILL.md +46 -0
  150. package/skills/remotion-docs/agents/openai.yaml +7 -0
  151. package/skills/remotion-docs/assets/remotion-icon.png +0 -0
  152. package/skills/remotion-interactivity/SKILL.md +247 -0
  153. package/skills/remotion-interactivity/agents/openai.yaml +7 -0
  154. package/skills/remotion-interactivity/assets/remotion-icon.png +0 -0
  155. package/skills/remotion-maps/SKILL.md +36 -0
  156. package/skills/remotion-maps/agents/openai.yaml +7 -0
  157. package/skills/remotion-maps/assets/remotion-icon.png +0 -0
  158. package/skills/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
  159. package/skills/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
  160. package/skills/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
  161. package/skills/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
  162. package/skills/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
  163. package/skills/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
  164. package/skills/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
  165. package/skills/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
  166. package/skills/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
  167. package/skills/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
  168. package/skills/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
  169. package/skills/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
  170. package/skills/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
  171. package/skills/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
  172. package/skills/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
  173. package/skills/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
  174. package/skills/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
  175. package/skills/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
  176. package/skills/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
  177. package/skills/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
  178. package/skills/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
  179. package/skills/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
  180. package/skills/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
  181. package/skills/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
  182. package/skills/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
  183. package/skills/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
  184. package/skills/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
  185. package/skills/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
  186. package/skills/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
  187. package/skills/remotion-markup/3d.md +86 -0
  188. package/skills/remotion-markup/SKILL.md +365 -0
  189. package/skills/remotion-markup/agents/openai.yaml +7 -0
  190. package/skills/remotion-markup/assets/remotion-icon.png +0 -0
  191. package/skills/remotion-markup/audio-visualization.md +198 -0
  192. package/skills/remotion-markup/audio.md +171 -0
  193. package/skills/remotion-markup/calculate-metadata.md +136 -0
  194. package/skills/remotion-markup/compositions.md +117 -0
  195. package/skills/remotion-markup/cropping.md +34 -0
  196. package/skills/remotion-markup/effects.md +251 -0
  197. package/skills/remotion-markup/embedding-videos.md +173 -0
  198. package/skills/remotion-markup/ffmpeg.md +38 -0
  199. package/skills/remotion-markup/gifs.md +187 -0
  200. package/skills/remotion-markup/google-fonts.md +76 -0
  201. package/skills/remotion-markup/html-in-canvas.md +128 -0
  202. package/skills/remotion-markup/images.md +73 -0
  203. package/skills/remotion-markup/light-leaks.md +106 -0
  204. package/skills/remotion-markup/local-fonts.md +69 -0
  205. package/skills/remotion-markup/lottie.md +73 -0
  206. package/skills/remotion-markup/measuring-dom-nodes.md +38 -0
  207. package/skills/remotion-markup/measuring-text.md +146 -0
  208. package/skills/remotion-markup/multi-scene-video.md +81 -0
  209. package/skills/remotion-markup/parameters.md +111 -0
  210. package/skills/remotion-markup/remotion-maps/SKILL.md +36 -0
  211. package/skills/remotion-markup/remotion-maps/agents/openai.yaml +7 -0
  212. package/skills/remotion-markup/remotion-maps/assets/remotion-icon.png +0 -0
  213. package/skills/remotion-markup/remotion-maps/techniques/cesium/TECHNIQUE.md +89 -0
  214. package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/CesiumFlythrough.tsx +284 -0
  215. package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/cesium-path.json +299 -0
  216. package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/city-path.json +12 -0
  217. package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/example-Root.tsx +39 -0
  218. package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/flight-path.ts +35 -0
  219. package/skills/remotion-markup/remotion-maps/techniques/cesium/assets/sample-river.geojson +215 -0
  220. package/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-data-sources.md +43 -0
  221. package/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-flyover-architecture.md +128 -0
  222. package/skills/remotion-markup/remotion-maps/techniques/cesium/references/3d-troubleshooting.md +57 -0
  223. package/skills/remotion-markup/remotion-maps/techniques/cesium/scripts/prep-cesium-path.mjs +161 -0
  224. package/skills/remotion-markup/remotion-maps/techniques/mapbox/TECHNIQUE.md +449 -0
  225. package/skills/remotion-markup/remotion-maps/techniques/mapbox/references/render-stability.md +64 -0
  226. package/skills/remotion-markup/remotion-maps/techniques/maplibre/TECHNIQUE.md +465 -0
  227. package/skills/remotion-markup/remotion-maps/techniques/maplibre/references/render-stability.md +64 -0
  228. package/skills/remotion-markup/remotion-maps/techniques/maptiler/TECHNIQUE.md +80 -0
  229. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/CountryLabel.tsx +70 -0
  230. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/MapTilerVectorElement.ts +80 -0
  231. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/RiverReveal.tsx +363 -0
  232. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/example-Root.tsx +22 -0
  233. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/country-meta.json +7535 -0
  234. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/sample-data/yarlung-flow.json +605 -0
  235. package/skills/remotion-markup/remotion-maps/techniques/maptiler/assets/tokens.ts +34 -0
  236. package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-data-sources.md +91 -0
  237. package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-explainer-architecture.md +129 -0
  238. package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/map-geo-prep.md +85 -0
  239. package/skills/remotion-markup/remotion-maps/techniques/maptiler/references/render-stability.md +64 -0
  240. package/skills/remotion-markup/remotion-maps/techniques/maptiler/scripts/prep-geo.mjs +202 -0
  241. package/skills/remotion-markup/remotion-maps/techniques/static-map/TECHNIQUE.md +37 -0
  242. package/skills/remotion-markup/sequencing.md +169 -0
  243. package/skills/remotion-markup/sfx.md +51 -0
  244. package/skills/remotion-markup/silence-detection.md +71 -0
  245. package/skills/remotion-markup/text-highlights.md +56 -0
  246. package/skills/remotion-markup/timing.md +111 -0
  247. package/skills/remotion-markup/transitions.md +239 -0
  248. package/skills/remotion-markup/video-editing.md +90 -0
  249. package/skills/remotion-markup/voiceover.md +99 -0
  250. package/skills/remotion-multimedia/SKILL.md +20 -0
  251. package/skills/remotion-multimedia/agents/openai.yaml +7 -0
  252. package/skills/remotion-multimedia/assets/remotion-icon.png +0 -0
  253. package/skills/remotion-multimedia/get-audio-duration.md +56 -0
  254. package/skills/remotion-multimedia/get-video-dimensions.md +66 -0
  255. package/skills/remotion-multimedia/get-video-duration.md +58 -0
  256. package/skills/remotion-render/SKILL.md +27 -0
  257. package/skills/remotion-render/agents/openai.yaml +7 -0
  258. package/skills/remotion-render/assets/remotion-icon.png +0 -0
  259. package/skills/remotion-render/transparent-videos.md +106 -0
  260. package/skills/remotion-saas/SKILL.md +33 -0
  261. package/skills/remotion-saas/agents/openai.yaml +7 -0
  262. package/skills/remotion-saas/assets/remotion-icon.png +0 -0
  263. package/skills/remotion-saas/framework.md +21 -0
  264. package/skills/remotion-saas/player.md +33 -0
  265. package/skills/remotion-saas/rendering.md +69 -0
  266. package/skills/remotion-studio/SKILL.md +24 -0
  267. package/skills/remotion-studio/agents/openai.yaml +7 -0
  268. package/skills/remotion-studio/assets/remotion-icon.png +0 -0
  269. package/skills/remotion-upgrade/SKILL.md +31 -0
  270. package/skills/remotion-upgrade/agents/openai.yaml +7 -0
  271. package/skills/remotion-upgrade/assets/remotion-icon.png +0 -0
  272. package/skills/remotion/SKILL.md +0 -95
  273. package/skills/remotion/rules/animations.md +0 -31
  274. package/skills/remotion/rules/assets.md +0 -78
  275. package/skills/remotion/rules/can-decode.md +0 -81
  276. package/skills/remotion/rules/charts.md +0 -120
  277. package/skills/remotion/rules/compositions.md +0 -154
  278. package/skills/remotion/rules/extract-frames.md +0 -229
  279. package/skills/remotion/rules/fonts.md +0 -152
  280. package/skills/remotion/rules/images.md +0 -134
  281. package/skills/remotion/rules/light-leaks.md +0 -73
  282. package/skills/remotion/rules/maps.md +0 -412
  283. package/skills/remotion/rules/sfx.md +0 -30
  284. package/skills/remotion/rules/subtitles.md +0 -36
  285. package/skills/remotion/rules/text-animations.md +0 -20
  286. package/skills/remotion/rules/timing.md +0 -136
  287. package/skills/remotion/rules/trimming.md +0 -51
  288. /package/skills/{remotion/rules → remotion-best-practices/remotion-captions}/transcribe-captions.md +0 -0
  289. /package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/3d.md +0 -0
  290. /package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/audio-visualization.md +0 -0
  291. /package/skills/{remotion/rules → remotion-best-practices/remotion-markup}/silence-detection.md +0 -0
  292. /package/skills/{remotion/rules → remotion-best-practices/remotion-render}/transparent-videos.md +0 -0
@@ -0,0 +1,128 @@
1
+ # 3D Flyover — architecture reference
2
+
3
+ Deep detail behind `TECHNIQUE.md`: provider loading, the camera-path pipeline, per-frame camera math, and
4
+ the proven terrain values. Both landscape and city modes have been forward-tested through Remotion.
5
+
6
+ ## 1. Provider initialization
7
+
8
+ Create the Viewer with `baseLayer: false`, UI widgets disabled, and
9
+ `contextOptions.webgl.preserveDrawingBuffer: true`. Never hide the credit display.
10
+
11
+ ### Landscape
12
+
13
+ Add MapTiler `satellite-v2` with `UrlTemplateImageryProvider`, then load
14
+ `terrain-quantized-mesh-v2` with `CesiumTerrainProvider.fromUrl({requestVertexNormals: true})`.
15
+ MapTiler supplies both datasets; no Cesium ion token is required.
16
+
17
+ ### City
18
+
19
+ Do not add MapTiler. Hide the globe, then add:
20
+
21
+ ```ts
22
+ viewer.scene.globe.show = false;
23
+ const tileset = await Cesium.Cesium3DTileset.fromUrl(
24
+ `https://tile.googleapis.com/v1/3dtiles/root.json?key=${GOOGLE_KEY}`,
25
+ {showCreditsOnScreen: true, maximumScreenSpaceError: 4},
26
+ );
27
+ viewer.scene.primitives.add(tileset);
28
+ ```
29
+
30
+ Lower `maximumScreenSpaceError` improves refinement at substantial download/render cost. Start at
31
+ `4` for a hero landmark and `6–8` for wider urban shots. Enforce the Google 30-second promotional
32
+ video ceiling in the component.
33
+
34
+ Load Cesium from the CDN after setting `window.CESIUM_BASE_URL`; the tested version is `1.143`.
35
+
36
+ ## 2. The camera path — structure & generation
37
+
38
+ Four properties matter, in order:
39
+
40
+ 1. **Continuous curvature** — the camera must flow through curves, never "fly straight, snap to a new
41
+ heading, fly straight." The component applies three passes of **Chaikin corner cutting** to every
42
+ supplied path. Each pass replaces a segment with quarter and three-quarter points, rounding a
43
+ corner into a curve. Three passes are the default; four is softer, two is tighter.
44
+ 2. **Constant ground speed** — precompute cumulative distance along the rounded curve and interpolate
45
+ by arc length. Do not animate by source-point index; unequal source spacing creates speed bumps.
46
+ 3. **Minimized amplitude** — for detailed landscape centerlines, dampen the prepared path toward its
47
+ straight start→end chord by a fixed fraction `DAMP` (0 = dead straight, 1 = full river). This is
48
+ the single swerve-amplitude knob.
49
+ 4. **Enough length** — `PATHKM ≥ TRAVEL_KM + 2·LOOK_AHEAD_KM` so the look-ahead aim never clamps.
50
+
51
+ `../scripts/prep-cesium-path.mjs` does: clip a window of the source centerline → resample to even
52
+ arc-length spacing (0.1 km) → moving-average smooth (±2.8 km window, 2 passes) → dampen toward the chord
53
+ (`DAMP=0.45`). Validate with the heading-delta probe it prints — deltas should be small and change
54
+ _gradually_ (water-wars: `3,0,-1,-3,-4,1,7,9,5,-5,-12,-7,…`). Big jumps = corners = bad.
55
+
56
+ The component then applies Chaikin smoothing to this prepared route, or directly to a short
57
+ hand-authored city route. Keep city control points sparse and intentional; smoothing cannot rescue a
58
+ zig-zagging route that crosses the subject repeatedly.
59
+
60
+ **Source data:** OSM via Overpass (~0.3 km vertex spacing) — Natural Earth is too coarse for inner
61
+ gorges. overpass-api.de is often busy → mirror `overpass.kumi.systems`.
62
+
63
+ ## 3. Camera animation per frame (position, heading, pitch, bank)
64
+
65
+ Walk the path by **arc length** (precompute cumulative distances once). Every frame:
66
+
67
+ - **Position** = the point at `dCam` km along the path, altitude `lerp(ALT_START, ALT_END, prog)`.
68
+ - **Heading** = bearing from the camera point to a **real point `LOOK_AHEAD_KM` further along the same
69
+ path**. A far aim averages wiggle → smooth heading; on a curved path it leads into the bend, so the
70
+ heading turns gently with the path. (A local-tangent aim spins the camera at every kink — don't.)
71
+ - **Pitch** = constant. We keep a MapLibre-style param `PITCH_FROM_NADIR` (90 = horizon), then convert:
72
+ **Cesium pitch = `-(90 - PITCH_FROM_NADIR)`** (Cesium: 0 = horizon, -90 = straight down). 76° → -14°.
73
+ - **Bank (roll)** = lean _into_ the turn — the helicopter tell. Measure turn rate as the bearing change
74
+ between `aim` and a point `2·LOOK_AHEAD_KM` ahead; `roll = clamp(dH · BANK_GAIN, ±MAX_BANK)`. Because
75
+ the path is smooth, `dH` changes gradually → the bank eases in and out, never jerks.
76
+
77
+ ```ts
78
+ const setCamera = (C, viewer, prog) => {
79
+ const dCam = Math.min(TRAVEL_KM, PATHKM - LOOK_AHEAD_KM * 2) * prog;
80
+ const cam = alongPath(dCam); // arc-length point
81
+ const aim = alongPath(dCam + LOOK_AHEAD_KM); // heading target (real point on the path)
82
+ const aim2 = alongPath(dCam + LOOK_AHEAD_KM * 2); // turn-rate probe → bank
83
+ const heading = bearing(cam, aim);
84
+ let dH = bearing(aim, aim2) - heading; while (dH > Math.PI) dH -= 2*Math.PI; while (dH < -Math.PI) dH += 2*Math.PI;
85
+ viewer.camera.setView({
86
+ destination: C.Cartesian3.fromDegrees(cam[0], cam[1], lerp(ALT_START, ALT_END, prog)),
87
+ orientation: { heading, pitch: C.Math.toRadians(-(90 - PITCH_FROM_NADIR)), roll: clamp(dH * BANK_GAIN, -MAX_BANK, MAX_BANK) },
88
+ });
89
+ };
90
+ ```
91
+
92
+ > **Cesium vs MapLibre conventions (gotcha):** Cesium heading is radians, 0 = north, clockwise. Pitch
93
+ > 0 = horizon, negative = down (MapLibre is the inverse). Roll positive = bank right; tune the sign by eye.
94
+
95
+ ## 4. The feel — proven water-wars values
96
+
97
+ | Param | Value | Meaning |
98
+ | ------------------------ | ---------------------- | ------------------------------------------------------------------------------------ |
99
+ | `TRAVEL_KM` | 13 | How far the camera travels. **Speed = `TRAVEL_KM / durationSeconds`.** |
100
+ | duration | 24 s (720 f @30) | 13 km / 24 s ≈ **0.54 km/s** — a slow, peaceful glide. 8 s felt "extremely rushed". |
101
+ | `ALT_START → ALT_END` | 4600 → 4300 m ASL | Absolute (terrain-independent). Inside the corridor walls → fly _through_, not over. |
102
+ | `LOOK_AHEAD_KM` | 1.5 | Heading smoothness vs responsiveness. |
103
+ | `PITCH_FROM_NADIR` | 76° | Stare-ahead down the corridor (90 = level). → Cesium -14°. |
104
+ | `MAX_BANK` / `BANK_GAIN` | 0.13 rad (~7.5°) / 0.6 | Helicopter lean into turns. |
105
+ | `verticalExaggeration` | 1.1 | Subtle terrain drama. |
106
+ | `DAMP` (prep) | 0.45 | Swerve amount: higher = weavier, lower = straighter. |
107
+
108
+ **A slow camera renders fast.** At 0.54 km/s the camera moves ~18 m/frame, so tiles stay cached and each
109
+ `settle()` returns almost immediately; the 720-frame render completed in one pass (no chunk-rendering).
110
+
111
+ ## 5. The complete component
112
+
113
+ The full, runnable component is `../assets/CesiumFlythrough.tsx` — read it directly. Its shape:
114
+
115
+ - `loadCesium()` — inject `CESIUM_BASE_URL` + the CDN `Cesium.js`, resolve when loaded.
116
+ - init effect — build the Viewer (§1), `setCamera(…, 0)`, `await settle(viewer)`, `continueRender`.
117
+ - `settle(viewer)` — loop `viewer.render()` until `globe.tilesLoaded` for landscapes or
118
+ `tileset.tilesLoaded` for cities is stable for ~8 ticks (cap ~600).
119
+ - per-frame effect — `delayRender({timeoutInMilliseconds: 60000})` → `setCamera(prog)` → `settle()` → `continueRender`.
120
+
121
+ ## 6. Render
122
+
123
+ ```bash
124
+ bunx remotion still src/index.ts <Comp> out.png --frame=N --gl=angle --timeout=180000 # validate framing/bank first
125
+ bunx remotion render src/index.ts <Comp> out.mp4 --gl=angle --concurrency=1 --timeout=180000
126
+ ```
127
+
128
+ `--gl=angle` is mandatory. Use `--concurrency=1`; `settle()` already serializes tile loading.
@@ -0,0 +1,57 @@
1
+ # 3D Flyover — troubleshooting
2
+
3
+ ## The headless dead-end (why we render through Remotion)
4
+
5
+ Cesium's globe **will not draw in a standalone headless Playwright/Chromium** harness. Verified on
6
+ Apple M4 (ANGLE Metal active, WebGL working): the skybox/stars render, but the globe surface produces
7
+ **zero draw commands** (`scene.frameState.commandList.length === 0`), `globe.tilesLoaded` never goes
8
+ true, and frames come back as the black starfield. No network failures; `sampleTerrainMostDetailed`
9
+ succeeds (terrain data is reachable). Dead-ends tried, all failed:
10
+
11
+ - default render loop, manual `scene.render()`, manual `viewer.render()`, headed mode (context-destroyed).
12
+
13
+ **What works:** render Cesium **through Remotion** — same headless Chrome, but driven by Remotion's frame
14
+ loop with these four non-negotiables:
15
+
16
+ 1. `useDefaultRenderLoop = false` — drive frames by hand.
17
+ 2. Per frame call **`viewer.render()`**, NOT `scene.render()`. `viewer.render()` does the full frame
18
+ (`initializeFrame` → tile streaming → render); `scene.render()` skips frame-init, so tiles never
19
+ advance and the globe never appears. **This is the single most important line.**
20
+ 3. `contextOptions: { webgl: { preserveDrawingBuffer: true } }` so Remotion's screenshot captures pixels.
21
+ 4. Gate init + every frame with `delayRender(…, {timeoutInMilliseconds})` — tile loading can exceed Remotion's
22
+ default; use 60–120 s.
23
+
24
+ The standalone `flythrough.html` / `render.mjs` / `probe.mjs` from the original spike are kept only as the
25
+ record of this dead-end. The canonical render path is the Remotion component
26
+ (`../assets/CesiumFlythrough.tsx`).
27
+
28
+ ## Symptom → fix
29
+
30
+ | Symptom | Cause | Fix |
31
+ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
32
+ | Frames are black with stars | Globe not drawing (headless Playwright, or `scene.render()` used) | Render through Remotion; use `viewer.render()`; `useDefaultRenderLoop=false`. |
33
+ | Screenshots blank/transparent | No `preserveDrawingBuffer` | `contextOptions:{ webgl:{ preserveDrawingBuffer:true } }`. |
34
+ | "delayRender timed out" | Cold tiles exceed the default | `delayRender(…, {timeoutInMilliseconds: 120000})` + `--timeout=180000`. |
35
+ | Globe is a dark/navy sphere | Imagery layer didn't attach | `baseLayer:false` then `viewer.imageryLayers.addImageryProvider(...)`. |
36
+ | High-pitch frame shows a void/starfield above the horizon | No atmosphere | `viewer.scene.skyAtmosphere.show = true`. |
37
+ | 403 on tiles in headless | Domain-locked MapTiler key | Use an **unrestricted** key. |
38
+ | Google root tileset returns 403 | Map Tiles API disabled, billing absent, wrong key, or application restriction blocks local headless rendering | Enable Map Tiles API and billing; restrict the key to that API while allowing the Remotion request. |
39
+ | Google scene shows a duplicate/competing surface | MapTiler or the Cesium globe is still enabled | Do not add MapTiler; set `viewer.scene.globe.show=false`. |
40
+ | Google mesh remains coarse | Screen-space error is too high or the capture starts before refinement | Lower `maximumScreenSpaceError`; settle on `tileset.tilesLoaded`. |
41
+ | WebGL unavailable / software renderer | Missing GL flag | Render with `--gl=angle`. |
42
+ | Camera looks at sky / ground, not terrain | Pitch sign / convention | Cesium pitch 0 = horizon, negative = down (inverse of MapLibre); `-(90 - PITCH_FROM_NADIR)`. |
43
+ | Aim/turn-probe clamps near the end | Path too short | `PATHKM ≥ TRAVEL_KM + 2·LOOK_AHEAD_KM`; raise `WINDOW_KM` in prep. |
44
+ | Path feels like straight-then-corner | Douglas-Peucker simplification | Use resample → moving-average smooth (see architecture §2), not `turf.simplify`. |
45
+ | Camera bumps left and right instead of swerving | Sparse route vertices are still being followed as straight segments | Keep `pathSmoothingPasses={3}`; use sparse intentional control points and arc-length movement. |
46
+
47
+ ## Gotchas checklist
48
+
49
+ - **`viewer.render()`, never `scene.render()`** per frame. The single biggest trap.
50
+ - Cesium loads from **CDN**; set `window.CESIUM_BASE_URL` _before_ injecting the script.
51
+ - `preserveDrawingBuffer: true` or screenshots are blank.
52
+ - `delayRender` uses `timeoutInMilliseconds`; set it to at least 60,000.
53
+ - Terrain: `baseLayer:false`, then add MapTiler imagery.
54
+ - Google: no MapTiler, hide the globe, retain `showCreditsOnScreen:true`.
55
+ - Always `skyAtmosphere.show = true`.
56
+ - Validate the path's heading-delta probe and render one **still** (framing + bank) before the full mp4.
57
+ - Cesium pitch/roll conventions are inverted vs MapLibre.
@@ -0,0 +1,161 @@
1
+ // Camera-path generator for the Cesium flythrough. Turns a river/route centerline GeoJSON into a LONG,
2
+ // CONTINUOUSLY-curving camera path so the camera banks through smooth flowing curves (no
3
+ // straight-then-corner). Method: clip → resample to even spacing → moving-average smooth (inherently
4
+ // continuous curvature) → dampen lateral deviation toward the straight chord (dials swerve amplitude).
5
+ // No Douglas-Peucker (that concentrates curvature at sparse control points → corners).
6
+ //
7
+ // RUN (out of the box, against the shipped sample):
8
+ // node prep-cesium-path.mjs
9
+ // → reads assets/sample-river.geojson (override: node prep-cesium-path.mjs <input.geojson> <output.json>)
10
+ // → writes assets/cesium-path.json (then import that JSON in CesiumFlythrough.tsx, or copy it
11
+ // into your Remotion project's src/geo/ and adjust the import)
12
+ //
13
+ // ADAPT for a new location: change START (a point ON your centerline where the corridor opens),
14
+ // WINDOW_KM, and DAMP/SMOOTH below. Input must be a single LineString feature (features[0].geometry).
15
+
16
+ import {readFileSync, writeFileSync, mkdirSync} from 'fs';
17
+ import {dirname, resolve} from 'path';
18
+ import {fileURLToPath} from 'url';
19
+
20
+ const __dir = dirname(fileURLToPath(import.meta.url));
21
+ const IN = process.argv[2] || resolve(__dir, '../assets/sample-river.geojson');
22
+ const OUT = process.argv[3] || resolve(__dir, '../assets/cesium-path.json');
23
+ const havKm = (a, b) => {
24
+ const R = 6371,
25
+ r = Math.PI / 180,
26
+ dLat = (b[1] - a[1]) * r,
27
+ dLng = (b[0] - a[0]) * r;
28
+ const h =
29
+ Math.sin(dLat / 2) ** 2 +
30
+ Math.cos(a[1] * r) * Math.cos(b[1] * r) * Math.sin(dLng / 2) ** 2;
31
+ return 2 * R * Math.asin(Math.sqrt(h));
32
+ };
33
+
34
+ const gorge = JSON.parse(readFileSync(IN, 'utf8')).features[0].geometry
35
+ .coordinates;
36
+
37
+ // ADAPT: clip ~24 km of river from the reach where the flythrough opens. START must be a point ON the
38
+ // centerline (the script snaps to the nearest vertex). The sample's opening is the Yarlung gorge:
39
+ const START = [94.968, 29.757];
40
+ let s0 = 0,
41
+ best = Infinity;
42
+ gorge.forEach((p, i) => {
43
+ const d = havKm(p, START);
44
+ if (d < best) {
45
+ best = d;
46
+ s0 = i;
47
+ }
48
+ });
49
+ const WINDOW_KM = 30; // clip to ~end of gorge data; smoothing+dampening shrink it to the usable corridor
50
+ const clip = [];
51
+ for (let i = s0, acc = 0; i < gorge.length; i++) {
52
+ if (i > s0) acc += havKm(gorge[i - 1], gorge[i]);
53
+ if (acc > WINDOW_KM) break;
54
+ clip.push(gorge[i]);
55
+ }
56
+
57
+ // Resample to even arc-length spacing so curvature is distributed evenly along the path.
58
+ const STEP_KM = 0.1;
59
+ const resample = (coords) => {
60
+ const out = [coords[0].slice()];
61
+ let carry = 0,
62
+ from = coords[0];
63
+ for (let i = 1; i < coords.length; i++) {
64
+ let segLen = havKm(from, coords[i]);
65
+ while (carry + segLen >= STEP_KM) {
66
+ const t = (STEP_KM - carry) / segLen;
67
+ const np = [
68
+ from[0] + (coords[i][0] - from[0]) * t,
69
+ from[1] + (coords[i][1] - from[1]) * t,
70
+ ];
71
+ out.push(np);
72
+ from = np;
73
+ segLen = havKm(from, coords[i]);
74
+ carry = 0;
75
+ }
76
+ carry += segLen;
77
+ from = coords[i];
78
+ }
79
+ return out;
80
+ };
81
+
82
+ // Moving-average smoothing — inherently continuous (no kinks). Window in points; repeat for extra glass.
83
+ const smoothMA = (coords, w, passes) => {
84
+ let c = coords;
85
+ for (let p = 0; p < passes; p++) {
86
+ c = c.map((_, i) => {
87
+ let sx = 0,
88
+ sy = 0,
89
+ n = 0;
90
+ for (
91
+ let j = Math.max(0, i - w);
92
+ j <= Math.min(c.length - 1, i + w);
93
+ j++
94
+ ) {
95
+ sx += c[j][0];
96
+ sy += c[j][1];
97
+ n++;
98
+ }
99
+ return [sx / n, sy / n];
100
+ });
101
+ }
102
+ return c;
103
+ };
104
+
105
+ const SMOOTH_W = 28; // ±2.8 km window — turns meanders into smooth flowing curves
106
+ const SMOOTH_PASSES = 2;
107
+ const DAMP = 0.45; // keep 45% of the (already-smooth) deviation → gentle, continuous swerve
108
+
109
+ const even = resample(clip);
110
+ const sm = smoothMA(even, SMOOTH_W, SMOOTH_PASSES);
111
+
112
+ const lat0 = (sm[0][1] * Math.PI) / 180;
113
+ const kx = 111.32 * Math.cos(lat0),
114
+ ky = 110.57;
115
+ const toXY = (p) => [(p[0] - sm[0][0]) * kx, (p[1] - sm[0][1]) * ky];
116
+ const toLL = (xy) => [sm[0][0] + xy[0] / kx, sm[0][1] + xy[1] / ky];
117
+ const A = toXY(sm[0]),
118
+ B = toXY(sm[sm.length - 1]);
119
+ const AB = [B[0] - A[0], B[1] - A[1]],
120
+ len2 = AB[0] ** 2 + AB[1] ** 2;
121
+ const path = sm.map((p) => {
122
+ const P = toXY(p);
123
+ const t = ((P[0] - A[0]) * AB[0] + (P[1] - A[1]) * AB[1]) / len2;
124
+ const proj = [A[0] + t * AB[0], A[1] + t * AB[1]];
125
+ return toLL([
126
+ proj[0] + (P[0] - proj[0]) * DAMP,
127
+ proj[1] + (P[1] - proj[1]) * DAMP,
128
+ ]);
129
+ });
130
+
131
+ mkdirSync(dirname(OUT), {recursive: true});
132
+ writeFileSync(OUT, JSON.stringify(path));
133
+
134
+ let len = 0;
135
+ for (let i = 1; i < path.length; i++) len += havKm(path[i - 1], path[i]);
136
+ console.log(
137
+ `cesium-path: clip ${clip.length} → resample ${even.length} → smooth → ${path.length} pts · ${len.toFixed(1)} km`,
138
+ );
139
+ const bear = (a, b) => {
140
+ const r = Math.PI / 180;
141
+ const y = Math.sin((b[0] - a[0]) * r) * Math.cos(b[1] * r);
142
+ const x =
143
+ Math.cos(a[1] * r) * Math.sin(b[1] * r) -
144
+ Math.sin(a[1] * r) * Math.cos(b[1] * r) * Math.cos((b[0] - a[0]) * r);
145
+ return (Math.atan2(y, x) * 180) / Math.PI;
146
+ };
147
+ // heading sampled every ~1.5 km — should change gradually & continuously (no big jumps = no corners)
148
+ const stepPts = Math.round(1.5 / STEP_KM);
149
+ let prev = null,
150
+ hs = [];
151
+ for (let i = 0; i + stepPts < path.length; i += stepPts) {
152
+ const h = bear(path[i], path[i + stepPts]);
153
+ if (prev !== null) {
154
+ let d = h - prev;
155
+ while (d > 180) d -= 360;
156
+ while (d < -180) d += 360;
157
+ hs.push(d.toFixed(0));
158
+ }
159
+ prev = h;
160
+ }
161
+ console.log(` heading deltas every 1.5km (deg): ${hs.join(', ')}`);