@scratch/scratch-vm 11.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsdoc.json +20 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +7004 -0
- package/LICENSE +12 -0
- package/README.md +120 -0
- package/TRADEMARK +1 -0
- package/commitlint.config.js +4 -0
- package/docs/extensions.md +527 -0
- package/package.json +103 -0
- package/release.config.js +13 -0
- package/src/blocks/scratch3_control.js +206 -0
- package/src/blocks/scratch3_core_example.js +69 -0
- package/src/blocks/scratch3_data.js +257 -0
- package/src/blocks/scratch3_event.js +137 -0
- package/src/blocks/scratch3_looks.js +612 -0
- package/src/blocks/scratch3_motion.js +288 -0
- package/src/blocks/scratch3_operators.js +154 -0
- package/src/blocks/scratch3_procedures.js +79 -0
- package/src/blocks/scratch3_sensing.js +336 -0
- package/src/blocks/scratch3_sound.js +350 -0
- package/src/dispatch/central-dispatch.js +143 -0
- package/src/dispatch/shared-dispatch.js +235 -0
- package/src/dispatch/worker-dispatch.js +110 -0
- package/src/engine/adapter.js +176 -0
- package/src/engine/block-utility.js +242 -0
- package/src/engine/blocks-execute-cache.js +19 -0
- package/src/engine/blocks-runtime-cache.js +78 -0
- package/src/engine/blocks.js +1299 -0
- package/src/engine/comment.js +56 -0
- package/src/engine/execute.js +580 -0
- package/src/engine/monitor-record.js +23 -0
- package/src/engine/mutation-adapter.js +48 -0
- package/src/engine/profiler.js +390 -0
- package/src/engine/runtime.js +2686 -0
- package/src/engine/scratch-blocks-constants.js +27 -0
- package/src/engine/sequencer.js +361 -0
- package/src/engine/stage-layering.js +29 -0
- package/src/engine/target.js +799 -0
- package/src/engine/thread.js +404 -0
- package/src/engine/variable.js +70 -0
- package/src/extension-support/argument-type.js +47 -0
- package/src/extension-support/block-type.js +50 -0
- package/src/extension-support/define-messages.js +18 -0
- package/src/extension-support/extension-manager.js +440 -0
- package/src/extension-support/extension-metadata.js +64 -0
- package/src/extension-support/extension-worker.js +59 -0
- package/src/extension-support/reporter-scope.js +18 -0
- package/src/extension-support/target-type.js +17 -0
- package/src/extensions/scratch3_boost/index.js +2113 -0
- package/src/extensions/scratch3_ev3/index.js +1355 -0
- package/src/extensions/scratch3_gdx_for/index.js +981 -0
- package/src/extensions/scratch3_gdx_for/scratch-link-device-adapter.js +44 -0
- package/src/extensions/scratch3_makeymakey/index.js +396 -0
- package/src/extensions/scratch3_microbit/index.js +984 -0
- package/src/extensions/scratch3_music/assets/drums/1-snare.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/10-wood-block.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/11-cowbell.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/12-triangle.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/13-bongo.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/14-conga.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/15-cabasa.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/16-guiro.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/17-vibraslap.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/18-cuica.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/2-bass-drum.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/3-side-stick.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/4-crash-cymbal.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/5-open-hi-hat.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/6-closed-hi-hat.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/7-tambourine.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/8-hand-clap.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/drums/9-claves.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/108.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/24.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/84.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/1-piano/96.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/10-clarinet/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/10-clarinet/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/11-saxophone/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/11-saxophone/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/11-saxophone/84.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/12-flute/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/12-flute/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/13-wooden-flute/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/14-bassoon/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/14-bassoon/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/14-bassoon/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/15-choir/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/15-choir/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/15-choir/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/16-vibraphone/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/16-vibraphone/72.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/17-music-box/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/18-steel-drum/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/19-marimba/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/2-electric-piano/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/20-synth-lead/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/21-synth-pad/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/3-organ/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/4-guitar/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/5-electric-guitar/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/6-bass/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/6-bass/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/7-pizzicato/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/8-cello/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/8-cello/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/8-cello/60.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/9-trombone/36.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/9-trombone/48.mp3 +0 -0
- package/src/extensions/scratch3_music/assets/instruments/9-trombone/60.mp3 +0 -0
- package/src/extensions/scratch3_music/index.js +1333 -0
- package/src/extensions/scratch3_music/manifest.js +63 -0
- package/src/extensions/scratch3_pen/index.js +770 -0
- package/src/extensions/scratch3_speech2text/index.js +700 -0
- package/src/extensions/scratch3_text2speech/index.js +766 -0
- package/src/extensions/scratch3_translate/index.js +286 -0
- package/src/extensions/scratch3_video_sensing/debug.js +13 -0
- package/src/extensions/scratch3_video_sensing/index.js +594 -0
- package/src/extensions/scratch3_video_sensing/library.js +384 -0
- package/src/extensions/scratch3_video_sensing/math.js +76 -0
- package/src/extensions/scratch3_video_sensing/view.js +509 -0
- package/src/extensions/scratch3_wedo2/index.js +1616 -0
- package/src/import/load-costume.js +416 -0
- package/src/import/load-sound.js +116 -0
- package/src/index.js +10 -0
- package/src/io/ble.js +256 -0
- package/src/io/bt.js +202 -0
- package/src/io/clock.js +39 -0
- package/src/io/cloud.js +169 -0
- package/src/io/keyboard.js +146 -0
- package/src/io/mouse.js +145 -0
- package/src/io/mouseWheel.js +28 -0
- package/src/io/userData.js +24 -0
- package/src/io/video.js +210 -0
- package/src/playground/benchmark.css +83 -0
- package/src/playground/benchmark.js +753 -0
- package/src/playground/index.html +111 -0
- package/src/playground/suite.css +78 -0
- package/src/playground/suite.html +25 -0
- package/src/playground/suite.js +544 -0
- package/src/playground/video-sensing.html +18 -0
- package/src/playground/video-sensing.js +133 -0
- package/src/serialization/deserialize-assets.js +178 -0
- package/src/serialization/sb2.js +1295 -0
- package/src/serialization/sb2_specmap.js +1818 -0
- package/src/serialization/sb3.js +1320 -0
- package/src/serialization/serialize-assets.js +60 -0
- package/src/sprites/rendered-target.js +1115 -0
- package/src/sprites/sprite.js +177 -0
- package/src/util/base64-util.js +48 -0
- package/src/util/cast.js +218 -0
- package/src/util/clone.js +17 -0
- package/src/util/color.js +204 -0
- package/src/util/fetch-with-timeout.js +53 -0
- package/src/util/get-monitor-id.js +33 -0
- package/src/util/jsonrpc.js +114 -0
- package/src/util/log.js +4 -0
- package/src/util/math-util.js +122 -0
- package/src/util/maybe-format-message.js +18 -0
- package/src/util/new-block-ids.js +33 -0
- package/src/util/rateLimiter.js +73 -0
- package/src/util/scratch-link-websocket.js +133 -0
- package/src/util/string-util.js +94 -0
- package/src/util/task-queue.js +203 -0
- package/src/util/timer.js +103 -0
- package/src/util/uid.js +29 -0
- package/src/util/variable-util.js +48 -0
- package/src/util/xml-escape.js +33 -0
- package/src/virtual-machine.js +1586 -0
- package/webpack.config.js +134 -0
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
const Runtime = require('../../engine/runtime');
|
|
2
|
+
|
|
3
|
+
const ArgumentType = require('../../extension-support/argument-type');
|
|
4
|
+
const BlockType = require('../../extension-support/block-type');
|
|
5
|
+
const Clone = require('../../util/clone');
|
|
6
|
+
const Cast = require('../../util/cast');
|
|
7
|
+
const formatMessage = require('format-message');
|
|
8
|
+
const Video = require('../../io/video');
|
|
9
|
+
|
|
10
|
+
const VideoMotion = require('./library');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Icon svg to be displayed in the blocks category menu, encoded as a data URI.
|
|
14
|
+
* @type {string}
|
|
15
|
+
*/
|
|
16
|
+
// eslint-disable-next-line max-len
|
|
17
|
+
const menuIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjBweCIgaGVpZ2h0PSIyMHB4IiB2aWV3Qm94PSIwIDAgMjAgMjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctTWVudTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJFeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctTWVudSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9InZpZGVvLW1vdGlvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDUuMDAwMDAwKSIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjMEVCRDhDIiBvcGFjaXR5PSIwLjI1IiBjeD0iMTYiIGN5PSI4IiByPSIyIj48L2NpcmNsZT4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjMEVCRDhDIiBvcGFjaXR5PSIwLjUiIGN4PSIxNiIgY3k9IjYiIHI9IjIiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiMwRUJEOEMiIG9wYWNpdHk9IjAuNzUiIGN4PSIxNiIgY3k9IjQiIHI9IjIiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsIiBmaWxsPSIjMEVCRDhDIiBjeD0iMTYiIGN5PSIyIiByPSIyIj48L2NpcmNsZT4KICAgICAgICAgICAgPHBhdGggZD0iTTExLjMzNTk3MzksMi4yMDk3ODgyNSBMOC4yNSw0LjIwOTk1NjQ5IEw4LjI1LDMuMDUgQzguMjUsMi4wNDQ4ODIyNyA3LjQ2ODU5MDMxLDEuMjUgNi41LDEuMjUgTDIuMDUsMS4yNSBDMS4wMzgwNzExOSwxLjI1IDAuMjUsMi4wMzgwNzExOSAwLjI1LDMuMDUgTDAuMjUsNyBDMC4yNSw3Ljk2MzY5OTM3IDEuMDQyMjQ5MTksOC43NTU5NDg1NiAyLjA1LDguOCBMNi41LDguOCBDNy40NTA4MzAwOSw4LjggOC4yNSw3Ljk3MzI3MjUgOC4yNSw3IEw4LjI1LDUuODU4NDUyNDEgTDguNjI4NjIzOTQsNi4wODU2MjY3NyBMMTEuNDI2Nzc2Nyw3Ljc3MzIyMzMgQzExLjQzNjg5NDMsNy43ODMzNDA5MSAxMS40NzU3NjU1LDcuOCAxMS41LDcuOCBDMTEuNjMzNDkzMiw3LjggMTEuNzUsNy42OTEyNjAzNCAxMS43NSw3LjU1IEwxMS43NSwyLjQgQzExLjc1LDIuNDE4MzgyNjkgMTEuNzIxOTAyOSwyLjM1MjgyMjgyIDExLjY4NTYyNjgsMi4yNzg2MjM5NCBDMTEuNjEyOTUyOCwyLjE1NzUwMDY5IDExLjQ3MDc5NjgsMi4xMjkwNjk1IDExLjMzNTk3MzksMi4yMDk3ODgyNSBaIiBpZD0idmlkZW9fMzdfIiBzdHJva2Utb3BhY2l0eT0iMC4xNSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjAuNSIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Icon svg to be displayed at the left edge of each extension block, encoded as a data URI.
|
|
21
|
+
* @type {string}
|
|
22
|
+
*/
|
|
23
|
+
// eslint-disable-next-line max-len
|
|
24
|
+
const blockIconURI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNDBweCIgaGVpZ2h0PSI0MHB4IiB2aWV3Qm94PSIwIDAgNDAgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjIgKDY3MTQ1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5FeHRlbnNpb25zL1NvZnR3YXJlL1ZpZGVvLVNlbnNpbmctQmxvY2s8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iRXh0ZW5zaW9ucy9Tb2Z0d2FyZS9WaWRlby1TZW5zaW5nLUJsb2NrIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2Utb3BhY2l0eT0iMC4xNSI+CiAgICAgICAgPGcgaWQ9InZpZGVvLW1vdGlvbiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwLjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjMDAwMDAwIj4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjRkZGRkZGIiBvcGFjaXR5PSIwLjI1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGN4PSIzMiIgY3k9IjE2IiByPSI0LjUiPjwvY2lyY2xlPgogICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiNGRkZGRkYiIG9wYWNpdHk9IjAuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjeD0iMzIiIGN5PSIxMiIgcj0iNC41Ij48L2NpcmNsZT4KICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC1Db3B5IiBmaWxsPSIjRkZGRkZGIiBvcGFjaXR5PSIwLjc1IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGN4PSIzMiIgY3k9IjgiIHI9IjQuNSI+PC9jaXJjbGU+CiAgICAgICAgICAgIDxjaXJjbGUgaWQ9Ik92YWwiIGZpbGw9IiNGRkZGRkYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY3g9IjMyIiBjeT0iNCIgcj0iNC41Ij48L2NpcmNsZT4KICAgICAgICAgICAgPHBhdGggZD0iTTIyLjY3MTk0NzcsNC40MTk1NzY0OSBMMTYuNSw4LjQxOTkxMjk4IEwxNi41LDYuMSBDMTYuNSw0LjA4OTc2NDU0IDE0LjkzNzE4MDYsMi41IDEzLDIuNSBMNC4xLDIuNSBDMi4wNzYxNDIzNywyLjUgMC41LDQuMDc2MTQyMzcgMC41LDYuMSBMMC41LDE0IEMwLjUsMTUuOTI3Mzk4NyAyLjA4NDQ5ODM5LDE3LjUxMTg5NzEgNC4xLDE3LjYgTDEzLDE3LjYgQzE0LjkwMTY2MDIsMTcuNiAxNi41LDE1Ljk0NjU0NSAxNi41LDE0IEwxNi41LDExLjcxNjkwNDggTDIyLjc1NzI0NzksMTUuNDcxMjUzNSBMMjIuODUzNTUzNCwxNS41NDY0NDY2IEMyMi44NzM3ODg2LDE1LjU2NjY4MTggMjIuOTUxNTMxLDE1LjYgMjMsMTUuNiBDMjMuMjY2OTg2NSwxNS42IDIzLjUsMTUuMzgyNTIwNyAyMy41LDE1LjEgTDIzLjUsNC44IEMyMy41LDQuODM2NzY1MzggMjMuNDQzODA1OCw0LjcwNTY0NTYzIDIzLjM3MTI1MzUsNC41NTcyNDc4OCBDMjMuMjI1OTA1Niw0LjMxNTAwMTM5IDIyLjk0MTU5MzcsNC4yNTgxMzg5OSAyMi42NzE5NDc3LDQuNDE5NTc2NDkgWiIgaWQ9InZpZGVvXzM3XyIgZmlsbD0iIzRENEQ0RCI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Sensor attribute video sensor block should report.
|
|
28
|
+
* @readonly
|
|
29
|
+
* @enum {string}
|
|
30
|
+
*/
|
|
31
|
+
const SensingAttribute = {
|
|
32
|
+
/** The amount of motion. */
|
|
33
|
+
MOTION: 'motion',
|
|
34
|
+
|
|
35
|
+
/** The direction of the motion. */
|
|
36
|
+
DIRECTION: 'direction'
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Subject video sensor block should report for.
|
|
41
|
+
* @readonly
|
|
42
|
+
* @enum {string}
|
|
43
|
+
*/
|
|
44
|
+
const SensingSubject = {
|
|
45
|
+
/** The sensor traits of the whole stage. */
|
|
46
|
+
STAGE: 'Stage',
|
|
47
|
+
|
|
48
|
+
/** The senosr traits of the area overlapped by this sprite. */
|
|
49
|
+
SPRITE: 'this sprite'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* States the video sensing activity can be set to.
|
|
54
|
+
* @readonly
|
|
55
|
+
* @enum {string}
|
|
56
|
+
*/
|
|
57
|
+
const VideoState = {
|
|
58
|
+
/** Video turned off. */
|
|
59
|
+
OFF: 'off',
|
|
60
|
+
|
|
61
|
+
/** Video turned on with default y axis mirroring. */
|
|
62
|
+
ON: 'on',
|
|
63
|
+
|
|
64
|
+
/** Video turned on without default y axis mirroring. */
|
|
65
|
+
ON_FLIPPED: 'on-flipped'
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Class for the motion-related blocks in Scratch 3.0
|
|
70
|
+
* @param {Runtime} runtime - the runtime instantiating this block package.
|
|
71
|
+
* @constructor
|
|
72
|
+
*/
|
|
73
|
+
class Scratch3VideoSensingBlocks {
|
|
74
|
+
constructor (runtime) {
|
|
75
|
+
/**
|
|
76
|
+
* The runtime instantiating this block package.
|
|
77
|
+
* @type {Runtime}
|
|
78
|
+
*/
|
|
79
|
+
this.runtime = runtime;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The motion detection algoritm used to power the motion amount and
|
|
83
|
+
* direction values.
|
|
84
|
+
* @type {VideoMotion}
|
|
85
|
+
*/
|
|
86
|
+
this.detect = new VideoMotion();
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The last millisecond epoch timestamp that the video stream was
|
|
90
|
+
* analyzed.
|
|
91
|
+
* @type {number}
|
|
92
|
+
*/
|
|
93
|
+
this._lastUpdate = null;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A flag to determine if this extension has been installed in a project.
|
|
97
|
+
* It is set to false the first time getInfo is run.
|
|
98
|
+
* @type {boolean}
|
|
99
|
+
*/
|
|
100
|
+
this.firstInstall = true;
|
|
101
|
+
|
|
102
|
+
if (this.runtime.ioDevices) {
|
|
103
|
+
// Configure the video device with values from globally stored locations.
|
|
104
|
+
this.runtime.on(Runtime.PROJECT_LOADED, this.updateVideoDisplay.bind(this));
|
|
105
|
+
|
|
106
|
+
// Clear target motion state values when the project starts.
|
|
107
|
+
this.runtime.on(Runtime.PROJECT_RUN_START, this.reset.bind(this));
|
|
108
|
+
|
|
109
|
+
// Kick off looping the analysis logic.
|
|
110
|
+
this._loop();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* After analyzing a frame the amount of milliseconds until another frame
|
|
116
|
+
* is analyzed.
|
|
117
|
+
* @type {number}
|
|
118
|
+
*/
|
|
119
|
+
static get INTERVAL () {
|
|
120
|
+
return 33;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Dimensions the video stream is analyzed at after its rendered to the
|
|
125
|
+
* sample canvas.
|
|
126
|
+
* @type {Array.<number>}
|
|
127
|
+
*/
|
|
128
|
+
static get DIMENSIONS () {
|
|
129
|
+
return [480, 360];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The key to load & store a target's motion-related state.
|
|
134
|
+
* @type {string}
|
|
135
|
+
*/
|
|
136
|
+
static get STATE_KEY () {
|
|
137
|
+
return 'Scratch.videoSensing';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The default motion-related state, to be used when a target has no existing motion state.
|
|
142
|
+
* @type {MotionState}
|
|
143
|
+
*/
|
|
144
|
+
static get DEFAULT_MOTION_STATE () {
|
|
145
|
+
return {
|
|
146
|
+
motionFrameNumber: 0,
|
|
147
|
+
motionAmount: 0,
|
|
148
|
+
motionDirection: 0
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The transparency setting of the video preview stored in a value
|
|
154
|
+
* accessible by any object connected to the virtual machine.
|
|
155
|
+
* @type {number}
|
|
156
|
+
*/
|
|
157
|
+
get globalVideoTransparency () {
|
|
158
|
+
const stage = this.runtime.getTargetForStage();
|
|
159
|
+
if (stage) {
|
|
160
|
+
return stage.videoTransparency;
|
|
161
|
+
}
|
|
162
|
+
return 50;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
set globalVideoTransparency (transparency) {
|
|
166
|
+
const stage = this.runtime.getTargetForStage();
|
|
167
|
+
if (stage) {
|
|
168
|
+
stage.videoTransparency = transparency;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* The video state of the video preview stored in a value accessible by any
|
|
174
|
+
* object connected to the virtual machine.
|
|
175
|
+
* @type {number}
|
|
176
|
+
*/
|
|
177
|
+
get globalVideoState () {
|
|
178
|
+
const stage = this.runtime.getTargetForStage();
|
|
179
|
+
if (stage) {
|
|
180
|
+
return stage.videoState;
|
|
181
|
+
}
|
|
182
|
+
// Though the default value for the stage is normally 'on', we need to default
|
|
183
|
+
// to 'off' here to prevent the video device from briefly activating
|
|
184
|
+
// while waiting for stage targets to be installed that say it should be off
|
|
185
|
+
return VideoState.OFF;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
set globalVideoState (state) {
|
|
189
|
+
const stage = this.runtime.getTargetForStage();
|
|
190
|
+
if (stage) {
|
|
191
|
+
stage.videoState = state;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get the latest values for video transparency and state,
|
|
197
|
+
* and set the video device to use them.
|
|
198
|
+
*/
|
|
199
|
+
updateVideoDisplay () {
|
|
200
|
+
this.setVideoTransparency({
|
|
201
|
+
TRANSPARENCY: this.globalVideoTransparency
|
|
202
|
+
});
|
|
203
|
+
this.videoToggle({
|
|
204
|
+
VIDEO_STATE: this.globalVideoState
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Reset the extension's data motion detection data. This will clear out
|
|
210
|
+
* for example old frames, so the first analyzed frame will not be compared
|
|
211
|
+
* against a frame from before reset was called.
|
|
212
|
+
*/
|
|
213
|
+
reset () {
|
|
214
|
+
this.detect.reset();
|
|
215
|
+
|
|
216
|
+
const targets = this.runtime.targets;
|
|
217
|
+
for (let i = 0; i < targets.length; i++) {
|
|
218
|
+
const state = targets[i].getCustomState(Scratch3VideoSensingBlocks.STATE_KEY);
|
|
219
|
+
if (state) {
|
|
220
|
+
state.motionAmount = 0;
|
|
221
|
+
state.motionDirection = 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Occasionally step a loop to sample the video, stamp it to the preview
|
|
228
|
+
* skin, and add a TypedArray copy of the canvas's pixel data.
|
|
229
|
+
* @private
|
|
230
|
+
*/
|
|
231
|
+
_loop () {
|
|
232
|
+
const loopTime = Math.max(this.runtime.currentStepTime, Scratch3VideoSensingBlocks.INTERVAL);
|
|
233
|
+
this._loopInterval = setTimeout(this._loop.bind(this), loopTime);
|
|
234
|
+
|
|
235
|
+
// Add frame to detector
|
|
236
|
+
const time = Date.now();
|
|
237
|
+
if (this._lastUpdate === null) {
|
|
238
|
+
this._lastUpdate = time;
|
|
239
|
+
}
|
|
240
|
+
const offset = time - this._lastUpdate;
|
|
241
|
+
if (offset > Scratch3VideoSensingBlocks.INTERVAL) {
|
|
242
|
+
const frame = this.runtime.ioDevices.video.getFrame({
|
|
243
|
+
format: Video.FORMAT_IMAGE_DATA,
|
|
244
|
+
dimensions: Scratch3VideoSensingBlocks.DIMENSIONS
|
|
245
|
+
});
|
|
246
|
+
if (frame) {
|
|
247
|
+
this._lastUpdate = time;
|
|
248
|
+
this.detect.addFrame(frame.data);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Stop the video sampling loop. Only used for testing.
|
|
255
|
+
*/
|
|
256
|
+
_stopLoop () {
|
|
257
|
+
clearTimeout(this._loopInterval);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Create data for a menu in scratch-blocks format, consisting of an array
|
|
262
|
+
* of objects with text and value properties. The text is a translated
|
|
263
|
+
* string, and the value is one-indexed.
|
|
264
|
+
* @param {object[]} info - An array of info objects each having a name
|
|
265
|
+
* property.
|
|
266
|
+
* @return {array} - An array of objects with text and value properties.
|
|
267
|
+
* @private
|
|
268
|
+
*/
|
|
269
|
+
_buildMenu (info) {
|
|
270
|
+
return info.map((entry, index) => {
|
|
271
|
+
const obj = {};
|
|
272
|
+
obj.text = entry.name;
|
|
273
|
+
obj.value = entry.value || String(index + 1);
|
|
274
|
+
return obj;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @param {Target} target - collect motion state for this target.
|
|
280
|
+
* @returns {MotionState} the mutable motion state associated with that
|
|
281
|
+
* target. This will be created if necessary.
|
|
282
|
+
* @private
|
|
283
|
+
*/
|
|
284
|
+
_getMotionState (target) {
|
|
285
|
+
let motionState = target.getCustomState(Scratch3VideoSensingBlocks.STATE_KEY);
|
|
286
|
+
if (!motionState) {
|
|
287
|
+
motionState = Clone.simple(Scratch3VideoSensingBlocks.DEFAULT_MOTION_STATE);
|
|
288
|
+
target.setCustomState(Scratch3VideoSensingBlocks.STATE_KEY, motionState);
|
|
289
|
+
}
|
|
290
|
+
return motionState;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
static get SensingAttribute () {
|
|
294
|
+
return SensingAttribute;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* An array of choices of whether a reporter should return the frame's
|
|
299
|
+
* motion amount or direction.
|
|
300
|
+
* @type {object[]}
|
|
301
|
+
* @param {string} name - the translatable name to display in sensor
|
|
302
|
+
* attribute menu
|
|
303
|
+
* @param {string} value - the serializable value of the attribute
|
|
304
|
+
*/
|
|
305
|
+
get ATTRIBUTE_INFO () {
|
|
306
|
+
return [
|
|
307
|
+
{
|
|
308
|
+
name: formatMessage({
|
|
309
|
+
id: 'videoSensing.motion',
|
|
310
|
+
default: 'motion',
|
|
311
|
+
description: 'Attribute for the "video [ATTRIBUTE] on [SUBJECT]" block'
|
|
312
|
+
}),
|
|
313
|
+
value: SensingAttribute.MOTION
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: formatMessage({
|
|
317
|
+
id: 'videoSensing.direction',
|
|
318
|
+
default: 'direction',
|
|
319
|
+
description: 'Attribute for the "video [ATTRIBUTE] on [SUBJECT]" block'
|
|
320
|
+
}),
|
|
321
|
+
value: SensingAttribute.DIRECTION
|
|
322
|
+
}
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static get SensingSubject () {
|
|
327
|
+
return SensingSubject;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* An array of info about the subject choices.
|
|
332
|
+
* @type {object[]}
|
|
333
|
+
* @param {string} name - the translatable name to display in the subject menu
|
|
334
|
+
* @param {string} value - the serializable value of the subject
|
|
335
|
+
*/
|
|
336
|
+
get SUBJECT_INFO () {
|
|
337
|
+
return [
|
|
338
|
+
{
|
|
339
|
+
name: formatMessage({
|
|
340
|
+
id: 'videoSensing.sprite',
|
|
341
|
+
default: 'sprite',
|
|
342
|
+
description: 'Subject for the "video [ATTRIBUTE] on [SUBJECT]" block'
|
|
343
|
+
}),
|
|
344
|
+
value: SensingSubject.SPRITE
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: formatMessage({
|
|
348
|
+
id: 'videoSensing.stage',
|
|
349
|
+
default: 'stage',
|
|
350
|
+
description: 'Subject for the "video [ATTRIBUTE] on [SUBJECT]" block'
|
|
351
|
+
}),
|
|
352
|
+
value: SensingSubject.STAGE
|
|
353
|
+
}
|
|
354
|
+
];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* States the video sensing activity can be set to.
|
|
359
|
+
* @readonly
|
|
360
|
+
* @enum {string}
|
|
361
|
+
*/
|
|
362
|
+
static get VideoState () {
|
|
363
|
+
return VideoState;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* An array of info on video state options for the "turn video [STATE]" block.
|
|
368
|
+
* @type {object[]}
|
|
369
|
+
* @param {string} name - the translatable name to display in the video state menu
|
|
370
|
+
* @param {string} value - the serializable value stored in the block
|
|
371
|
+
*/
|
|
372
|
+
get VIDEO_STATE_INFO () {
|
|
373
|
+
return [
|
|
374
|
+
{
|
|
375
|
+
name: formatMessage({
|
|
376
|
+
id: 'videoSensing.off',
|
|
377
|
+
default: 'off',
|
|
378
|
+
description: 'Option for the "turn video [STATE]" block'
|
|
379
|
+
}),
|
|
380
|
+
value: VideoState.OFF
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
name: formatMessage({
|
|
384
|
+
id: 'videoSensing.on',
|
|
385
|
+
default: 'on',
|
|
386
|
+
description: 'Option for the "turn video [STATE]" block'
|
|
387
|
+
}),
|
|
388
|
+
value: VideoState.ON
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: formatMessage({
|
|
392
|
+
id: 'videoSensing.onFlipped',
|
|
393
|
+
default: 'on flipped',
|
|
394
|
+
description: 'Option for the "turn video [STATE]" block that causes the video to be flipped' +
|
|
395
|
+
' horizontally (reversed as in a mirror)'
|
|
396
|
+
}),
|
|
397
|
+
value: VideoState.ON_FLIPPED
|
|
398
|
+
}
|
|
399
|
+
];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* @returns {object} metadata for this extension and its blocks.
|
|
404
|
+
*/
|
|
405
|
+
getInfo () {
|
|
406
|
+
// Set the video display properties to defaults the first time
|
|
407
|
+
// getInfo is run. This turns on the video device when it is
|
|
408
|
+
// first added to a project, and is overwritten by a PROJECT_LOADED
|
|
409
|
+
// event listener that later calls updateVideoDisplay
|
|
410
|
+
if (this.firstInstall) {
|
|
411
|
+
this.globalVideoState = VideoState.ON;
|
|
412
|
+
this.globalVideoTransparency = 50;
|
|
413
|
+
this.updateVideoDisplay();
|
|
414
|
+
this.firstInstall = false;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Return extension definition
|
|
418
|
+
return {
|
|
419
|
+
id: 'videoSensing',
|
|
420
|
+
name: formatMessage({
|
|
421
|
+
id: 'videoSensing.categoryName',
|
|
422
|
+
default: 'Video Sensing',
|
|
423
|
+
description: 'Label for the video sensing extension category'
|
|
424
|
+
}),
|
|
425
|
+
blockIconURI: blockIconURI,
|
|
426
|
+
menuIconURI: menuIconURI,
|
|
427
|
+
blocks: [
|
|
428
|
+
{
|
|
429
|
+
// @todo this hat needs to be set itself to restart existing
|
|
430
|
+
// threads like Scratch 2's behaviour.
|
|
431
|
+
opcode: 'whenMotionGreaterThan',
|
|
432
|
+
text: formatMessage({
|
|
433
|
+
id: 'videoSensing.whenMotionGreaterThan',
|
|
434
|
+
default: 'when video motion > [REFERENCE]',
|
|
435
|
+
description: 'Event that triggers when the amount of motion is greater than [REFERENCE]'
|
|
436
|
+
}),
|
|
437
|
+
blockType: BlockType.HAT,
|
|
438
|
+
arguments: {
|
|
439
|
+
REFERENCE: {
|
|
440
|
+
type: ArgumentType.NUMBER,
|
|
441
|
+
defaultValue: 10
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
opcode: 'videoOn',
|
|
447
|
+
blockType: BlockType.REPORTER,
|
|
448
|
+
text: formatMessage({
|
|
449
|
+
id: 'videoSensing.videoOn',
|
|
450
|
+
default: 'video [ATTRIBUTE] on [SUBJECT]',
|
|
451
|
+
description: 'Reporter that returns the amount of [ATTRIBUTE] for the selected [SUBJECT]'
|
|
452
|
+
}),
|
|
453
|
+
arguments: {
|
|
454
|
+
ATTRIBUTE: {
|
|
455
|
+
type: ArgumentType.NUMBER,
|
|
456
|
+
menu: 'ATTRIBUTE',
|
|
457
|
+
defaultValue: SensingAttribute.MOTION
|
|
458
|
+
},
|
|
459
|
+
SUBJECT: {
|
|
460
|
+
type: ArgumentType.NUMBER,
|
|
461
|
+
menu: 'SUBJECT',
|
|
462
|
+
defaultValue: SensingSubject.SPRITE
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
opcode: 'videoToggle',
|
|
468
|
+
text: formatMessage({
|
|
469
|
+
id: 'videoSensing.videoToggle',
|
|
470
|
+
default: 'turn video [VIDEO_STATE]',
|
|
471
|
+
description: 'Controls display of the video preview layer'
|
|
472
|
+
}),
|
|
473
|
+
arguments: {
|
|
474
|
+
VIDEO_STATE: {
|
|
475
|
+
type: ArgumentType.NUMBER,
|
|
476
|
+
menu: 'VIDEO_STATE',
|
|
477
|
+
defaultValue: VideoState.ON
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
opcode: 'setVideoTransparency',
|
|
483
|
+
text: formatMessage({
|
|
484
|
+
id: 'videoSensing.setVideoTransparency',
|
|
485
|
+
default: 'set video transparency to [TRANSPARENCY]',
|
|
486
|
+
description: 'Controls transparency of the video preview layer'
|
|
487
|
+
}),
|
|
488
|
+
arguments: {
|
|
489
|
+
TRANSPARENCY: {
|
|
490
|
+
type: ArgumentType.NUMBER,
|
|
491
|
+
defaultValue: 50
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
],
|
|
496
|
+
menus: {
|
|
497
|
+
ATTRIBUTE: {
|
|
498
|
+
acceptReporters: true,
|
|
499
|
+
items: this._buildMenu(this.ATTRIBUTE_INFO)
|
|
500
|
+
},
|
|
501
|
+
SUBJECT: {
|
|
502
|
+
acceptReporters: true,
|
|
503
|
+
items: this._buildMenu(this.SUBJECT_INFO)
|
|
504
|
+
},
|
|
505
|
+
VIDEO_STATE: {
|
|
506
|
+
acceptReporters: true,
|
|
507
|
+
items: this._buildMenu(this.VIDEO_STATE_INFO)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Analyze a part of the frame that a target overlaps.
|
|
515
|
+
* @param {Target} target - a target to determine where to analyze
|
|
516
|
+
* @returns {MotionState} the motion state for the given target
|
|
517
|
+
*/
|
|
518
|
+
_analyzeLocalMotion (target) {
|
|
519
|
+
const drawable = this.runtime.renderer._allDrawables[target.drawableID];
|
|
520
|
+
const state = this._getMotionState(target);
|
|
521
|
+
this.detect.getLocalMotion(drawable, state);
|
|
522
|
+
return state;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* A scratch reporter block handle that analyzes the last two frames and
|
|
527
|
+
* depending on the arguments, returns the motion or direction for the
|
|
528
|
+
* whole stage or just the target sprite.
|
|
529
|
+
* @param {object} args - the block arguments
|
|
530
|
+
* @param {BlockUtility} util - the block utility
|
|
531
|
+
* @returns {number} the motion amount or direction of the stage or sprite
|
|
532
|
+
*/
|
|
533
|
+
videoOn (args, util) {
|
|
534
|
+
this.detect.analyzeFrame();
|
|
535
|
+
|
|
536
|
+
let state = this.detect;
|
|
537
|
+
if (args.SUBJECT === SensingSubject.SPRITE) {
|
|
538
|
+
state = this._analyzeLocalMotion(util.target);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (args.ATTRIBUTE === SensingAttribute.MOTION) {
|
|
542
|
+
return state.motionAmount;
|
|
543
|
+
}
|
|
544
|
+
return state.motionDirection;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* A scratch hat block edge handle that analyzes the last two frames where
|
|
549
|
+
* the target sprite overlaps and if it has more motion than the given
|
|
550
|
+
* reference value.
|
|
551
|
+
* @param {object} args - the block arguments
|
|
552
|
+
* @param {BlockUtility} util - the block utility
|
|
553
|
+
* @returns {boolean} true if the sprite overlaps more motion than the
|
|
554
|
+
* reference
|
|
555
|
+
*/
|
|
556
|
+
whenMotionGreaterThan (args, util) {
|
|
557
|
+
this.detect.analyzeFrame();
|
|
558
|
+
const state = this._analyzeLocalMotion(util.target);
|
|
559
|
+
return state.motionAmount > Number(args.REFERENCE);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* A scratch command block handle that configures the video state from
|
|
564
|
+
* passed arguments.
|
|
565
|
+
* @param {object} args - the block arguments
|
|
566
|
+
* @param {VideoState} args.VIDEO_STATE - the video state to set the device to
|
|
567
|
+
*/
|
|
568
|
+
videoToggle (args) {
|
|
569
|
+
const state = args.VIDEO_STATE;
|
|
570
|
+
this.globalVideoState = state;
|
|
571
|
+
if (state === VideoState.OFF) {
|
|
572
|
+
this.runtime.ioDevices.video.disableVideo();
|
|
573
|
+
} else {
|
|
574
|
+
this.runtime.ioDevices.video.enableVideo();
|
|
575
|
+
// Mirror if state is ON. Do not mirror if state is ON_FLIPPED.
|
|
576
|
+
this.runtime.ioDevices.video.mirror = state === VideoState.ON;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* A scratch command block handle that configures the video preview's
|
|
582
|
+
* transparency from passed arguments.
|
|
583
|
+
* @param {object} args - the block arguments
|
|
584
|
+
* @param {number} args.TRANSPARENCY - the transparency to set the video
|
|
585
|
+
* preview to
|
|
586
|
+
*/
|
|
587
|
+
setVideoTransparency (args) {
|
|
588
|
+
const transparency = Cast.toNumber(args.TRANSPARENCY);
|
|
589
|
+
this.globalVideoTransparency = transparency;
|
|
590
|
+
this.runtime.ioDevices.video.setPreviewGhost(transparency);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
module.exports = Scratch3VideoSensingBlocks;
|