cuju-render 0.1.0__py3-none-any.whl

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 (382) hide show
  1. cuju/render/__init__.py +759 -0
  2. cuju/render/__main__.py +1065 -0
  3. cuju/render/_export/__init__.py +3 -0
  4. cuju/render/_export/feed.py +542 -0
  5. cuju/render/_export/sizes.py +157 -0
  6. cuju/render/_export/video.py +1618 -0
  7. cuju/render/_export/video_jobs.py +408 -0
  8. cuju/render/_format/__init__.py +3 -0
  9. cuju/render/_format/annotations.py +235 -0
  10. cuju/render/_format/codec.py +307 -0
  11. cuju/render/_format/keep.py +121 -0
  12. cuju/render/_format/recording.py +860 -0
  13. cuju/render/_format/writer.py +54 -0
  14. cuju/render/_guide/__init__.py +3 -0
  15. cuju/render/_guide/doctor.py +523 -0
  16. cuju/render/_guide/help.py +62 -0
  17. cuju/render/_guide/tutorial.py +254 -0
  18. cuju/render/_http/__init__.py +3 -0
  19. cuju/render/_http/commands.py +57 -0
  20. cuju/render/_http/headers.py +103 -0
  21. cuju/render/_http/launch.py +500 -0
  22. cuju/render/_http/launchers.py +408 -0
  23. cuju/render/_http/pwa.py +128 -0
  24. cuju/render/_http/server.py +2105 -0
  25. cuju/render/_http/window.py +360 -0
  26. cuju/render/_moments/__init__.py +3 -0
  27. cuju/render/_moments/captions.py +284 -0
  28. cuju/render/_moments/events.py +1123 -0
  29. cuju/render/_moments/search.py +694 -0
  30. cuju/render/_packages/__init__.py +3 -0
  31. cuju/render/_packages/glsl.py +746 -0
  32. cuju/render/_packages/loudness.py +334 -0
  33. cuju/render/_packages/pack.py +1959 -0
  34. cuju/render/_packages/presentation.py +1376 -0
  35. cuju/render/_packages/vocabulary.py +609 -0
  36. cuju/render/_playing/__init__.py +3 -0
  37. cuju/render/_playing/achievements.py +463 -0
  38. cuju/render/_playing/bench.py +609 -0
  39. cuju/render/_playing/challenges.py +1813 -0
  40. cuju/render/_playing/demo.py +323 -0
  41. cuju/render/_playing/draw.py +211 -0
  42. cuju/render/_playing/errors.py +20 -0
  43. cuju/render/_playing/game.py +645 -0
  44. cuju/render/_playing/limits.py +339 -0
  45. cuju/render/_playing/play.py +926 -0
  46. cuju/render/_playing/policy_worker.py +250 -0
  47. cuju/render/_playing/strict.py +810 -0
  48. cuju/render/_registry/__init__.py +3 -0
  49. cuju/render/_registry/clips.py +394 -0
  50. cuju/render/_registry/joints.py +108 -0
  51. cuju/render/_registry/teams.py +2058 -0
  52. cuju/render/_store/__init__.py +3 -0
  53. cuju/render/_store/home.py +70 -0
  54. cuju/render/_store/library.py +604 -0
  55. cuju/render/_store/samples.py +163 -0
  56. cuju/render/_text/__init__.py +3 -0
  57. cuju/render/_text/languages.py +637 -0
  58. cuju/render/_text/messages.py +1396 -0
  59. cuju/render/_tournaments/__init__.py +3 -0
  60. cuju/render/_tournaments/results.py +547 -0
  61. cuju/render/_tournaments/tournament.py +2742 -0
  62. cuju/render/_tournaments/tournament_cli.py +587 -0
  63. cuju/render/_tournaments/tournament_runner.py +1975 -0
  64. cuju/render/_version.py +6 -0
  65. cuju/render/_watch/__init__.py +3 -0
  66. cuju/render/_watch/grid.py +265 -0
  67. cuju/render/_watch/live.py +664 -0
  68. cuju/render/_watch/notebook.py +79 -0
  69. cuju/render/_watch/show.py +171 -0
  70. cuju/render/samples/sample-11v11.cjr +0 -0
  71. cuju/render/samples/sample-5v5.cjr +0 -0
  72. cuju/render/samples/teams/starter/main.py +33 -0
  73. cuju/render/scenarios/benchmark_full_game_11_vs_11_easy.py +46 -0
  74. cuju/render/scenarios/benchmark_full_game_11_vs_11_hard.py +46 -0
  75. cuju/render/scenarios/benchmark_full_game_11_vs_11_medium.py +46 -0
  76. cuju/render/scenarios/benchmark_full_game_5_vs_5_easy.py +34 -0
  77. cuju/render/scenarios/benchmark_full_game_5_vs_5_hard.py +34 -0
  78. cuju/render/scenarios/benchmark_full_game_5_vs_5_medium.py +34 -0
  79. cuju/render/web/assets/adboard_polygon.webp +0 -0
  80. cuju/render/web/assets/adboard_your_ad_here.webp +0 -0
  81. cuju/render/web/assets/animations/kaykit-rig-medium-combatmelee.glb +0 -0
  82. cuju/render/web/assets/animations/kaykit-rig-medium-general.glb +0 -0
  83. cuju/render/web/assets/animations/kaykit-rig-medium-movementadvanced.glb +0 -0
  84. cuju/render/web/assets/animations/kaykit-rig-medium-movementbasic.glb +0 -0
  85. cuju/render/web/assets/animations/kaykit-rig-medium-simulation.glb +0 -0
  86. cuju/render/web/assets/animations/kaykit-rig-medium-special.glb +0 -0
  87. cuju/render/web/assets/ball.glb +0 -0
  88. cuju/render/web/assets/challenges/3_vs_1_with_keeper.mp4 +0 -0
  89. cuju/render/web/assets/challenges/3_vs_1_with_keeper.webp +0 -0
  90. cuju/render/web/assets/challenges/corner.mp4 +0 -0
  91. cuju/render/web/assets/challenges/corner.webp +0 -0
  92. cuju/render/web/assets/challenges/counterattack_easy.mp4 +0 -0
  93. cuju/render/web/assets/challenges/counterattack_easy.webp +0 -0
  94. cuju/render/web/assets/challenges/counterattack_hard.mp4 +0 -0
  95. cuju/render/web/assets/challenges/counterattack_hard.webp +0 -0
  96. cuju/render/web/assets/challenges/empty_goal.mp4 +0 -0
  97. cuju/render/web/assets/challenges/empty_goal.webp +0 -0
  98. cuju/render/web/assets/challenges/empty_goal_close.mp4 +0 -0
  99. cuju/render/web/assets/challenges/empty_goal_close.webp +0 -0
  100. cuju/render/web/assets/challenges/manifest.json +375 -0
  101. cuju/render/web/assets/challenges/one_on_one.mp4 +0 -0
  102. cuju/render/web/assets/challenges/one_on_one.webp +0 -0
  103. cuju/render/web/assets/challenges/one_on_one_hard.mp4 +0 -0
  104. cuju/render/web/assets/challenges/one_on_one_hard.webp +0 -0
  105. cuju/render/web/assets/challenges/pass_and_shoot_with_keeper.mp4 +0 -0
  106. cuju/render/web/assets/challenges/pass_and_shoot_with_keeper.webp +0 -0
  107. cuju/render/web/assets/challenges/run_pass_and_shoot_with_keeper.mp4 +0 -0
  108. cuju/render/web/assets/challenges/run_pass_and_shoot_with_keeper.webp +0 -0
  109. cuju/render/web/assets/challenges/run_to_score.mp4 +0 -0
  110. cuju/render/web/assets/challenges/run_to_score.webp +0 -0
  111. cuju/render/web/assets/challenges/run_to_score_with_keeper.mp4 +0 -0
  112. cuju/render/web/assets/challenges/run_to_score_with_keeper.webp +0 -0
  113. cuju/render/web/assets/challenges/single_goal_versus_lazy.mp4 +0 -0
  114. cuju/render/web/assets/challenges/single_goal_versus_lazy.webp +0 -0
  115. cuju/render/web/assets/crowd.webp +0 -0
  116. cuju/render/web/assets/crowd_normal.webp +0 -0
  117. cuju/render/web/assets/cuju-logo-384.png +0 -0
  118. cuju/render/web/assets/cuju-logo.png +0 -0
  119. cuju/render/web/assets/cuju-logo.svg +46 -0
  120. cuju/render/web/assets/cuju-mark-light.svg +33 -0
  121. cuju/render/web/assets/cuju-mark.svg +33 -0
  122. cuju/render/web/assets/goal.glb +0 -0
  123. cuju/render/web/assets/grass.webp +0 -0
  124. cuju/render/web/assets/hair_black.png +0 -0
  125. cuju/render/web/assets/hair_blonde.png +0 -0
  126. cuju/render/web/assets/hair_brown.png +0 -0
  127. cuju/render/web/assets/hair_darkblonde.png +0 -0
  128. cuju/render/web/assets/hair_long01.glb +0 -0
  129. cuju/render/web/assets/hair_long02.glb +0 -0
  130. cuju/render/web/assets/hair_medium01.glb +0 -0
  131. cuju/render/web/assets/hair_red.png +0 -0
  132. cuju/render/web/assets/hair_short01.glb +0 -0
  133. cuju/render/web/assets/hair_short02.glb +0 -0
  134. cuju/render/web/assets/icons/cuju-192.png +0 -0
  135. cuju/render/web/assets/icons/cuju-512.png +0 -0
  136. cuju/render/web/assets/icons/cuju-maskable-512.png +0 -0
  137. cuju/render/web/assets/kit_goalkeeper.webp +0 -0
  138. cuju/render/web/assets/kit_mask.png +0 -0
  139. cuju/render/web/assets/kit_normal.webp +0 -0
  140. cuju/render/web/assets/manifest.json +601 -0
  141. cuju/render/web/assets/models/kaykit-barbarian.glb +0 -0
  142. cuju/render/web/assets/models/kaykit-barbarian.json +23 -0
  143. cuju/render/web/assets/models/kaykit-knight.glb +0 -0
  144. cuju/render/web/assets/models/kaykit-knight.json +23 -0
  145. cuju/render/web/assets/models/kaykit-mage.glb +0 -0
  146. cuju/render/web/assets/models/kaykit-mage.json +23 -0
  147. cuju/render/web/assets/models/kaykit-mannequin-medium.glb +0 -0
  148. cuju/render/web/assets/models/kaykit-mannequin-medium.json +23 -0
  149. cuju/render/web/assets/models/kaykit-ranger.glb +0 -0
  150. cuju/render/web/assets/models/kaykit-ranger.json +23 -0
  151. cuju/render/web/assets/models/kaykit-rogue-hooded.glb +0 -0
  152. cuju/render/web/assets/models/kaykit-rogue-hooded.json +23 -0
  153. cuju/render/web/assets/models/kaykit-rogue.glb +0 -0
  154. cuju/render/web/assets/models/kaykit-rogue.json +23 -0
  155. cuju/render/web/assets/models/kaykit-skeleton-mage.glb +0 -0
  156. cuju/render/web/assets/models/kaykit-skeleton-mage.json +23 -0
  157. cuju/render/web/assets/models/kaykit-skeleton-minion.glb +0 -0
  158. cuju/render/web/assets/models/kaykit-skeleton-minion.json +23 -0
  159. cuju/render/web/assets/models/kaykit-skeleton-rogue.glb +0 -0
  160. cuju/render/web/assets/models/kaykit-skeleton-rogue.json +23 -0
  161. cuju/render/web/assets/models/kaykit-skeleton-warrior.glb +0 -0
  162. cuju/render/web/assets/models/kaykit-skeleton-warrior.json +23 -0
  163. cuju/render/web/assets/pitch.webp +0 -0
  164. cuju/render/web/assets/pitch_normal.webp +0 -0
  165. cuju/render/web/assets/player.glb +0 -0
  166. cuju/render/web/assets/shoe.webp +0 -0
  167. cuju/render/web/assets/shoe_sole.png +0 -0
  168. cuju/render/web/assets/skin_01.png +0 -0
  169. cuju/render/web/assets/skin_02.png +0 -0
  170. cuju/render/web/assets/skin_03.png +0 -0
  171. cuju/render/web/assets/skin_04.png +0 -0
  172. cuju/render/web/assets/sounds/applause.ogg +0 -0
  173. cuju/render/web/assets/sounds/beach-wave-1.ogg +0 -0
  174. cuju/render/web/assets/sounds/beach-wave-2.ogg +0 -0
  175. cuju/render/web/assets/sounds/beach-wave-3.ogg +0 -0
  176. cuju/render/web/assets/sounds/beach-wave-4.ogg +0 -0
  177. cuju/render/web/assets/sounds/city-horn.ogg +0 -0
  178. cuju/render/web/assets/sounds/city-loop.ogg +0 -0
  179. cuju/render/web/assets/sounds/city-siren.ogg +0 -0
  180. cuju/render/web/assets/sounds/crowd-cheer.ogg +0 -0
  181. cuju/render/web/assets/sounds/crowd-loop.ogg +0 -0
  182. cuju/render/web/assets/sounds/crowd-ooh.ogg +0 -0
  183. cuju/render/web/assets/sounds/gulls.ogg +0 -0
  184. cuju/render/web/assets/sounds/neon-sting.ogg +0 -0
  185. cuju/render/web/assets/sounds/rain-loop.ogg +0 -0
  186. cuju/render/web/assets/sounds/sounds.json +46 -0
  187. cuju/render/web/assets/sounds/space-beep.ogg +0 -0
  188. cuju/render/web/assets/sounds/space-hum.ogg +0 -0
  189. cuju/render/web/assets/sounds/space-radio.ogg +0 -0
  190. cuju/render/web/assets/sounds/whistle-long.ogg +0 -0
  191. cuju/render/web/assets/sounds/whistle-short.ogg +0 -0
  192. cuju/render/web/assets/sounds/wind-loop.ogg +0 -0
  193. cuju/render/web/easy.css +357 -0
  194. cuju/render/web/export.html +23 -0
  195. cuju/render/web/feed.css +262 -0
  196. cuju/render/web/feed.html +28 -0
  197. cuju/render/web/flat.css +120 -0
  198. cuju/render/web/home.css +837 -0
  199. cuju/render/web/index.html +373 -0
  200. cuju/render/web/js/boot.js +50 -0
  201. cuju/render/web/js/broadcast/audio.js +2141 -0
  202. cuju/render/web/js/broadcast/celebrate.js +1238 -0
  203. cuju/render/web/js/broadcast/decisions.js +609 -0
  204. cuju/render/web/js/broadcast/hud.js +352 -0
  205. cuju/render/web/js/broadcast/show.js +3614 -0
  206. cuju/render/web/js/broadcast/transition.js +2231 -0
  207. cuju/render/web/js/broadcast/voices.js +153 -0
  208. cuju/render/web/js/capture.js +101 -0
  209. cuju/render/web/js/core/accessibility.js +90 -0
  210. cuju/render/web/js/core/api.js +429 -0
  211. cuju/render/web/js/core/comfort.js +135 -0
  212. cuju/render/web/js/core/i18n.js +705 -0
  213. cuju/render/web/js/core/icons.js +167 -0
  214. cuju/render/web/js/core/input-settings.js +156 -0
  215. cuju/render/web/js/core/keys.js +277 -0
  216. cuju/render/web/js/core/language-ui.js +125 -0
  217. cuju/render/web/js/core/menu.js +853 -0
  218. cuju/render/web/js/core/names.js +113 -0
  219. cuju/render/web/js/core/page-structure.js +110 -0
  220. cuju/render/web/js/core/scenarios.js +109 -0
  221. cuju/render/web/js/core/spoilers.js +236 -0
  222. cuju/render/web/js/core/typeahead.js +38 -0
  223. cuju/render/web/js/export/dom-picture.js +330 -0
  224. cuju/render/web/js/export/export-host.js +97 -0
  225. cuju/render/web/js/export/feed-dialog.js +191 -0
  226. cuju/render/web/js/export/feed-params.js +266 -0
  227. cuju/render/web/js/export/feed.js +363 -0
  228. cuju/render/web/js/export/mp4-mux.js +295 -0
  229. cuju/render/web/js/export/photo-core.js +313 -0
  230. cuju/render/web/js/export/photo.js +1314 -0
  231. cuju/render/web/js/export/safe-frame.js +59 -0
  232. cuju/render/web/js/export/size-fields.js +103 -0
  233. cuju/render/web/js/export/sizes.js +178 -0
  234. cuju/render/web/js/export/video-boot.js +55 -0
  235. cuju/render/web/js/export/video-browser.js +325 -0
  236. cuju/render/web/js/export/video-export.js +417 -0
  237. cuju/render/web/js/export/video-plan.js +207 -0
  238. cuju/render/web/js/export/video-range.js +185 -0
  239. cuju/render/web/js/export/webm-mux.js +198 -0
  240. cuju/render/web/js/feed-boot.js +151 -0
  241. cuju/render/web/js/feed-frame.js +101 -0
  242. cuju/render/web/js/help/doctor.js +488 -0
  243. cuju/render/web/js/help/firstrun.js +379 -0
  244. cuju/render/web/js/help/help-center.js +438 -0
  245. cuju/render/web/js/help/install-offer.js +164 -0
  246. cuju/render/web/js/help/install-state.js +104 -0
  247. cuju/render/web/js/help/lessons-core.js +207 -0
  248. cuju/render/web/js/help/lessons.js +463 -0
  249. cuju/render/web/js/help/palette.js +584 -0
  250. cuju/render/web/js/help/pwa.js +257 -0
  251. cuju/render/web/js/help/tour-core.js +241 -0
  252. cuju/render/web/js/help/tour.js +461 -0
  253. cuju/render/web/js/main.js +2513 -0
  254. cuju/render/web/js/pages/draw.js +188 -0
  255. cuju/render/web/js/pages/fieldpage.js +530 -0
  256. cuju/render/web/js/pages/home.js +521 -0
  257. cuju/render/web/js/pages/matches.js +779 -0
  258. cuju/render/web/js/pages/moments-ui.js +359 -0
  259. cuju/render/web/js/pages/queue-filters.js +63 -0
  260. cuju/render/web/js/pages/recording-groups.js +80 -0
  261. cuju/render/web/js/pages/recordings.js +1069 -0
  262. cuju/render/web/js/play/bench.js +347 -0
  263. cuju/render/web/js/play/challenges.js +1302 -0
  264. cuju/render/web/js/play/medals.js +127 -0
  265. cuju/render/web/js/play/play.js +1953 -0
  266. cuju/render/web/js/play/teasers.js +196 -0
  267. cuju/render/web/js/play/touch.js +350 -0
  268. cuju/render/web/js/play/tournament-layout.js +487 -0
  269. cuju/render/web/js/play/tournament-results.js +441 -0
  270. cuju/render/web/js/play/tournament-strict.js +560 -0
  271. cuju/render/web/js/play/tournament.js +2585 -0
  272. cuju/render/web/js/players/animate.js +972 -0
  273. cuju/render/web/js/players/clips.js +224 -0
  274. cuju/render/web/js/players/kaykit.js +162 -0
  275. cuju/render/web/js/players/kits.js +676 -0
  276. cuju/render/web/js/players/number-patch.js +82 -0
  277. cuju/render/web/js/players/players.js +2694 -0
  278. cuju/render/web/js/players/recolor.js +893 -0
  279. cuju/render/web/js/players/retarget.js +325 -0
  280. cuju/render/web/js/players/rig-numbers.js +174 -0
  281. cuju/render/web/js/presentation/animator.js +231 -0
  282. cuju/render/web/js/presentation/assign.js +85 -0
  283. cuju/render/web/js/presentation/behaviors.js +440 -0
  284. cuju/render/web/js/presentation/budget.js +209 -0
  285. cuju/render/web/js/presentation/catalog.js +1674 -0
  286. cuju/render/web/js/presentation/clocks.js +72 -0
  287. cuju/render/web/js/presentation/commands.js +301 -0
  288. cuju/render/web/js/presentation/contract.js +240 -0
  289. cuju/render/web/js/presentation/effects.js +904 -0
  290. cuju/render/web/js/presentation/flash.js +605 -0
  291. cuju/render/web/js/presentation/freeze-worklet.js +22 -0
  292. cuju/render/web/js/presentation/glsl.js +464 -0
  293. cuju/render/web/js/presentation/host.js +323 -0
  294. cuju/render/web/js/presentation/index.js +2066 -0
  295. cuju/render/web/js/presentation/loudness-worklet.js +235 -0
  296. cuju/render/web/js/presentation/loudness.js +740 -0
  297. cuju/render/web/js/presentation/moments.js +536 -0
  298. cuju/render/web/js/presentation/post.js +327 -0
  299. cuju/render/web/js/presentation/preview.js +180 -0
  300. cuju/render/web/js/presentation/protocol.js +174 -0
  301. cuju/render/web/js/presentation/reach.js +158 -0
  302. cuju/render/web/js/presentation/rigging.js +130 -0
  303. cuju/render/web/js/presentation/sandbox.js +157 -0
  304. cuju/render/web/js/presentation/shaders.js +235 -0
  305. cuju/render/web/js/presentation/stage.js +402 -0
  306. cuju/render/web/js/presentation/teamaudio.js +722 -0
  307. cuju/render/web/js/presentation/tracks.js +197 -0
  308. cuju/render/web/js/presentation/values.js +81 -0
  309. cuju/render/web/js/recording/annotation-data.js +203 -0
  310. cuju/render/web/js/recording/captions.js +491 -0
  311. cuju/render/web/js/recording/codec.js +185 -0
  312. cuju/render/web/js/recording/decode-worker.js +70 -0
  313. cuju/render/web/js/recording/decode.js +94 -0
  314. cuju/render/web/js/recording/episodes.js +46 -0
  315. cuju/render/web/js/recording/format.js +461 -0
  316. cuju/render/web/js/recording/live.js +348 -0
  317. cuju/render/web/js/recording/moments-query.js +59 -0
  318. cuju/render/web/js/recording/moments.js +149 -0
  319. cuju/render/web/js/recording/pose.js +86 -0
  320. cuju/render/web/js/recording/timeline.js +275 -0
  321. cuju/render/web/js/teams/art.js +50 -0
  322. cuju/render/web/js/teams/clip-editor.js +293 -0
  323. cuju/render/web/js/teams/editor.js +1979 -0
  324. cuju/render/web/js/teams/library.js +344 -0
  325. cuju/render/web/js/teams/painter.js +633 -0
  326. cuju/render/web/js/teams/surprise-ui.js +195 -0
  327. cuju/render/web/js/teams/surprise.js +497 -0
  328. cuju/render/web/js/teams/team-check.js +127 -0
  329. cuju/render/web/js/watch/annotations.js +270 -0
  330. cuju/render/web/js/watch/flat.js +366 -0
  331. cuju/render/web/js/watch/grid.js +436 -0
  332. cuju/render/web/js/watch/pitch2d.js +289 -0
  333. cuju/render/web/js/watch/player-tools.js +192 -0
  334. cuju/render/web/js/watch/presets.js +201 -0
  335. cuju/render/web/js/world/arenas.js +997 -0
  336. cuju/render/web/js/world/ball.js +204 -0
  337. cuju/render/web/js/world/cameras.js +982 -0
  338. cuju/render/web/js/world/crowd.js +376 -0
  339. cuju/render/web/js/world/field.js +227 -0
  340. cuju/render/web/js/world/framing.js +145 -0
  341. cuju/render/web/js/world/occlusion.js +48 -0
  342. cuju/render/web/js/world/pitch.js +703 -0
  343. cuju/render/web/js/world/scene.js +395 -0
  344. cuju/render/web/js/world/sky.js +325 -0
  345. cuju/render/web/js/world/stadium.js +1262 -0
  346. cuju/render/web/js/world/vendor-sky.js +367 -0
  347. cuju/render/web/js/world/weather.js +264 -0
  348. cuju/render/web/languages/en.json +4750 -0
  349. cuju/render/web/lessons.json +137 -0
  350. cuju/render/web/manifest.webmanifest +23 -0
  351. cuju/render/web/style.css +8399 -0
  352. cuju/render/web/sw.js +235 -0
  353. cuju/render/web/vendor/fabric/LICENSE +16 -0
  354. cuju/render/web/vendor/fabric/fabric.min.mjs +1 -0
  355. cuju/render/web/vendor/lucide/LICENSE +43 -0
  356. cuju/render/web/vendor/lucide/icons.js +141 -0
  357. cuju/render/web/vendor/three/LICENSE +21 -0
  358. cuju/render/web/vendor/three/build/three.core.js +60586 -0
  359. cuju/render/web/vendor/three/build/three.module.js +19719 -0
  360. cuju/render/web/vendor/three/examples/jsm/loaders/GLTFLoader.js +4925 -0
  361. cuju/render/web/vendor/three/examples/jsm/postprocessing/EffectComposer.js +365 -0
  362. cuju/render/web/vendor/three/examples/jsm/postprocessing/MaskPass.js +195 -0
  363. cuju/render/web/vendor/three/examples/jsm/postprocessing/OutputPass.js +148 -0
  364. cuju/render/web/vendor/three/examples/jsm/postprocessing/Pass.js +191 -0
  365. cuju/render/web/vendor/three/examples/jsm/postprocessing/RenderPass.js +193 -0
  366. cuju/render/web/vendor/three/examples/jsm/postprocessing/ShaderPass.js +135 -0
  367. cuju/render/web/vendor/three/examples/jsm/postprocessing/UnrealBloomPass.js +541 -0
  368. cuju/render/web/vendor/three/examples/jsm/shaders/CopyShader.js +52 -0
  369. cuju/render/web/vendor/three/examples/jsm/shaders/LuminosityHighPassShader.js +68 -0
  370. cuju/render/web/vendor/three/examples/jsm/shaders/OutputShader.js +103 -0
  371. cuju/render/web/vendor/three/examples/jsm/utils/BufferGeometryUtils.js +1501 -0
  372. cuju/render/web/vendor/three/examples/jsm/utils/SkeletonUtils.js +496 -0
  373. cuju_render-0.1.0.dist-info/METADATA +116 -0
  374. cuju_render-0.1.0.dist-info/RECORD +382 -0
  375. cuju_render-0.1.0.dist-info/WHEEL +4 -0
  376. cuju_render-0.1.0.dist-info/licenses/LICENSE +202 -0
  377. cuju_render-0.1.0.dist-info/licenses/LICENSES/CC-BY-4.0.txt +396 -0
  378. cuju_render-0.1.0.dist-info/licenses/LICENSES/CC0-1.0.txt +127 -0
  379. cuju_render-0.1.0.dist-info/licenses/LICENSES/ISC.txt +16 -0
  380. cuju_render-0.1.0.dist-info/licenses/LICENSES/MIT.txt +24 -0
  381. cuju_render-0.1.0.dist-info/licenses/LICENSES/Unlicense.txt +13 -0
  382. cuju_render-0.1.0.dist-info/licenses/NOTICE +35 -0
@@ -0,0 +1,463 @@
1
+ // Copyright 2026 The cuju Authors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // The hands-on lessons. A small panel at the bottom of the window asks the person to do one thing,
5
+ // such as jumping to a goal or following a player, offers a sample first when the lesson needs a
6
+ // recording, and watches the page's own state a few times a second until the thing is done. The
7
+ // browser keeps the lessons done, Reset forgets them, and every lesson done is reported to the
8
+ // server, so `cuju render tutorial` sees the lessons that only a page can check. Those lessons are
9
+ // also watched while no panel shows, so a script that follows the steps of the tutorial reports
10
+ // them, and on load the page takes in the lessons that the server knows done. The panel is a
11
+ // region beside the page, so every control stays usable, and Esc closes it while it has the
12
+ // focus. Scripts reach it as window.cuju.tutorial.
13
+
14
+ import { LESSONS_KEY, checkLesson, doneCount, lessonAnnouncement, lessonAskNodes, lessonPraiseNodes, lessonTitle, markDone, needMet, nextLesson, progressState } from './lessons-core.js';
15
+ import { t, tn } from '../core/i18n.js';
16
+ import { icon, reicon, relabel, symbolOnly } from '../core/icons.js';
17
+
18
+ // The panel looks this often while a lesson is under way.
19
+ const LOOK_MS = 400;
20
+ // The teams of the registry are read this often while the lesson of a team is under way.
21
+ const TEAMS_MS = 3000;
22
+
23
+ function h(tag, attributes = {}, ...children) {
24
+ const node = document.createElement(tag);
25
+ for (const [key, value] of Object.entries(attributes)) {
26
+ if (key.startsWith('on') && typeof value === 'function') {
27
+ node.addEventListener(key.slice(2), value);
28
+ } else if (value !== null && value !== undefined && value !== false) {
29
+ node.setAttribute(key, value === true ? '' : value);
30
+ }
31
+ }
32
+ node.append(...children.flat().filter((child) => child !== null && child !== undefined));
33
+ return node;
34
+ }
35
+
36
+ export async function loadCatalog() {
37
+ const res = await fetch('lessons.json', { cache: 'no-cache' });
38
+ if (!res.ok) {
39
+ throw new Error(t('lessons.loadFailed', { status: res.status }));
40
+ }
41
+ return (await res.json()).lessons;
42
+ }
43
+
44
+ export class Lessons {
45
+ // helpers holds ensure(need), which adds a sample and resolves once it is there, and
46
+ // onChange(), which redraws the list of the Help page.
47
+ constructor(app, lessons, helpers) {
48
+ this.app = app;
49
+ this.lessons = lessons;
50
+ this.ids = lessons.map((lesson) => lesson.id);
51
+ this.helpers = helpers;
52
+ this.progress = this.read();
53
+ this.active = null;
54
+ this.base = null;
55
+ this.memory = {};
56
+ this.teamCount = null;
57
+ this.count = h('p', { class: 'lesson-count' });
58
+ this.title = h('h2', { id: 'lesson-title', tabindex: '-1' });
59
+ this.ask = h('p', { class: 'lesson-ask' });
60
+ this.offerButton = h('button', { type: 'button', class: 'btn small', onclick: () => this.fillNeed() });
61
+ this.goButton = h('button', { type: 'button', class: 'btn small', onclick: () => this.goThere() });
62
+ this.offer = h('div', { class: 'lesson-offer' }, this.offerButton, this.goButton);
63
+ this.status = h('p', { class: 'lesson-status', role: 'status', 'aria-live': 'polite' });
64
+ this.nextButton = h('button', { type: 'button', class: 'btn primary small', ...symbolOnly(t('lessons.skip')), onclick: () => this.advance() }, icon('next'));
65
+ this.panel = h('aside', { id: 'lesson-panel', class: 'lesson-panel', role: 'region', 'aria-labelledby': 'lesson-title', hidden: true },
66
+ this.count, this.title, this.ask, this.offer, this.status,
67
+ h('div', { class: 'lesson-actions' }, this.nextButton,
68
+ h('button', { type: 'button', class: 'btn small', ...symbolOnly(t('lessons.close')), onclick: () => this.stop(true) }, icon('close'))));
69
+ this.panel.addEventListener('keydown', (e) => {
70
+ if (e.key === 'Escape') {
71
+ e.preventDefault();
72
+ e.stopPropagation();
73
+ this.stop(true);
74
+ }
75
+ });
76
+ (document.getElementById('app') || document.body).append(this.panel);
77
+ // The lessons that only a page can check are watched all the time, so a person or a
78
+ // script that does one without starting it, as the steps of `cuju render tutorial` do,
79
+ // still reports it.
80
+ this.watched = lessons.filter((lesson) => lesson.agent && lesson.agent.check === 'page').map((lesson) => lesson.id);
81
+ this.background = {};
82
+ this.watchTimer = setInterval(() => this.watch(), LOOK_MS);
83
+ this.synced = this.sync();
84
+ }
85
+
86
+ // Takes in the lessons that the server knows done, those other pages reported and those whose
87
+ // checks of the library hold, so a fresh browser shows the progress the server has.
88
+ async sync() {
89
+ // An answer to a look that began before a reset holds the lessons the reset forgot, so a
90
+ // look waits for a reset under way and drops an answer that a reset overtook.
91
+ await this.resetting;
92
+ const resets = this.resets || 0;
93
+ try {
94
+ const res = await fetch('/api/help/tutorial', { cache: 'no-store' });
95
+ if (!res.ok) {
96
+ return this.state();
97
+ }
98
+ const server = await res.json();
99
+ if ((this.resets || 0) !== resets) {
100
+ return this.state();
101
+ }
102
+ const done = (server.lessons || []).filter((entry) => entry.done && !(entry.id in this.progress.done));
103
+ if (done.length) {
104
+ const when = new Date().toISOString();
105
+ for (const entry of done) {
106
+ this.progress = markDone(this.progress, entry.id, when, this.ids);
107
+ }
108
+ this.save();
109
+ if (this.active) {
110
+ this.showNext(this.active);
111
+ }
112
+ }
113
+ } catch {
114
+ // The server is away, the browser keeps what it has.
115
+ }
116
+ return this.state();
117
+ }
118
+
119
+ // One look for the lessons of the page that are not done and not under way.
120
+ watch() {
121
+ if (document.hidden) {
122
+ return;
123
+ }
124
+ const waiting = this.watched.filter((id) => !(id in this.progress.done) && !(this.active && this.active.id === id));
125
+ if (!waiting.length) {
126
+ return;
127
+ }
128
+ // Watched in the background, the seeks of a replay or of the show after the match stay
129
+ // out, so watching a match with its replays leaves Jump to a goal open.
130
+ const app = this.app;
131
+ const snap = { ...this.snapshot(), show: !!((app.director && app.director.active) || (app.postMatch && app.postMatch.running)) };
132
+ for (const id of waiting) {
133
+ const entry = this.background[id] || (this.background[id] = { base: snap, memory: {} });
134
+ if ((entry.base.source && entry.base.source.id) !== (snap.source && snap.source.id)) {
135
+ entry.base = snap;
136
+ }
137
+ // A lesson counts once its check turns true, so a state that already holds when the
138
+ // watching begins, such as a followed player at a reset, stays out.
139
+ if (!checkLesson(id, snap, entry.base, entry.memory)) {
140
+ entry.ready = true;
141
+ } else if (entry.ready) {
142
+ delete this.background[id];
143
+ this.progress = markDone(this.progress, id, new Date().toISOString(), this.ids);
144
+ this.save();
145
+ this.report([id]);
146
+ }
147
+ }
148
+ }
149
+
150
+ read() {
151
+ try {
152
+ return progressState(JSON.parse(localStorage.getItem(LESSONS_KEY)), this.ids);
153
+ } catch {
154
+ return progressState(null, this.ids);
155
+ }
156
+ }
157
+
158
+ save() {
159
+ try {
160
+ localStorage.setItem(LESSONS_KEY, JSON.stringify(this.progress));
161
+ } catch {
162
+ // Storage can be unavailable, the lessons then last for this visit only.
163
+ }
164
+ this.helpers.onChange();
165
+ }
166
+
167
+ lesson(id) {
168
+ return this.lessons.find((lesson) => lesson.id === id) || null;
169
+ }
170
+
171
+ get isOpen() {
172
+ return !this.panel.hidden;
173
+ }
174
+
175
+ // What the page holds now, for the checks of lessons-core.js.
176
+ snapshot() {
177
+ const app = this.app;
178
+ const tl = app.timeline;
179
+ const source = app.source && !app.source.game ? { kind: app.source.kind, id: app.source.id } : null;
180
+ const play = app.play;
181
+ const game = play && play.game;
182
+ let running = null;
183
+ if (game && game.started && !game.ended && game.source && game.source.store) {
184
+ const store = game.source.store;
185
+ const frame = store.get(store.last);
186
+ running = { id: game.id, running: !game.paused, step: frame && typeof frame.step === 'number' ? frame.step : null };
187
+ }
188
+ let challenge = false;
189
+ try {
190
+ const page = app.challengesPage;
191
+ const state = page && page.state();
192
+ challenge = !!(state && (state.run || (state.jobs && state.jobs.length)));
193
+ } catch {
194
+ challenge = false;
195
+ }
196
+ const capture = app.photo && app.photo.lastCapture;
197
+ return {
198
+ at: performance.now(),
199
+ page: app.page,
200
+ source,
201
+ t: source && tl ? tl.t : null,
202
+ sps: source && tl ? tl.sps : null,
203
+ playing: !!(source && tl && tl.playing),
204
+ jumps: source && tl ? tl.jumps || 0 : 0,
205
+ speed: tl ? tl.direction * tl.speed : 1,
206
+ goals: source && tl && tl.store ? tl.store.goals.map((goal) => goal.index) : [],
207
+ camera: app.cameras ? app.cameras.mode : null,
208
+ game: running,
209
+ teams: this.teamCount,
210
+ challenge,
211
+ photo: capture ? JSON.stringify(capture) : null,
212
+ };
213
+ }
214
+
215
+ // Begins a lesson, by default the next one not done, on its page.
216
+ start(id = null) {
217
+ const lesson = this.lesson(id || this.progress.current || nextLesson(this.progress, this.ids) || this.ids[0]);
218
+ if (!lesson) {
219
+ return this.state();
220
+ }
221
+ this.active = lesson;
222
+ this.progress = { ...this.progress, current: lesson.id };
223
+ this.save();
224
+ this.memory = {};
225
+ this.teamCount = null;
226
+ this.base = null;
227
+ const index = this.ids.indexOf(lesson.id);
228
+ this.count.textContent = t('lessons.count', { index: index + 1, count: this.ids.length });
229
+ this.title.textContent = lessonTitle(lesson);
230
+ this.ask.replaceChildren(...lessonAskNodes(lesson));
231
+ this.panel.hidden = false;
232
+ this.panel.classList.remove('lesson-done');
233
+ if (this.app.page !== lesson.page && !(lesson.page === 'watch' && this.app.page === 'watch')) {
234
+ this.app.showPage(lesson.page);
235
+ }
236
+ const done = lesson.id in this.progress.done;
237
+ this.status.replaceChildren(...(done ? tn('lessons.doneBefore') : [lessonAnnouncement(lesson, index, this.ids.length)]));
238
+ this.showNext(lesson);
239
+ this.updateOffer();
240
+ this.title.focus({ preventScroll: true });
241
+ clearInterval(this.timer);
242
+ this.timer = setInterval(() => this.look(), LOOK_MS);
243
+ this.look();
244
+ return this.state();
245
+ }
246
+
247
+ // The button that moves on names the step it takes, with the symbol of an arrow, or a check
248
+ // mark for the last lesson.
249
+ showNext(lesson) {
250
+ const label = this.nextLabel(lesson);
251
+ relabel(this.nextButton, label);
252
+ reicon(this.nextButton, label === t('lessons.finish') ? 'check' : 'next');
253
+ }
254
+
255
+ nextLabel(lesson) {
256
+ const after = nextLesson(this.progress, this.ids, lesson.id);
257
+ if (lesson.id in this.progress.done) {
258
+ return after ? t('lessons.next') : t('lessons.finish');
259
+ }
260
+ return t('lessons.skip');
261
+ }
262
+
263
+ updateOffer() {
264
+ const lesson = this.active;
265
+ if (!lesson) {
266
+ return;
267
+ }
268
+ const snap = this.snapshot();
269
+ const missing = !needMet(lesson, snap);
270
+ const team = lesson.id === 'register_team' && !(lesson.id in this.progress.done);
271
+ this.offerButton.hidden = !(missing || team);
272
+ this.offerButton.textContent = team ? t('lessons.offer.team') : t('lessons.offer.recording');
273
+ this.offerButton.disabled = false;
274
+ const away = this.app.page !== lesson.page;
275
+ this.goButton.hidden = !away;
276
+ this.goButton.textContent = t('lessons.go', { page: t(`palette.page.${lesson.page}`) });
277
+ this.offer.hidden = this.offerButton.hidden && this.goButton.hidden;
278
+ }
279
+
280
+ async fillNeed() {
281
+ const lesson = this.active;
282
+ if (!lesson) {
283
+ return;
284
+ }
285
+ this.offerButton.disabled = true;
286
+ this.status.textContent = t('lessons.adding');
287
+ try {
288
+ await this.helpers.ensure(lesson.id === 'register_team' ? 'team' : 'recording');
289
+ this.status.textContent = lesson.id === 'register_team' ? t('lessons.added.team') : t('lessons.added.recording');
290
+ } catch (err) {
291
+ this.status.textContent = t('lessons.addFailed', { error: err.message });
292
+ }
293
+ this.offerButton.disabled = false;
294
+ const focused = document.activeElement === this.offerButton || document.activeElement === document.body;
295
+ this.updateOffer();
296
+ // The offer hides once its sample is there, so the focus goes on to the next button of
297
+ // the panel rather than to the page.
298
+ if (focused && this.isOpen && this.offerButton.hidden) {
299
+ (this.goButton.hidden ? this.nextButton : this.goButton).focus({ preventScroll: true });
300
+ }
301
+ }
302
+
303
+ goThere() {
304
+ if (this.active) {
305
+ this.app.showPage(this.active.page);
306
+ this.updateOffer();
307
+ }
308
+ }
309
+
310
+ async readTeams() {
311
+ if (this.teamsBusy || (this.teamsAt && performance.now() - this.teamsAt < TEAMS_MS)) {
312
+ return;
313
+ }
314
+ this.teamsBusy = true;
315
+ try {
316
+ const { api } = await import('../core/api.js');
317
+ const teams = await api.teams();
318
+ this.teamCount = teams.filter((team) => team.kind !== 'builtin').length;
319
+ } catch {
320
+ // The server is away, the lesson waits for it.
321
+ } finally {
322
+ this.teamsAt = performance.now();
323
+ this.teamsBusy = false;
324
+ }
325
+ }
326
+
327
+ // One look at the page, which ends the lesson once its check holds.
328
+ look() {
329
+ const lesson = this.active;
330
+ if (!lesson || !this.isOpen) {
331
+ return;
332
+ }
333
+ if (lesson.id === 'register_team') {
334
+ this.readTeams();
335
+ }
336
+ const snap = this.snapshot();
337
+ // A lesson compares with the page as it stood when the lesson began, or when the recording
338
+ // that it shows changed.
339
+ if (!this.base || (this.base.source && this.base.source.id) !== (snap.source && snap.source.id)) {
340
+ this.base = snap;
341
+ }
342
+ this.panel.classList.toggle('lesson-compact', !!snap.game && this.app.page === 'play');
343
+ this.updateOffer();
344
+ if (lesson.id === 'play_game' && snap.game && !this.memory.reported) {
345
+ const step = snap.game.step - (this.memory.firstStep ?? snap.game.step);
346
+ if (step > 0 && step < 300) {
347
+ const seconds = Math.floor(step / 10);
348
+ if (seconds !== this.memory.shownSeconds && seconds % 5 === 0) {
349
+ this.memory.shownSeconds = seconds;
350
+ this.status.textContent = t('lessons.played', { count: seconds });
351
+ }
352
+ }
353
+ }
354
+ if (!checkLesson(lesson.id, snap, this.base, this.memory) || this.memory.reported) {
355
+ return;
356
+ }
357
+ this.memory.reported = true;
358
+ this.complete(lesson);
359
+ }
360
+
361
+ complete(lesson) {
362
+ this.progress = markDone(this.progress, lesson.id, new Date().toISOString(), this.ids);
363
+ this.save();
364
+ this.panel.classList.add('lesson-done');
365
+ const praise = document.createDocumentFragment();
366
+ praise.append(...lessonPraiseNodes(lesson));
367
+ this.status.replaceChildren(...tn('lessons.done', { praise }));
368
+ this.showNext(lesson);
369
+ this.report([lesson.id]);
370
+ if (this.onDone) {
371
+ this.onDone(lesson.id);
372
+ }
373
+ }
374
+
375
+ async report(ids) {
376
+ try {
377
+ await fetch('/api/help/tutorial', {
378
+ method: 'POST', cache: 'no-store', headers: { 'Content-Type': 'application/json' },
379
+ body: JSON.stringify({ done: ids }),
380
+ });
381
+ } catch {
382
+ // The server is away, the browser keeps the lesson all the same.
383
+ }
384
+ }
385
+
386
+ // The next lesson not done, or the end of the tutorial.
387
+ advance() {
388
+ const lesson = this.active;
389
+ const after = lesson ? nextLesson(this.progress, this.ids, lesson.id) : nextLesson(this.progress, this.ids);
390
+ if (!after || after === (lesson && lesson.id)) {
391
+ this.stop(false);
392
+ this.progress = { ...this.progress, current: null };
393
+ this.save();
394
+ const all = doneCount(this.progress, this.ids) === this.ids.length;
395
+ this.app.hud?.toast(all ? t('lessons.allDone') : t('lessons.stopped'), 'info', 4000);
396
+ return this.state();
397
+ }
398
+ return this.start(after);
399
+ }
400
+
401
+ // Closes the panel, and with focus gives the focus back to the page.
402
+ stop(focus = false) {
403
+ clearInterval(this.timer);
404
+ this.timer = null;
405
+ const inside = this.panel.contains(document.activeElement);
406
+ this.panel.hidden = true;
407
+ this.active = null;
408
+ if (focus || inside) {
409
+ document.getElementById('pages')?.focus({ preventScroll: true });
410
+ }
411
+ return this.state();
412
+ }
413
+
414
+ // Forgets every lesson done, in the browser and on the server.
415
+ async reset() {
416
+ this.resets = (this.resets || 0) + 1;
417
+ this.stop(false);
418
+ this.progress = progressState(null, this.ids);
419
+ this.background = {};
420
+ this.save();
421
+ // The page lessons take their starting point at once, so a step that follows the reset
422
+ // before the next look still counts.
423
+ this.watch();
424
+ this.resetting = (async () => {
425
+ try {
426
+ await fetch('/api/help/tutorial', {
427
+ method: 'POST', cache: 'no-store', headers: { 'Content-Type': 'application/json' },
428
+ body: JSON.stringify({ reset: true }),
429
+ });
430
+ } catch {
431
+ // The server is away, the browser has forgotten the lessons all the same.
432
+ }
433
+ })();
434
+ await this.resetting;
435
+ return this.state();
436
+ }
437
+
438
+ state() {
439
+ return {
440
+ active: this.active ? this.active.id : null,
441
+ done: Object.keys(this.progress.done).filter((id) => this.ids.includes(id)),
442
+ next: nextLesson(this.progress, this.ids),
443
+ count: this.ids.length,
444
+ };
445
+ }
446
+
447
+ // The functions of window.cuju.tutorial.
448
+ script() {
449
+ return {
450
+ lessons: () => this.lessons.map((lesson) => ({ id: lesson.id, title: lesson.title, page: lesson.page, ask: lesson.ask, needs: lesson.needs || null, done: lesson.id in this.progress.done })),
451
+ start: (id) => this.start(id || null),
452
+ stop: () => this.stop(false),
453
+ next: () => this.advance(),
454
+ check: () => {
455
+ this.look();
456
+ return this.state();
457
+ },
458
+ reset: () => this.reset(),
459
+ state: () => this.state(),
460
+ snapshot: () => this.snapshot(),
461
+ };
462
+ }
463
+ }