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.
- cuju/render/__init__.py +759 -0
- cuju/render/__main__.py +1065 -0
- cuju/render/_export/__init__.py +3 -0
- cuju/render/_export/feed.py +542 -0
- cuju/render/_export/sizes.py +157 -0
- cuju/render/_export/video.py +1618 -0
- cuju/render/_export/video_jobs.py +408 -0
- cuju/render/_format/__init__.py +3 -0
- cuju/render/_format/annotations.py +235 -0
- cuju/render/_format/codec.py +307 -0
- cuju/render/_format/keep.py +121 -0
- cuju/render/_format/recording.py +860 -0
- cuju/render/_format/writer.py +54 -0
- cuju/render/_guide/__init__.py +3 -0
- cuju/render/_guide/doctor.py +523 -0
- cuju/render/_guide/help.py +62 -0
- cuju/render/_guide/tutorial.py +254 -0
- cuju/render/_http/__init__.py +3 -0
- cuju/render/_http/commands.py +57 -0
- cuju/render/_http/headers.py +103 -0
- cuju/render/_http/launch.py +500 -0
- cuju/render/_http/launchers.py +408 -0
- cuju/render/_http/pwa.py +128 -0
- cuju/render/_http/server.py +2105 -0
- cuju/render/_http/window.py +360 -0
- cuju/render/_moments/__init__.py +3 -0
- cuju/render/_moments/captions.py +284 -0
- cuju/render/_moments/events.py +1123 -0
- cuju/render/_moments/search.py +694 -0
- cuju/render/_packages/__init__.py +3 -0
- cuju/render/_packages/glsl.py +746 -0
- cuju/render/_packages/loudness.py +334 -0
- cuju/render/_packages/pack.py +1959 -0
- cuju/render/_packages/presentation.py +1376 -0
- cuju/render/_packages/vocabulary.py +609 -0
- cuju/render/_playing/__init__.py +3 -0
- cuju/render/_playing/achievements.py +463 -0
- cuju/render/_playing/bench.py +609 -0
- cuju/render/_playing/challenges.py +1813 -0
- cuju/render/_playing/demo.py +323 -0
- cuju/render/_playing/draw.py +211 -0
- cuju/render/_playing/errors.py +20 -0
- cuju/render/_playing/game.py +645 -0
- cuju/render/_playing/limits.py +339 -0
- cuju/render/_playing/play.py +926 -0
- cuju/render/_playing/policy_worker.py +250 -0
- cuju/render/_playing/strict.py +810 -0
- cuju/render/_registry/__init__.py +3 -0
- cuju/render/_registry/clips.py +394 -0
- cuju/render/_registry/joints.py +108 -0
- cuju/render/_registry/teams.py +2058 -0
- cuju/render/_store/__init__.py +3 -0
- cuju/render/_store/home.py +70 -0
- cuju/render/_store/library.py +604 -0
- cuju/render/_store/samples.py +163 -0
- cuju/render/_text/__init__.py +3 -0
- cuju/render/_text/languages.py +637 -0
- cuju/render/_text/messages.py +1396 -0
- cuju/render/_tournaments/__init__.py +3 -0
- cuju/render/_tournaments/results.py +547 -0
- cuju/render/_tournaments/tournament.py +2742 -0
- cuju/render/_tournaments/tournament_cli.py +587 -0
- cuju/render/_tournaments/tournament_runner.py +1975 -0
- cuju/render/_version.py +6 -0
- cuju/render/_watch/__init__.py +3 -0
- cuju/render/_watch/grid.py +265 -0
- cuju/render/_watch/live.py +664 -0
- cuju/render/_watch/notebook.py +79 -0
- cuju/render/_watch/show.py +171 -0
- cuju/render/samples/sample-11v11.cjr +0 -0
- cuju/render/samples/sample-5v5.cjr +0 -0
- cuju/render/samples/teams/starter/main.py +33 -0
- cuju/render/scenarios/benchmark_full_game_11_vs_11_easy.py +46 -0
- cuju/render/scenarios/benchmark_full_game_11_vs_11_hard.py +46 -0
- cuju/render/scenarios/benchmark_full_game_11_vs_11_medium.py +46 -0
- cuju/render/scenarios/benchmark_full_game_5_vs_5_easy.py +34 -0
- cuju/render/scenarios/benchmark_full_game_5_vs_5_hard.py +34 -0
- cuju/render/scenarios/benchmark_full_game_5_vs_5_medium.py +34 -0
- cuju/render/web/assets/adboard_polygon.webp +0 -0
- cuju/render/web/assets/adboard_your_ad_here.webp +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-combatmelee.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-general.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-movementadvanced.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-movementbasic.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-simulation.glb +0 -0
- cuju/render/web/assets/animations/kaykit-rig-medium-special.glb +0 -0
- cuju/render/web/assets/ball.glb +0 -0
- cuju/render/web/assets/challenges/3_vs_1_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/3_vs_1_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/corner.mp4 +0 -0
- cuju/render/web/assets/challenges/corner.webp +0 -0
- cuju/render/web/assets/challenges/counterattack_easy.mp4 +0 -0
- cuju/render/web/assets/challenges/counterattack_easy.webp +0 -0
- cuju/render/web/assets/challenges/counterattack_hard.mp4 +0 -0
- cuju/render/web/assets/challenges/counterattack_hard.webp +0 -0
- cuju/render/web/assets/challenges/empty_goal.mp4 +0 -0
- cuju/render/web/assets/challenges/empty_goal.webp +0 -0
- cuju/render/web/assets/challenges/empty_goal_close.mp4 +0 -0
- cuju/render/web/assets/challenges/empty_goal_close.webp +0 -0
- cuju/render/web/assets/challenges/manifest.json +375 -0
- cuju/render/web/assets/challenges/one_on_one.mp4 +0 -0
- cuju/render/web/assets/challenges/one_on_one.webp +0 -0
- cuju/render/web/assets/challenges/one_on_one_hard.mp4 +0 -0
- cuju/render/web/assets/challenges/one_on_one_hard.webp +0 -0
- cuju/render/web/assets/challenges/pass_and_shoot_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/pass_and_shoot_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/run_pass_and_shoot_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/run_pass_and_shoot_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/run_to_score.mp4 +0 -0
- cuju/render/web/assets/challenges/run_to_score.webp +0 -0
- cuju/render/web/assets/challenges/run_to_score_with_keeper.mp4 +0 -0
- cuju/render/web/assets/challenges/run_to_score_with_keeper.webp +0 -0
- cuju/render/web/assets/challenges/single_goal_versus_lazy.mp4 +0 -0
- cuju/render/web/assets/challenges/single_goal_versus_lazy.webp +0 -0
- cuju/render/web/assets/crowd.webp +0 -0
- cuju/render/web/assets/crowd_normal.webp +0 -0
- cuju/render/web/assets/cuju-logo-384.png +0 -0
- cuju/render/web/assets/cuju-logo.png +0 -0
- cuju/render/web/assets/cuju-logo.svg +46 -0
- cuju/render/web/assets/cuju-mark-light.svg +33 -0
- cuju/render/web/assets/cuju-mark.svg +33 -0
- cuju/render/web/assets/goal.glb +0 -0
- cuju/render/web/assets/grass.webp +0 -0
- cuju/render/web/assets/hair_black.png +0 -0
- cuju/render/web/assets/hair_blonde.png +0 -0
- cuju/render/web/assets/hair_brown.png +0 -0
- cuju/render/web/assets/hair_darkblonde.png +0 -0
- cuju/render/web/assets/hair_long01.glb +0 -0
- cuju/render/web/assets/hair_long02.glb +0 -0
- cuju/render/web/assets/hair_medium01.glb +0 -0
- cuju/render/web/assets/hair_red.png +0 -0
- cuju/render/web/assets/hair_short01.glb +0 -0
- cuju/render/web/assets/hair_short02.glb +0 -0
- cuju/render/web/assets/icons/cuju-192.png +0 -0
- cuju/render/web/assets/icons/cuju-512.png +0 -0
- cuju/render/web/assets/icons/cuju-maskable-512.png +0 -0
- cuju/render/web/assets/kit_goalkeeper.webp +0 -0
- cuju/render/web/assets/kit_mask.png +0 -0
- cuju/render/web/assets/kit_normal.webp +0 -0
- cuju/render/web/assets/manifest.json +601 -0
- cuju/render/web/assets/models/kaykit-barbarian.glb +0 -0
- cuju/render/web/assets/models/kaykit-barbarian.json +23 -0
- cuju/render/web/assets/models/kaykit-knight.glb +0 -0
- cuju/render/web/assets/models/kaykit-knight.json +23 -0
- cuju/render/web/assets/models/kaykit-mage.glb +0 -0
- cuju/render/web/assets/models/kaykit-mage.json +23 -0
- cuju/render/web/assets/models/kaykit-mannequin-medium.glb +0 -0
- cuju/render/web/assets/models/kaykit-mannequin-medium.json +23 -0
- cuju/render/web/assets/models/kaykit-ranger.glb +0 -0
- cuju/render/web/assets/models/kaykit-ranger.json +23 -0
- cuju/render/web/assets/models/kaykit-rogue-hooded.glb +0 -0
- cuju/render/web/assets/models/kaykit-rogue-hooded.json +23 -0
- cuju/render/web/assets/models/kaykit-rogue.glb +0 -0
- cuju/render/web/assets/models/kaykit-rogue.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-mage.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-mage.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-minion.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-minion.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-rogue.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-rogue.json +23 -0
- cuju/render/web/assets/models/kaykit-skeleton-warrior.glb +0 -0
- cuju/render/web/assets/models/kaykit-skeleton-warrior.json +23 -0
- cuju/render/web/assets/pitch.webp +0 -0
- cuju/render/web/assets/pitch_normal.webp +0 -0
- cuju/render/web/assets/player.glb +0 -0
- cuju/render/web/assets/shoe.webp +0 -0
- cuju/render/web/assets/shoe_sole.png +0 -0
- cuju/render/web/assets/skin_01.png +0 -0
- cuju/render/web/assets/skin_02.png +0 -0
- cuju/render/web/assets/skin_03.png +0 -0
- cuju/render/web/assets/skin_04.png +0 -0
- cuju/render/web/assets/sounds/applause.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-1.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-2.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-3.ogg +0 -0
- cuju/render/web/assets/sounds/beach-wave-4.ogg +0 -0
- cuju/render/web/assets/sounds/city-horn.ogg +0 -0
- cuju/render/web/assets/sounds/city-loop.ogg +0 -0
- cuju/render/web/assets/sounds/city-siren.ogg +0 -0
- cuju/render/web/assets/sounds/crowd-cheer.ogg +0 -0
- cuju/render/web/assets/sounds/crowd-loop.ogg +0 -0
- cuju/render/web/assets/sounds/crowd-ooh.ogg +0 -0
- cuju/render/web/assets/sounds/gulls.ogg +0 -0
- cuju/render/web/assets/sounds/neon-sting.ogg +0 -0
- cuju/render/web/assets/sounds/rain-loop.ogg +0 -0
- cuju/render/web/assets/sounds/sounds.json +46 -0
- cuju/render/web/assets/sounds/space-beep.ogg +0 -0
- cuju/render/web/assets/sounds/space-hum.ogg +0 -0
- cuju/render/web/assets/sounds/space-radio.ogg +0 -0
- cuju/render/web/assets/sounds/whistle-long.ogg +0 -0
- cuju/render/web/assets/sounds/whistle-short.ogg +0 -0
- cuju/render/web/assets/sounds/wind-loop.ogg +0 -0
- cuju/render/web/easy.css +357 -0
- cuju/render/web/export.html +23 -0
- cuju/render/web/feed.css +262 -0
- cuju/render/web/feed.html +28 -0
- cuju/render/web/flat.css +120 -0
- cuju/render/web/home.css +837 -0
- cuju/render/web/index.html +373 -0
- cuju/render/web/js/boot.js +50 -0
- cuju/render/web/js/broadcast/audio.js +2141 -0
- cuju/render/web/js/broadcast/celebrate.js +1238 -0
- cuju/render/web/js/broadcast/decisions.js +609 -0
- cuju/render/web/js/broadcast/hud.js +352 -0
- cuju/render/web/js/broadcast/show.js +3614 -0
- cuju/render/web/js/broadcast/transition.js +2231 -0
- cuju/render/web/js/broadcast/voices.js +153 -0
- cuju/render/web/js/capture.js +101 -0
- cuju/render/web/js/core/accessibility.js +90 -0
- cuju/render/web/js/core/api.js +429 -0
- cuju/render/web/js/core/comfort.js +135 -0
- cuju/render/web/js/core/i18n.js +705 -0
- cuju/render/web/js/core/icons.js +167 -0
- cuju/render/web/js/core/input-settings.js +156 -0
- cuju/render/web/js/core/keys.js +277 -0
- cuju/render/web/js/core/language-ui.js +125 -0
- cuju/render/web/js/core/menu.js +853 -0
- cuju/render/web/js/core/names.js +113 -0
- cuju/render/web/js/core/page-structure.js +110 -0
- cuju/render/web/js/core/scenarios.js +109 -0
- cuju/render/web/js/core/spoilers.js +236 -0
- cuju/render/web/js/core/typeahead.js +38 -0
- cuju/render/web/js/export/dom-picture.js +330 -0
- cuju/render/web/js/export/export-host.js +97 -0
- cuju/render/web/js/export/feed-dialog.js +191 -0
- cuju/render/web/js/export/feed-params.js +266 -0
- cuju/render/web/js/export/feed.js +363 -0
- cuju/render/web/js/export/mp4-mux.js +295 -0
- cuju/render/web/js/export/photo-core.js +313 -0
- cuju/render/web/js/export/photo.js +1314 -0
- cuju/render/web/js/export/safe-frame.js +59 -0
- cuju/render/web/js/export/size-fields.js +103 -0
- cuju/render/web/js/export/sizes.js +178 -0
- cuju/render/web/js/export/video-boot.js +55 -0
- cuju/render/web/js/export/video-browser.js +325 -0
- cuju/render/web/js/export/video-export.js +417 -0
- cuju/render/web/js/export/video-plan.js +207 -0
- cuju/render/web/js/export/video-range.js +185 -0
- cuju/render/web/js/export/webm-mux.js +198 -0
- cuju/render/web/js/feed-boot.js +151 -0
- cuju/render/web/js/feed-frame.js +101 -0
- cuju/render/web/js/help/doctor.js +488 -0
- cuju/render/web/js/help/firstrun.js +379 -0
- cuju/render/web/js/help/help-center.js +438 -0
- cuju/render/web/js/help/install-offer.js +164 -0
- cuju/render/web/js/help/install-state.js +104 -0
- cuju/render/web/js/help/lessons-core.js +207 -0
- cuju/render/web/js/help/lessons.js +463 -0
- cuju/render/web/js/help/palette.js +584 -0
- cuju/render/web/js/help/pwa.js +257 -0
- cuju/render/web/js/help/tour-core.js +241 -0
- cuju/render/web/js/help/tour.js +461 -0
- cuju/render/web/js/main.js +2513 -0
- cuju/render/web/js/pages/draw.js +188 -0
- cuju/render/web/js/pages/fieldpage.js +530 -0
- cuju/render/web/js/pages/home.js +521 -0
- cuju/render/web/js/pages/matches.js +779 -0
- cuju/render/web/js/pages/moments-ui.js +359 -0
- cuju/render/web/js/pages/queue-filters.js +63 -0
- cuju/render/web/js/pages/recording-groups.js +80 -0
- cuju/render/web/js/pages/recordings.js +1069 -0
- cuju/render/web/js/play/bench.js +347 -0
- cuju/render/web/js/play/challenges.js +1302 -0
- cuju/render/web/js/play/medals.js +127 -0
- cuju/render/web/js/play/play.js +1953 -0
- cuju/render/web/js/play/teasers.js +196 -0
- cuju/render/web/js/play/touch.js +350 -0
- cuju/render/web/js/play/tournament-layout.js +487 -0
- cuju/render/web/js/play/tournament-results.js +441 -0
- cuju/render/web/js/play/tournament-strict.js +560 -0
- cuju/render/web/js/play/tournament.js +2585 -0
- cuju/render/web/js/players/animate.js +972 -0
- cuju/render/web/js/players/clips.js +224 -0
- cuju/render/web/js/players/kaykit.js +162 -0
- cuju/render/web/js/players/kits.js +676 -0
- cuju/render/web/js/players/number-patch.js +82 -0
- cuju/render/web/js/players/players.js +2694 -0
- cuju/render/web/js/players/recolor.js +893 -0
- cuju/render/web/js/players/retarget.js +325 -0
- cuju/render/web/js/players/rig-numbers.js +174 -0
- cuju/render/web/js/presentation/animator.js +231 -0
- cuju/render/web/js/presentation/assign.js +85 -0
- cuju/render/web/js/presentation/behaviors.js +440 -0
- cuju/render/web/js/presentation/budget.js +209 -0
- cuju/render/web/js/presentation/catalog.js +1674 -0
- cuju/render/web/js/presentation/clocks.js +72 -0
- cuju/render/web/js/presentation/commands.js +301 -0
- cuju/render/web/js/presentation/contract.js +240 -0
- cuju/render/web/js/presentation/effects.js +904 -0
- cuju/render/web/js/presentation/flash.js +605 -0
- cuju/render/web/js/presentation/freeze-worklet.js +22 -0
- cuju/render/web/js/presentation/glsl.js +464 -0
- cuju/render/web/js/presentation/host.js +323 -0
- cuju/render/web/js/presentation/index.js +2066 -0
- cuju/render/web/js/presentation/loudness-worklet.js +235 -0
- cuju/render/web/js/presentation/loudness.js +740 -0
- cuju/render/web/js/presentation/moments.js +536 -0
- cuju/render/web/js/presentation/post.js +327 -0
- cuju/render/web/js/presentation/preview.js +180 -0
- cuju/render/web/js/presentation/protocol.js +174 -0
- cuju/render/web/js/presentation/reach.js +158 -0
- cuju/render/web/js/presentation/rigging.js +130 -0
- cuju/render/web/js/presentation/sandbox.js +157 -0
- cuju/render/web/js/presentation/shaders.js +235 -0
- cuju/render/web/js/presentation/stage.js +402 -0
- cuju/render/web/js/presentation/teamaudio.js +722 -0
- cuju/render/web/js/presentation/tracks.js +197 -0
- cuju/render/web/js/presentation/values.js +81 -0
- cuju/render/web/js/recording/annotation-data.js +203 -0
- cuju/render/web/js/recording/captions.js +491 -0
- cuju/render/web/js/recording/codec.js +185 -0
- cuju/render/web/js/recording/decode-worker.js +70 -0
- cuju/render/web/js/recording/decode.js +94 -0
- cuju/render/web/js/recording/episodes.js +46 -0
- cuju/render/web/js/recording/format.js +461 -0
- cuju/render/web/js/recording/live.js +348 -0
- cuju/render/web/js/recording/moments-query.js +59 -0
- cuju/render/web/js/recording/moments.js +149 -0
- cuju/render/web/js/recording/pose.js +86 -0
- cuju/render/web/js/recording/timeline.js +275 -0
- cuju/render/web/js/teams/art.js +50 -0
- cuju/render/web/js/teams/clip-editor.js +293 -0
- cuju/render/web/js/teams/editor.js +1979 -0
- cuju/render/web/js/teams/library.js +344 -0
- cuju/render/web/js/teams/painter.js +633 -0
- cuju/render/web/js/teams/surprise-ui.js +195 -0
- cuju/render/web/js/teams/surprise.js +497 -0
- cuju/render/web/js/teams/team-check.js +127 -0
- cuju/render/web/js/watch/annotations.js +270 -0
- cuju/render/web/js/watch/flat.js +366 -0
- cuju/render/web/js/watch/grid.js +436 -0
- cuju/render/web/js/watch/pitch2d.js +289 -0
- cuju/render/web/js/watch/player-tools.js +192 -0
- cuju/render/web/js/watch/presets.js +201 -0
- cuju/render/web/js/world/arenas.js +997 -0
- cuju/render/web/js/world/ball.js +204 -0
- cuju/render/web/js/world/cameras.js +982 -0
- cuju/render/web/js/world/crowd.js +376 -0
- cuju/render/web/js/world/field.js +227 -0
- cuju/render/web/js/world/framing.js +145 -0
- cuju/render/web/js/world/occlusion.js +48 -0
- cuju/render/web/js/world/pitch.js +703 -0
- cuju/render/web/js/world/scene.js +395 -0
- cuju/render/web/js/world/sky.js +325 -0
- cuju/render/web/js/world/stadium.js +1262 -0
- cuju/render/web/js/world/vendor-sky.js +367 -0
- cuju/render/web/js/world/weather.js +264 -0
- cuju/render/web/languages/en.json +4750 -0
- cuju/render/web/lessons.json +137 -0
- cuju/render/web/manifest.webmanifest +23 -0
- cuju/render/web/style.css +8399 -0
- cuju/render/web/sw.js +235 -0
- cuju/render/web/vendor/fabric/LICENSE +16 -0
- cuju/render/web/vendor/fabric/fabric.min.mjs +1 -0
- cuju/render/web/vendor/lucide/LICENSE +43 -0
- cuju/render/web/vendor/lucide/icons.js +141 -0
- cuju/render/web/vendor/three/LICENSE +21 -0
- cuju/render/web/vendor/three/build/three.core.js +60586 -0
- cuju/render/web/vendor/three/build/three.module.js +19719 -0
- cuju/render/web/vendor/three/examples/jsm/loaders/GLTFLoader.js +4925 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/EffectComposer.js +365 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/MaskPass.js +195 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/OutputPass.js +148 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/Pass.js +191 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/RenderPass.js +193 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/ShaderPass.js +135 -0
- cuju/render/web/vendor/three/examples/jsm/postprocessing/UnrealBloomPass.js +541 -0
- cuju/render/web/vendor/three/examples/jsm/shaders/CopyShader.js +52 -0
- cuju/render/web/vendor/three/examples/jsm/shaders/LuminosityHighPassShader.js +68 -0
- cuju/render/web/vendor/three/examples/jsm/shaders/OutputShader.js +103 -0
- cuju/render/web/vendor/three/examples/jsm/utils/BufferGeometryUtils.js +1501 -0
- cuju/render/web/vendor/three/examples/jsm/utils/SkeletonUtils.js +496 -0
- cuju_render-0.1.0.dist-info/METADATA +116 -0
- cuju_render-0.1.0.dist-info/RECORD +382 -0
- cuju_render-0.1.0.dist-info/WHEEL +4 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSE +202 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/CC-BY-4.0.txt +396 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/CC0-1.0.txt +127 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/ISC.txt +16 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/MIT.txt +24 -0
- cuju_render-0.1.0.dist-info/licenses/LICENSES/Unlicense.txt +13 -0
- cuju_render-0.1.0.dist-info/licenses/NOTICE +35 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright 2026 The cuju Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
// The state of the offer to install the page as an app, shared by the offer on Home and the
|
|
5
|
+
// Install the app part of Help. Chrome and Edge fire beforeinstallprompt once a page load, often
|
|
6
|
+
// before the modules of the page load, so js/boot.js keeps the event in window.cujuInstall and
|
|
7
|
+
// says each change with the event cuju-install on the window. The browser keeps a dismissal of the
|
|
8
|
+
// offer, and the rules at the top of the file touch nothing of the page.
|
|
9
|
+
|
|
10
|
+
export const OFFER_KEY = 'cuju.installOffer';
|
|
11
|
+
// The page loads that pass before the offer shows, so a first visit stays with its first tips.
|
|
12
|
+
export const QUIET_VISITS = 1;
|
|
13
|
+
const MOST_VISITS = 1000;
|
|
14
|
+
|
|
15
|
+
// The stored state of the offer, whether it was dismissed and how many times the page loaded.
|
|
16
|
+
export function offerState(stored) {
|
|
17
|
+
const source = stored && typeof stored === 'object' ? stored : {};
|
|
18
|
+
const visits = Number.isInteger(source.visits) && source.visits > 0 ? Math.min(source.visits, MOST_VISITS) : 0;
|
|
19
|
+
return { dismissed: source.dismissed === true, visits };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// The state after one more load of the page.
|
|
23
|
+
export function countVisit(state) {
|
|
24
|
+
const clean = offerState(state);
|
|
25
|
+
return { ...clean, visits: Math.min(clean.visits + 1, MOST_VISITS) };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// The state after the person turns the offer down, which keeps it away for good.
|
|
29
|
+
export function dismissOffer(state) {
|
|
30
|
+
return { ...offerState(state), dismissed: true };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Whether the offer shows on Home. It needs the browser's own offer, a page that is no installed
|
|
34
|
+
// app, a visit after the first, no dismissal, the Home page and nothing open over it.
|
|
35
|
+
export function offerShown({ state, prompt, installed, page, busy }) {
|
|
36
|
+
const clean = offerState(state);
|
|
37
|
+
return !!prompt && !installed && !clean.dismissed && clean.visits > QUIET_VISITS && page === 'home' && !busy;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The way this browser installs a page as an app. browser, it fires beforeinstallprompt, as
|
|
41
|
+
// Chrome, Edge and other Chromium browsers do. safari, Safari on a Mac, whose File menu adds the
|
|
42
|
+
// page to the Dock. command, any other browser, for which cuju render app --install makes the app.
|
|
43
|
+
export function installRoute({ hasEvent, userAgent = '', vendor = '' }) {
|
|
44
|
+
if (hasEvent) {
|
|
45
|
+
return 'browser';
|
|
46
|
+
}
|
|
47
|
+
const apple = /Apple/.test(vendor) && /Safari\//.test(userAgent) && !/(Chrome|CriOS|FxiOS|Edg)\//.test(userAgent);
|
|
48
|
+
if (apple && /Macintosh/.test(userAgent)) {
|
|
49
|
+
return 'safari';
|
|
50
|
+
}
|
|
51
|
+
return 'command';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Whether the page runs as an app, an installed page, a page added to the Dock or the window of
|
|
55
|
+
// cuju render app through the system's web view.
|
|
56
|
+
export function runsAsApp(win = globalThis) {
|
|
57
|
+
const media = (query) => !!(win.matchMedia && win.matchMedia(query).matches);
|
|
58
|
+
return media('(display-mode: standalone)') || media('(display-mode: window-controls-overlay)')
|
|
59
|
+
|| media('(display-mode: minimal-ui)') || win.navigator?.standalone === true || !!win.pywebview;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// What boot.js keeps, the browser's offer and whether the page was installed during this visit.
|
|
63
|
+
function held() {
|
|
64
|
+
const win = globalThis.window;
|
|
65
|
+
if (win && !win.cujuInstall) {
|
|
66
|
+
win.cujuInstall = { prompt: null, installed: false };
|
|
67
|
+
}
|
|
68
|
+
return win ? win.cujuInstall : { prompt: null, installed: false };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function heldPrompt() {
|
|
72
|
+
return held().prompt;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function installedNow() {
|
|
76
|
+
return held().installed || runsAsApp();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Calls fn on each change of the offer or of the install.
|
|
80
|
+
export function onInstallChange(fn) {
|
|
81
|
+
globalThis.window?.addEventListener('cuju-install', fn);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function changed() {
|
|
85
|
+
const win = globalThis.window;
|
|
86
|
+
if (win && typeof win.dispatchEvent === 'function' && typeof Event === 'function') {
|
|
87
|
+
win.dispatchEvent(new Event('cuju-install'));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Shows the browser's offer, which it gives once, and returns the person's answer, accepted or
|
|
92
|
+
// dismissed, or unavailable when the browser holds no offer.
|
|
93
|
+
export async function promptInstall() {
|
|
94
|
+
const keep = held();
|
|
95
|
+
const prompt = keep.prompt;
|
|
96
|
+
if (!prompt) {
|
|
97
|
+
return { outcome: 'unavailable' };
|
|
98
|
+
}
|
|
99
|
+
keep.prompt = null;
|
|
100
|
+
changed();
|
|
101
|
+
await prompt.prompt();
|
|
102
|
+
const choice = await prompt.userChoice;
|
|
103
|
+
return { outcome: choice && choice.outcome === 'accepted' ? 'accepted' : 'dismissed' };
|
|
104
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// Copyright 2026 The cuju Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
// The rules of the hands-on lessons. The catalog of lessons is web/lessons.json, which the page
|
|
5
|
+
// and the command `cuju render tutorial` both read. A lesson asks the person to do one thing and
|
|
6
|
+
// ends when the page's own state shows it done. The page takes a snapshot of its state a few times
|
|
7
|
+
// a second, and checkLesson compares it with the snapshot taken when the lesson began, keeping
|
|
8
|
+
// what it needs between two looks in a memory of the lesson. The browser keeps the lessons done.
|
|
9
|
+
// Nothing here touches the page, so the rules hold the same in a test. The page shows the title,
|
|
10
|
+
// the ask and the praise of a lesson as the messages lesson.<id>.title, .ask and .praise, whose
|
|
11
|
+
// English is the catalog's, and the catalog's own text stands in for a lesson without messages.
|
|
12
|
+
|
|
13
|
+
import { has, plainMarks, plainText, t, tn, tOr } from '../core/i18n.js';
|
|
14
|
+
|
|
15
|
+
export const LESSONS_KEY = 'cuju.lessons';
|
|
16
|
+
|
|
17
|
+
// The camera modes that follow one player.
|
|
18
|
+
export const FOLLOW_MODES = ['player', 'owner', 'fpp'];
|
|
19
|
+
// The camera modes that a person chooses, as the View menu lists them. The shows of the page move
|
|
20
|
+
// the camera through modes of their own, which no lesson counts.
|
|
21
|
+
export const CHOSEN_MODES = ['broadcast', 'tactical', 'goal', 'player', 'free', 'ball', 'owner', 'fpp'];
|
|
22
|
+
// Steps of a game that make 30 seconds of match time, at ten steps a second.
|
|
23
|
+
export const PLAYED_STEPS = 300;
|
|
24
|
+
// How far before and after a goal a seek lands to count as a jump to it, in seconds. N lands six
|
|
25
|
+
// seconds before the goal.
|
|
26
|
+
export const GOAL_BEFORE = 8;
|
|
27
|
+
export const GOAL_AFTER = 4;
|
|
28
|
+
// A move of the timeline between two looks that is this many seconds more than playing explains
|
|
29
|
+
// counts as a jump.
|
|
30
|
+
export const JUMP_SECONDS = 2;
|
|
31
|
+
|
|
32
|
+
// The stored progress, the lessons done with the time of each and the lesson under way, kept to
|
|
33
|
+
// the lessons of the catalog.
|
|
34
|
+
export function progressState(stored, ids) {
|
|
35
|
+
const source = stored && typeof stored === 'object' ? stored : {};
|
|
36
|
+
const known = new Set(ids);
|
|
37
|
+
const done = {};
|
|
38
|
+
if (source.done && typeof source.done === 'object' && !Array.isArray(source.done)) {
|
|
39
|
+
for (const [id, when] of Object.entries(source.done)) {
|
|
40
|
+
if (known.has(id) && typeof when === 'string') {
|
|
41
|
+
done[id] = when;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const current = typeof source.current === 'string' && known.has(source.current) ? source.current : null;
|
|
46
|
+
return { done, current };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// The progress once a lesson is done, which keeps the first time it was done.
|
|
50
|
+
export function markDone(progress, id, when, ids) {
|
|
51
|
+
const clean = progressState(progress, ids);
|
|
52
|
+
if (!ids.includes(id)) {
|
|
53
|
+
return clean;
|
|
54
|
+
}
|
|
55
|
+
return { ...clean, done: { ...clean.done, [id]: clean.done[id] || when } };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// The first lesson not done after the given one, then from the start, or null when all are done.
|
|
59
|
+
export function nextLesson(progress, ids, after = null) {
|
|
60
|
+
const clean = progressState(progress, ids);
|
|
61
|
+
const from = after ? ids.indexOf(after) + 1 : 0;
|
|
62
|
+
const order = [...ids.slice(from), ...ids.slice(0, from)];
|
|
63
|
+
return order.find((id) => !(id in clean.done)) || null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// How many lessons are done.
|
|
67
|
+
export function doneCount(progress, ids) {
|
|
68
|
+
const clean = progressState(progress, ids);
|
|
69
|
+
return ids.filter((id) => id in clean.done).length;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Whether a lesson's need is there, a recording that plays or nothing.
|
|
73
|
+
export function needMet(lesson, snap) {
|
|
74
|
+
if (!lesson || !lesson.needs) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (lesson.needs === 'recording') {
|
|
78
|
+
return !!(snap && snap.source);
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Whether the timeline moved by a jump between two looks, more than playing explains.
|
|
84
|
+
export function jumped(previous, snap) {
|
|
85
|
+
if (!previous || !snap || !snap.source || !previous.source || previous.source.id !== snap.source.id) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (typeof previous.t !== 'number' || typeof snap.t !== 'number' || !snap.sps) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const seconds = Math.max(0, (snap.at - previous.at) / 1000);
|
|
92
|
+
const played = previous.playing ? Math.abs(previous.speed || 1) * seconds * snap.sps : 0;
|
|
93
|
+
return Math.abs(snap.t - previous.t) > played + JUMP_SECONDS * snap.sps;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Whether the timeline stands at a goal, from a little before it to a little after.
|
|
97
|
+
export function atGoal(snap) {
|
|
98
|
+
if (!snap || !snap.source || !Array.isArray(snap.goals) || !snap.sps || typeof snap.t !== 'number') {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return snap.goals.some((index) => snap.t >= index - GOAL_BEFORE * snap.sps && snap.t <= index + GOAL_AFTER * snap.sps);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Whether a lesson is done, from the snapshot now, the one of the lesson's start and the memory of
|
|
105
|
+
// the lesson, which this function fills.
|
|
106
|
+
export function checkLesson(id, snap, base, memory = {}) {
|
|
107
|
+
if (!snap) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
switch (id) {
|
|
111
|
+
case 'open_sample':
|
|
112
|
+
return !!snap.source && (snap.source.kind === 'match' || snap.source.kind === 'file');
|
|
113
|
+
case 'seek_goal': {
|
|
114
|
+
// A replay and the show after the match seek on their own. A snapshot marked show, as
|
|
115
|
+
// the watching in the background marks them, keeps their seeks out, from the first look
|
|
116
|
+
// during the show to the first look after it.
|
|
117
|
+
if (snap.show) {
|
|
118
|
+
memory.inShow = true;
|
|
119
|
+
memory.previous = null;
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
// The timeline counts its jumps, so a jump counts even when the recording opened since
|
|
123
|
+
// the last look. Jumps made before the lesson began stay out, and a recording opened
|
|
124
|
+
// later counts from its start.
|
|
125
|
+
const id = snap.source ? snap.source.id : null;
|
|
126
|
+
if (!memory.seeks || memory.seeks.id !== id) {
|
|
127
|
+
const before = !memory.seeks && base && base.source && base.source.id === id ? (base.jumps || 0) : 0;
|
|
128
|
+
memory.seeks = { id, jumps: before };
|
|
129
|
+
}
|
|
130
|
+
if (memory.inShow) {
|
|
131
|
+
memory.inShow = false;
|
|
132
|
+
memory.seeks.jumps = snap.jumps || 0;
|
|
133
|
+
}
|
|
134
|
+
if (jumped(memory.previous, snap) || (snap.jumps || 0) > memory.seeks.jumps) {
|
|
135
|
+
memory.jumps = (memory.jumps || 0) + 1;
|
|
136
|
+
}
|
|
137
|
+
memory.seeks.jumps = Math.max(memory.seeks.jumps, snap.jumps || 0);
|
|
138
|
+
memory.previous = snap;
|
|
139
|
+
return !!memory.jumps && atGoal(snap);
|
|
140
|
+
}
|
|
141
|
+
case 'switch_camera': {
|
|
142
|
+
// The first chosen camera seen with the recording is the one to switch from.
|
|
143
|
+
if (!snap.source || !CHOSEN_MODES.includes(snap.camera)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (memory.camera === undefined || memory.cameraSource !== snap.source.id) {
|
|
147
|
+
memory.camera = snap.camera;
|
|
148
|
+
memory.cameraSource = snap.source.id;
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
return snap.camera !== memory.camera;
|
|
152
|
+
}
|
|
153
|
+
case 'follow_player':
|
|
154
|
+
return !!snap.source && FOLLOW_MODES.includes(snap.camera);
|
|
155
|
+
case 'play_game': {
|
|
156
|
+
const game = snap.game;
|
|
157
|
+
if (!game || !game.running || typeof game.step !== 'number') {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
if (memory.gameId !== game.id) {
|
|
161
|
+
memory.gameId = game.id;
|
|
162
|
+
memory.firstStep = game.step;
|
|
163
|
+
}
|
|
164
|
+
memory.firstStep = Math.min(memory.firstStep, game.step);
|
|
165
|
+
return game.step - memory.firstStep >= PLAYED_STEPS;
|
|
166
|
+
}
|
|
167
|
+
case 'register_team':
|
|
168
|
+
return (snap.teams || 0) > 0;
|
|
169
|
+
case 'start_challenge':
|
|
170
|
+
return !!snap.challenge;
|
|
171
|
+
case 'make_photo':
|
|
172
|
+
return !!snap.photo && (!base || snap.photo !== base.photo);
|
|
173
|
+
default:
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The title, the ask and the praise of a lesson in the page's language.
|
|
179
|
+
export function lessonTitle(lesson) {
|
|
180
|
+
return tOr(`lesson.${lesson.id}.title`, lesson.title);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function lessonAsk(lesson) {
|
|
184
|
+
return tOr(`lesson.${lesson.id}.ask`, lesson.ask);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function lessonPraise(lesson) {
|
|
188
|
+
return tOr(`lesson.${lesson.id}.praise`, lesson.praise);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// The ask and the praise as nodes, their marks as strong words, code and keycaps, for the page.
|
|
192
|
+
function markedOr(id, fallback) {
|
|
193
|
+
return has(id) ? tn(id) : [plainMarks(plainText(fallback))];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function lessonAskNodes(lesson) {
|
|
197
|
+
return markedOr(`lesson.${lesson.id}.ask`, lesson.ask);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function lessonPraiseNodes(lesson) {
|
|
201
|
+
return markedOr(`lesson.${lesson.id}.praise`, lesson.praise);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// The words a screen reader hears when a lesson begins.
|
|
205
|
+
export function lessonAnnouncement(lesson, index, count) {
|
|
206
|
+
return t('lessons.announce', { index: index + 1, count, title: lessonTitle(lesson), ask: lessonAsk(lesson) });
|
|
207
|
+
}
|