diff --git a/docs/static/skillmap/rockstar/decision-tree.png b/docs/static/skillmap/rockstar/decision-tree.png
new file mode 100644
index 00000000000..a5c8eebf4a7
Binary files /dev/null and b/docs/static/skillmap/rockstar/decision-tree.png differ
diff --git a/docs/static/skillmap/rockstar/rockscout-imgs-array.gif b/docs/static/skillmap/rockstar/rockscout-imgs-array.gif
new file mode 100644
index 00000000000..4f3d7557309
Binary files /dev/null and b/docs/static/skillmap/rockstar/rockscout-imgs-array.gif differ
diff --git a/docs/static/skillmap/rockstar/rockscout.png b/docs/static/skillmap/rockstar/rockscout.png
new file mode 100644
index 00000000000..da1a573b877
Binary files /dev/null and b/docs/static/skillmap/rockstar/rockscout.png differ
diff --git a/docs/test/tutorials/lyla-jr-2.md b/docs/test/tutorials/lyla-jr-2.md
new file mode 100644
index 00000000000..8c5fcee5f5a
--- /dev/null
+++ b/docs/test/tutorials/lyla-jr-2.md
@@ -0,0 +1,687 @@
+# Pickle Party
+### @explicitHints true
+### @flyoutOnly true
+
+
+## Pickle Party Intro @showdialog
+
+**Ready to code a pickle party?**
+
+![Pickle Party Game](/static/tutorials/lyla/lyla.gif "Characters chasing pickle slices." )
+
+
+
+## {Step 2}
+
+**Take a look at the game window**
+
+![Lyla on the screen](/static/tutorials/lyla/lyla.png "Lyla is alone on the screen." )
+
+You should see Lyla on the screen.
+
+
+
+## {Step 3}
+
+**Click the circles to add other players**
+
+![The circles allow you to control other players](/static/tutorials/lyla/circles.gif "Click the circles to control other players." )
+
+
+
+
+## {Step 4}
+
+**Press the A button to clear the message**
+
+![Press A or B to clear the splash screen](/static/tutorials/lyla/splash.gif "Read the message, then clear it so you can play." )
+
+
+
+
+
+## {Step 5}
+
+**The arrow keys move your player**
+
+![The arrow keys move whichever player you have selected](/static/tutorials/lyla/arrows.gif "The game window is the same color as the player circle." )
+
+
+
+
+
+## {Step 5}
+
+**Let's add pickles to chase!**
+
+![Add a flying pickle with a new block](/static/tutorials/lyla/pickle.gif "Choose the pickle from the gallery" )
+
+#### ~ tutorialhint
+
+```blocks
+//@highlight
+sprites.sendFlying(lyla_imgs.picklechip, 1)
+```
+
+
+
+
+## {Step 6}
+
+**Use the arrow keys to catch pickles!**
+
+![Choose a character and chase pickles](/static/tutorials/lyla/play.gif "You get points for pickles" )
+
+
+
+
+
+## {Step 7}
+
+**Make it fancy**
+
+Set the scene to look like the diner.
+
+![Use the set scene block](/static/tutorials/lyla/on-start.gif "Use the set scene block" )
+
+#### ~ tutorialhint
+
+```blocks
+sprites.sendFlying(lyla_imgs.picklechip, 1)
+//@highlight
+scene.setBG(lyla_imgs.diner)
+```
+
+
+
+## {Step 8}
+
+**Add a timer**
+
+How many points can you get in 30 seconds?
+
+![Grab the timer block](/static/tutorials/lyla/timer.gif "The timer will count down from 45 to 0." )
+
+#### ~ tutorialhint
+
+```blocks
+sprites.sendFlying(lyla_imgs.picklechip, 1)
+scene.setBG(lyla_imgs.diner)
+//@highlight
+game.gameCountdown(30)
+```
+
+
+
+
+## {Step 9}
+
+**Play your game!**
+
+![Can you catch all the pickles?](/static/tutorials/lyla/timesup.gif "Can you catch all the pickles?" )
+
+#### ~ tutorialhint
+
+
+
+
+
+
+## {Step 10}
+
+**Make it your own!**
+
+If you want, you can swap your team, edit your pickle chips, or even add sounds!
+
+![Add something special](/static/tutorials/lyla/game-over.gif "Add something special". )
+
+#### ~ tutorialhint
+
+```blocks
+sprites.sendFlying(lyla_imgs.picklechip, 1)
+scene.setBG(lyla_imgs.diner)
+game.gameCountdown(30)
+//@highlight
+sprites.assignPlayerImgs(lyla_imgs.lyla, lyla_imgs.louisa, lyla_imgs.liana, lyla_imgs.luke)
+music.play(music.createSong(assets.song`countdown`), music.PlaybackMode.InBackground)
+
+```
+
+
+
+
+## {Step 11}
+
+**Play until you win!**
+
+
+
+
+
+## {Finale}
+
+**🥒 Excellent 🥒**
+
+You finished your game!
+
+If you want to play with others, sign-in and select **Done** to start an online multiplayer session with up to three friends.
+
+
+
+```blockconfig.global
+scene.setBG(lyla_imgs.diner)
+game.gameCountdown(30)
+sprites.sendFlying(lyla_imgs.picklechip, 1)
+sprites.assignPlayerImgs(lyla_imgs.lyla, lyla_imgs.stu, lyla_imgs.everett, lyla_imgs.luke)
+music.play(music.createSong(assets.song`countdown`), music.PlaybackMode.InBackground)
+
+```
+
+
+
+
+```ghost
+scene.setBG(lyla_imgs.diner)
+game.gameCountdown(30)
+sprites.sendFlying(lyla_imgs.picklechip, 1)
+sprites.assignPlayerImgs(lyla_imgs.lyla, lyla_imgs.stu, lyla_imgs.everett, lyla_imgs.luke)
+music.play(music.melodyPlayable(music.baDing), music.PlaybackMode.UntilDone)
+music.play(music.createSong(assets.song`countdown`), music.PlaybackMode.InBackground)
+
+```
+
+
+
+```package
+multiplayer
+arcade-text=github:microsoft/arcade-text#v1.3.0
+lyla_imgs=github:kiki-lee/lyla_imgs#v0.0.6
+arcade-block-icons=github:kiki-lee/arcade-block-icons#v0.0.10
+```
+
+
+```customts
+
+
+//% color=#b79900 icon="\uf1ce"
+namespace pickle {
+
+ /* Code to set up Lyla game only */
+
+ // Make sure not to remove later player when earlier player selected
+ export let playersConnected = 0;
+ // Keep count to delete old splash when new splash arrives
+ export let pickles_to_get = 7;
+ export let characters = [lyla_imgs.lyla, lyla_imgs.everett, lyla_imgs.stu, lyla_imgs.luke];
+ // Create textsprite for score
+ export let scoreText = textsprite.create("");
+ export let theseThings = " items";
+
+ sprites.onOverlap(SpriteKind.Player, SpriteKind.Projectile, function (sprite, otherSprite) {
+ sprites.destroy(otherSprite, effects.disintegrate, 100)
+ pickle.changeScoreOverride(1)
+ })
+
+ info.onCountdownEnd(function () {
+ game.simpleGame()
+ })
+
+ pickle.setPlayersWith(characters, 0)
+
+ mp.onControllerEvent(ControllerEvent.Connected, function (thisPlayer) {
+ if (mp.getPlayerProperty(thisPlayer, mp.PlayerProperty.Number) <= characters.length) {
+ pickle.setPlayersWith(characters, mp.getPlayerProperty(thisPlayer, mp.PlayerProperty.Number))
+ }
+ })
+
+
+ /********/
+
+
+ //% blockId=set_players
+ // block="set game for $num player(s) with $list"
+ //% num.defl=1
+ //% list.shadow=variables_get
+ //% list.defl=characters
+ export function setPlayersWith(list: Image[], num: number) {
+
+ if (num == 0){
+ mp.setPlayerSprite(mp.getPlayerByIndex(0), sprites.create(list[0], SpriteKind.Player))
+ mp.getPlayerSprite(mp.getPlayerByIndex(0)).setStayInScreen(true)
+ mp.getPlayerSprite(mp.getPlayerByIndex(0)).setPosition(40, 20)
+ mp.getPlayerSprite(mp.getPlayerByIndex(0)).z = 1000
+ mp.moveWithButtons(mp.getPlayerByIndex(0))
+ }
+ else if (num > playersConnected) {
+ playersConnected = num;
+ pickles_to_get = 7 * num;
+ sprites.destroyAllSpritesOfKind(SpriteKind.Player)
+ let xloc = [
+ 40,
+ 120,
+ 40,
+ 120
+ ]
+ let yloc = [
+ 30,
+ 30,
+ 90,
+ 90
+ ]
+ for (let index = 0; index <= num - 1; index++) {
+ mp.setPlayerSprite(mp.getPlayerByIndex(index), sprites.create(list[index], SpriteKind.Player))
+ mp.getPlayerSprite(mp.getPlayerByIndex(index)).setStayInScreen(true)
+ mp.getPlayerSprite(mp.getPlayerByIndex(index)).setPosition(xloc.shift(), yloc.shift())
+ mp.getPlayerSprite(mp.getPlayerByIndex(index)).z = 1000
+ mp.moveWithButtons(mp.getPlayerByIndex(index))
+ }
+ game.splashMP("Grab " + pickles_to_get + theseThings + " to win!")
+ }
+ }
+
+ //% blockId=bump_sprite
+ // block="$thisSprite bump $thatSprite"
+ //% thisSprite.shadow=variables_get
+ //% thisSprite.defl=sprite
+ //% thatSprite.shadow=variables_get
+ //% thatSprite.defl=otherSprite
+ export function bumpSprite(thisSprite: Sprite, thatSprite: Sprite) {
+ thatSprite.setPosition((thisSprite.x + 80) % 160, thisSprite.y)
+ }
+
+
+ /**
+ * Overrides the normal score UI with an iconified version
+ */
+ //% blockId=set_score_override
+ //% block="set `ICON.pickle` to $thisScore"
+ //% thisScore.defl=0
+ //% color="#b70082"
+ //% group="Info"
+ //% help=github:docs/mp_set_score_override
+ export function setScoreOverride(thisScore: number) {
+ let thisIcon = img`
+ . . . . . . . . . . . . . . . .
+. . . . . 7 7 a 8. . . . . . .
+. . . . 7 7 a 8 7 7 a 8 7. . .
+. . . 7 7 a 8 7 7 a 8 7 7 7. .
+. . 7 7 a 8 7 7 a 8 7 7 7 a 8.
+. . 7 a 8 7 7 a 8 7 7 7 a 8 7.
+. 7 a 8 7 7 a 8 7 7 7 a 8 7. .
+.a 8 7 7 a 8 7 7 7 a 8 7 7 7.
+. . 7 7 a 8 7 7 a 8 8 7 7 7 7.
+. . 7 a 8 7 7 a 8 7 7 7 7 7 a.
+. . . 8 7 7 a 8 7 7 7 7 7 a 8.
+. . . 7 7 a 8 7 7 7 7 a a 8. .
+. . . .a 8 7 7 7 7 a 8 7. . .
+. . . . . . 7 7 7 a 8 7. . . .
+. . . . . . . . . . . . . . . .
+. . . . . . . . . . . . . . . .
+`
+ info.setScore(thisScore)
+ pickle.scoreText.setText(" x " + convertToText(info.score()))
+ scoreText.setIcon(thisIcon)
+ scoreText.setBorder(1, 3, 1)
+ scoreText.setMaxFontHeight(9)
+ scoreText.right = 160
+ scoreText.top = 1
+ scoreText.update()
+ info.showScore(false)
+ }
+
+ /**
+ * Changes the score and overrides the traditional UI
+ * with an iconified version
+ */
+ //% blockId=mp_change_score_override
+ //% block="change `ICON.pickle` by $thisScore"
+ //% thisScore.defl=1
+ //% color="#b70082"
+ //% help=github:docs/mp_change_score_override
+ //% group="Info"
+ export function changeScoreOverride(thisScore: number) {
+ info.changeScoreBy(thisScore)
+ pickle.setScoreOverride(info.score())
+ }
+}
+
+
+
+namespace loops {
+
+ /**
+ * Run code when the play button is pressed
+ * (Like on start, but jr)
+ */
+ //% color=#488898
+ //% help=game/on-start-simple
+ //% weight=99
+ //% afterOnStart=false
+ //% blockId=on_start_simple
+ //% block="on `ICON.play`"
+ //% blockAllowMultiple=0
+ export function onStartSimple(a: () => void): void {
+ a();
+ }
+}
+
+
+namespace music {
+ /**
+ * Simplified block to play a song
+ */
+ //% help=game/simple-song
+ //% blockId=playThis
+ //% block="play $thisSong"
+ //% thisSong.shadow=music_song_field_editor
+ export function simpleSong(thisSong: Playable) {
+ music.play(thisSong, music.PlaybackMode.UntilDone)
+ }
+}
+
+
+//% weight=200
+namespace game {
+
+ /**
+ * Start the game timer
+ */
+ //% blockId=game_countdown
+ //% block="`ICON.clock-white` $thisSec (s)"
+ //% thisSec.defl = 30
+ //% help=github:docs/game_coundown
+ export function gameCountdown(thisSec: number) {
+ info.startCountdown(thisSec)
+ }
+
+
+ /**
+ * Run code on an interval of time. This executes before game.onUpdate()
+ * @param body code to execute
+ */
+ //% help=game/on-update-interval weight=99 afterOnStart=true
+ //% blockId=gameinterval3
+ //% weight=100
+ //% block="every $period second(s)"
+ //% period.defl=1
+ //% blockAllowMultiple=1
+ export function onUpdateInterval3(period: number, a: () => void): void {
+ period = period * 1000;
+ if (!a || period < 0) return;
+ let timer = 0;
+ game.eventContext().registerFrameHandler(scene.UPDATE_INTERVAL_PRIORITY, () => {
+ const time = game.currentScene().millis();
+ if (timer <= time) {
+ timer = time + period;
+ a();
+ }
+ });
+ }
+
+ //% blockId=hold_text
+ //% weight=200
+ //% block="show $thisText"
+ //% thisText.defl="Press (A) to play"
+ export function holdText(thisText: string) {
+ game.showLongText(thisText, DialogLayout.Full)
+ }
+
+
+ /**
+ * Special lose sequence
+ */
+ //% blockId=set_lyla_lose
+ //% block="game over `ICON.frown-open-white`"
+ //% help=github:docs/set_simple_lose
+ export function simpleLoss() {
+ game.gameOver(false)
+ }
+
+
+ /**
+ * Special win sequence
+ */
+ //% blockId=set_lyla_win
+ //% block="game over `ICON.smile-beam-white`"
+ //% weight=300
+ //% help=github:docs/set_simple_win
+ export function simpleWin() {
+ if (pickle.playersConnected > 1) {
+ game.setGameOverMessage(true, "Great Teamwork!")
+ } else {
+ game.setGameOverMessage(true, "Great Work!")
+
+ }
+ game.gameOver(true)
+ }
+
+
+ /**
+ * Special win sequence
+ */
+ //% blockId=set_lyla_g_o
+ //% block="game over"
+ //% weight=300
+ //% help=github:docs/set_simple_g_o
+ export function simpleGame() {
+ if (info.score() >= 7 * pickle.playersConnected) {
+ game.simpleWin()
+ } else {
+ game.simpleLoss()
+ }
+ }
+
+
+ /**
+ * Show a title and an optional subtitle menu
+ * Can be dismissed by any player
+ * @param title
+ * @param subtitle
+ */
+ //% weight=90 help=game/splashMP
+ //% blockId=gameSplashMP block="splash %title||%subtitle"
+ //% title.shadow=text
+ //% subtitle.shadow=text
+ //% group="Prompt"
+ export function splashMP(title: any, subtitle?: any) {
+ title = console.inspect(title);
+ subtitle = subtitle ? console.inspect(subtitle) : subtitle;
+ controller._setUserEventsEnabled(false);
+ game.pushScene();
+ game.currentScene().flags |= scene.Flag.SeeThrough;
+
+ const dialog = new SplashDialog(screen.width, subtitle ? 42 : 35);
+ dialog.setText(title);
+ if (subtitle) dialog.setSubtext(subtitle);
+
+ const s = sprites.create(dialog.image, -1);
+ let pressed = true;
+ let done = false;
+ let connected = false;
+
+ mp.onControllerEvent(ControllerEvent.Connected, function (thisPlayer) {
+ connected = true;
+ })
+
+ game.onUpdate(() => {
+ dialog.update();
+ const currentState = ( connected ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.One), mp.MultiplayerButton.A)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.Two), mp.MultiplayerButton.A)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.Three), mp.MultiplayerButton.A)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.Four), mp.MultiplayerButton.A)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.One), mp.MultiplayerButton.B)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.Two), mp.MultiplayerButton.B)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.Three), mp.MultiplayerButton.B)) ||
+ (mp.isButtonPressed(mp.playerSelector(mp.PlayerNumber.Four), mp.MultiplayerButton.B))
+ )
+ if (currentState && !pressed) {
+ connected = false;
+ pressed = true;
+ scene.setBackgroundImage(null); // GC it
+ game.popScene();
+ done = true;
+ }
+ else if (pressed && !currentState) {
+ pressed = false;
+ connected = false;
+ }
+ })
+
+ pauseUntil(() => done);
+ controller._setUserEventsEnabled(true);
+ }
+
+}
+
+
+
+//% weight=100
+namespace sprites {
+ export enum Plyrs {
+ //% block="Player 1"
+ One = 0,
+ //% block="Player 2"
+ Two = 1,
+ //% block="Player 3"
+ Three = 2,
+ //% block="Player 4"
+ Four = 3
+ }
+
+
+ /**
+ * Creates a moving sprite with the image that you choose
+ */
+ //% blockId=send_flying
+ //% weight=1000
+ //% block="add $thing every $interval `ICON.clock-white`"
+ //% thing.shadow=screen_image_picker
+ //% thing.defl=lyla_imgs.picklechip
+ //% interval.defl=1
+ export function sendFlying(thing: Image, interval:number) {
+ if (thing.equals(lyla_imgs.picklechip)) {
+ pickle.theseThings = " pickles";
+ }
+ game.onUpdateInterval(interval*1000, function () {
+ let foodFight = sprites.createProjectileFromSide(thing, randint(-100, 100), randint(-100, 100))
+ })
+ }
+
+
+
+ /**
+ * Assign images to players by array
+ */
+ //% blockId=assign_player_images
+ //% block="team = $img1 $img2 $img3 $img4"
+ //% img1.shadow=screen_image_picker
+ //% img2.shadow=screen_image_picker
+ //% img3.shadow=screen_image_picker
+ //% img4.shadow=screen_image_picker
+ //% img1.defl=lyla_imgs.lyla
+ //% img2.defl=lyla_imgs.stu
+ //% img3.defl=lyla_imgs.everett
+ //% img4.defl=lyla_imgs.luke
+ //% inlineInputMode=inline
+ //% weight=1200
+ export function assignPlayerImgs(img1: Image, img2: Image, img3: Image, img4: Image) {
+ pickle.characters[0] = img1;
+ pickle.characters[1] = img2;
+ pickle.characters[2] = img3;
+ pickle.characters[3] = img4;
+ }
+
+}
+
+
+
+//% weight=250
+namespace info {
+ /**
+ * Runs code once each time a player's score reaches a given value.
+ * @param score The score to check for, eg: 100
+ * @param handler The code to run when the score is reached
+ */
+ //% blockId=onScore2
+ //% block="after $score `ICON.pickle`"
+ //% score.defl=20
+ //% blockGap=8
+ //% help=docs/on-score
+ //% group="Info"
+ export function onScore2(score: number, handler: () => void) {
+ info.onScore(score, handler);
+ }
+}
+
+
+//% weight=100
+namespace scene {
+ /**
+ * Sets the background with fewer words
+ */
+ //% blockId=set_bg
+ //% block="set scene $thisBG"
+ //% thisBG.shadow=lyla_bg_image_picker
+ //% help=docs/set_bg
+ //% group="Scene"
+ export function setBG(thisBG: Image) {
+ scene.setBackgroundImage(thisBG)
+ }
+}
+
+
+namespace images {
+ //% blockId=lyla_bg_image_picker block="%img"
+ //% shim=TD_ID
+ //% img.fieldEditor="sprite"
+ //% img.fieldOptions.taggedTemplate="img"
+ //% img.fieldOptions.decompileIndirectFixedInstances="true"
+ //% img.fieldOptions.decompileArgumentAsString="true"
+ //% img.fieldOptions.sizes="-1,-1"
+ //% img.fieldOptions.filter="lylabg"
+ //% weight=100 group="Create"
+ //% blockHidden=1 duplicateShadowOnDrag
+ export function _screenImageLylaBG(img: Image) {
+ return img
+ }
+}
+
+```
+
+```simtheme
+{
+ "palette": [
+ "#000000",
+ "#FFFFFF",
+ "#FF2121",
+ "#D26A9E",
+ "#F9C890",
+ "#FDFF70",
+ "#8E2EC4",
+ "#408325",
+ "#4166D8",
+ "#10CCE5",
+ "#95D6B1",
+ "#A4839F",
+ "#693C16",
+ "#E5CDC4",
+ "#A46C46",
+ "#000000"
+ ]
+}
+```
+
+
+```assetjson
+{
+ "assets.json": "",
+ "images.g.jres": "{\n \"EM~exxT809P9NBm_MJip\": {\n \"data\": \"003c000408010204001c00100500640000041e000004000000000000000000000000000a000004120000000400012408000c00012410001400012407001c00020a006400f401640000040000000000000000000000000000000003060018001c000124\",\n \"mimeType\": \"application/mkcd-song\",\n \"displayName\": \"countdown\",\n \"namespace\": \"mySongs.\"\n },\n \"*\": {\n \"mimeType\": \"image/x-mkcd-f4\",\n \"dataEncoding\": \"base64\",\n \"namespace\": \"myImages\"\n }\n}",
+ "images.g.ts": "// Auto-generated code. Do not edit.\nnamespace myImages {\n\n helpers._registerFactory(\"image\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n\n }\n return null;\n })\n\n helpers._registerFactory(\"animation\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n\n }\n return null;\n })\n\n helpers._registerFactory(\"song\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n case \"EM~exxT809P9NBm_MJip\":\n case \"countdown\":return hex`003c000408010204001c00100500640000041e000004000000000000000000000000000a000004120000000400012408000c00012410001400012407001c00020a006400f401640000040000000000000000000000000000000003060018001c000124`;\n }\n return null;\n })\n\n}\n// Auto-generated code. Do not edit.\n",
+ "main.blocks": "",
+ "main.ts": "\n",
+ "pxt.json": "{\n \"name\": \"TMNT_Music\",\n \"description\": \"\",\n \"dependencies\": {\n \"device\": \"*\"\n },\n \"files\": [\n \"main.blocks\",\n \"main.ts\",\n \"assets.json\",\n \"images.g.jres\",\n \"images.g.ts\",\n \"tilemap.g.jres\",\n \"tilemap.g.ts\"\n ],\n \"targetVersions\": {\n \"branch\": \"v1.12.30\",\n \"tag\": \"v1.12.30\",\n \"commits\": \"https://github.com/microsoft/pxt-arcade/commits/33228b1cc7e1bea3f728c26a6047bdef35fd2c09\",\n \"target\": \"1.12.30\",\n \"pxt\": \"8.5.41\"\n },\n \"preferredEditor\": \"tsprj\",\n \"palette\": [\n \"#000000\",\n \"#FFFFFF\",\n \"#FF2121\",\n \"#DFDDDE\",\n \"#FF8135\",\n \"#FFF609\",\n \"#8E2EC4\",\n \"#408325\",\n \"#003FAD\",\n \"#87F2FF\",\n \"#EBF8F9\",\n \"#A4839F\",\n \"#F9F6E1\",\n \"#E5CDC4\",\n \"#91463d\",\n \"#000000\"\n ]\n}\n",
+ "tilemap.g.jres": "{\n \"transparency16\": {\n \"data\": \"hwQQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true\n },\n \"*\": {\n \"mimeType\": \"image/x-mkcd-f4\",\n \"dataEncoding\": \"base64\",\n \"namespace\": \"myTiles\"\n }\n}",
+ "tilemap.g.ts": "// Auto-generated code. Do not edit.\nnamespace myTiles {\n //% fixedInstance jres blockIdentity=images._tile\n export const transparency16 = image.ofBuffer(hex``);\n\n helpers._registerFactory(\"tile\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n case \"transparency16\":return transparency16;\n }\n return null;\n })\n\n}\n// Auto-generated code. Do not edit.\n"
+}
+```
diff --git a/docs/test/tutorials/rockscout.md b/docs/test/tutorials/rockscout.md
new file mode 100644
index 00000000000..281bf1e6ad5
--- /dev/null
+++ b/docs/test/tutorials/rockscout.md
@@ -0,0 +1,519 @@
+# Florida Rockscout
+### @explicitHints true
+
+
+## {Welcome @showdialog}
+
+Congratulations! You've just accepted a job managing Terri, the last remaining **Florida Rockscout!**
+
+![Navigate the maze backstage](/static/skillmap/rockstar/rockscout.png "Look what we're about to do today!")
+
+We'll walk you through the skills you'll need to help Terri navigate backstage to collect equipment from the show while avoiding screaming fans!
+
+
+
+
+## {2. We need a HERO}
+
+**👏 We need a sprite!**
+
+---
+
+- :paper plane: From the ``||sprites:Sprites||`` category, drag
+``||variables(sprites):set [rockscout] to sprite [ ] of kind [Player]||``
+into **the empty**
+``||loops(noclick):on start||``
+container that's already in the workspace.
+
+
+~hint What does that mean? 🤷🏽
+
+---
+
+When giving instructions, we'll highlight some text to give you a better idea of
+what you are looking for.
+
+For example, when we suggest the
+``||variables(sprites):set [rockscout] to sprite [ ] of kind [Player]||``
+block, we are pointing you toward
+
+```block
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+```
+
+which is located in the ``||sprites:Sprites||`` category in the toolbox.
+
+hint~
+
+
+
+~hint What's a sprite? 💡
+
+---
+
+In Arcade, each character or image that does something is called a **SPRITE**.
+
+Sprites have properties that you can use and change — things like scale, position, and lifespan are all properties of sprites.
+
+Our rockscout will be a sprite, too.
+
+hint~
+
+
+
+
+#### ~ tutorialhint
+```blocks
+// @highlight
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+```
+
+
+
+
+## {3. Drawing an Avatar}
+
+**Designing an Avatar**
+
+---
+
+You might notice that you can design your own sprite image (aka avatar) if you click on the rockscout already in the workspace.
+
+While it might look like you're drawing with pixels, what you are really doing is
+creating an array of numbers that tells the computer what your avatar should look like.
+
+![Look at your array](/static/skillmap/rockstar/rockscout-imgs-array.gif "Your sprite image is an array of hexadecimal digits.")
+
+
+
+
+
+## {4. Control the Player}
+
+**Time to get the sprite moving**
+
+---
+
+- :game: From ``||controller: Controller||``, drag
+``||controller:move [rockscout] with buttons ⊕||``
+to **the end** of the ``||loops(noclick):on start||`` container.
+
+
+
+#### ~ tutorialhint
+```blocks
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+// @highlight
+controller.moveSprite(rockscout)
+```
+
+
+## {5. Try It}
+
+**Check the Game Window**
+
+Terri appears in the middle of a wall and gets completely lost when moving off screen!
+
+We'll fix that over the next couple of steps.
+
+
+
+## {6. Trapped Backstage}
+
+The Rockscout sprite should start at the stage door.
+
+---
+
+- :tree: To start Terri at the stage door, go to ``||scene:Scene||`` and drag
+``||scene: place [rockscout] on top of random [ ]||``
+to **the end** of the
+``||loops(noclick):on start||``
+container.
+
+- :mouse pointer: Click the checkered tile and select the teal stage door called **stage** from the grid.
+
+_💡 Don't forget to play with your project after each step to see the changes your code has made._
+
+
+
+#### ~ tutorialhint
+```blocks
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+controller.moveSprite(rockscout)
+// @highlight
+tiles.placeOnRandomTile(rockscout, assets.tile`stage`)
+
+```
+
+
+## {7. Follow with Camera}
+
+
+- :tree: To keep Terri in sight, go to ``||scene:Scene||`` and drag
+``||scene:camera follow sprite [rockscout]||``
+to **the end** of the
+``||loops(noclick):on start||`` container.
+
+#### ~ tutorialhint
+```blocks
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+controller.moveSprite(rockscout)
+tiles.placeOnRandomTile(rockscout, assets.tile`stage`)
+// @highlight
+scene.cameraFollowSprite(rockscout)
+
+```
+
+
+## {8. Look Again}
+
+**🕹️ Try your maze in the game window**
+
+---
+
+You should be able to see your sprite as you move it around backstage.
+
+Can you get to the exit?
+
+
+
+## {9. Add Points}
+
+**🎸 Award points when Terri grabs an instrument**
+
+---
+
+
+- :tree: To detect an overlap, go to ``||scene:Scene||`` and drag an
+``||scene:on [sprite] of kind [Player] overlaps [ ] at [location]||``
+bundle into an empty area of the workspace.
+
+- :mouse pointer: Change the "overlaps" checkerboard to the red guitar called **instrument1**.
+
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+```
+
+
+#### ~ tutorialhint
+```blocks
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+```
+
+## {10. Try It!}
+
+**🕹️ Try your maze in the game window**
+
+---
+
+You should get one point for every guitar you collect.
+
+What about the drums and keyboard?
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+```
+
+
+
+## {11. More Instruments}
+
+**🎹 Do it all again**
+Follow the same steps two more times to add points for the **drums** and **keyboard** tiles.
+
+
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+```
+
+#### ~ tutorialhint
+```blocks
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument0`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument4`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+```
+
+
+## {12. Look Again...Again}
+
+**🕹️ Try your maze again**
+
+---
+
+You should get one point for every instrument you collect!
+
+Can you make it to the exit?
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+```
+
+
+## {13. Out the Door}
+
+**🚪 Make it out the door**
+
+Let's finish the game with a WIN when Terri overlaps the exit door!
+
+---
+
+- :tree: To detect an overlap, go to ``||scene:Scene||`` and drag the
+``||scene:on [sprite] of kind [Player] overlaps [ ] at [location]||``
+bundle into an empty area of the workspace.
+
+- :mouse pointer: Change the checkerboard to the red door tile named **exit**.
+
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`exit`, function (sprite, location) {
+ game.over(true)
+})
+```
+
+
+#### ~ tutorialhint
+```blocks
+scene.onOverlapTile(SpriteKind.Player, assets.tile`exit`, function (sprite, location) {
+ game.over(true)
+})
+```
+
+
+
+## {14. Spot the Fan}
+
+**Remove points when Terri runs into a screaming fan 📸**
+
+When your sprite overlaps a fan, change the score.
+
+---
+
+- :tree: To detect an overlap, go to ``||scene:Scene||`` and drag the
+``||scene:on [sprite] of kind [Player] overlaps [ ] at [location]||``
+bundle into an empty area of the workspace.
+
+- :mouse pointer: Change the checkerboard to the tile called **fan1**.
+
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`fan1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(-1)
+})
+```
+
+
+#### ~ tutorialhint
+```blocks
+scene.onOverlapTile(SpriteKind.Player, assets.tile`fan1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(-1)
+})
+```
+
+
+## {15. More Fans}
+
+**🎤 Encore 🎤**
+
+Follow the same steps two more times to include the other two fans.
+
+
+```blockconfig.local
+scene.onOverlapTile(SpriteKind.Player, assets.tile`fan1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(-1)
+})
+```
+
+
+#### ~ tutorialhint
+```blocks
+scene.onOverlapTile(SpriteKind.Player, assets.tile`fan2`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(-1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`fan3`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(-1)
+})
+```
+
+
+## {16. Look Again}
+
+**🕹️ Try your maze in the game window**
+
+---
+
+You should lose one point for every fan you run into.
+
+How many points can you keep on your way to the door?
+
+
+## {17. Out of Time}
+
+**🕒 Make it out in time**
+
+Use a timer to add some hustle to the whole experience!
+
+---
+
+- :id card: From ``||info:Info||``, drag
+``||info:start countdown [30] (s)||``
+into **the end** of the
+``||loops(noclick):on start||``
+container.
+
+
+#### ~ tutorialhint
+```blocks
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+controller.moveSprite(rockscout)
+scene.cameraFollowSprite(rockscout)
+tiles.placeOnRandomTile(rockscout, assets.tile`stage`)
+//@highlight
+info.startCountdown(30)
+```
+
+
+
+
+## {18. Decision Tree}
+
+**Make it your own!**
+
+---
+
+Now you can change anything you want.
+
+Sometimes it's easiest to write down your plan so you know how each change will affect the game.
+
+Try making a decision tree!
+
+![Map it out](/static/skillmap/rockstar/decision-tree.png "Draw a decision tree - or flow chart - to detail what happens for each decision.")
+
+
+
+
+## {Finale}
+
+🔥 **Congratulations** 🔥
+
+---
+
+Grab your instruments and get Terri to the end of the maze before time runs out!
+
+When you're done playing, click **Done** to share your final game for feedback.
+
+
+
+```blockconfig.global
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+controller.moveSprite(rockscout)
+scene.cameraFollowSprite(rockscout)
+tiles.placeOnRandomTile(rockscout, assets.tile`stage`)
+game.over(true)
+info.startCountdown(30)
+```
+
+
+
+```package
+pxt-tilemaps=github:microsoft/pxt-tilemaps/
+```
+
+
+```ghost
+
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument0`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument4`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`exit`, function (sprite, location) {
+ game.over(true)
+})
+
+
+let rockscout = sprites.create(assets.image`Rockscout`, SpriteKind.Player)
+controller.moveSprite(rockscout)
+scene.cameraFollowSprite(rockscout)
+tiles.placeOnRandomTile(rockscout, assets.tile`stage`)
+
+
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument3`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument2`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`instrument1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(1)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`door`, function (sprite, location) {
+ game.over(true)
+})
+scene.onOverlapTile(SpriteKind.Player, assets.tile`fan1`, function (sprite, location) {
+ tiles.setTileAt(location, assets.tile`transparency16`)
+ info.changeScoreBy(-1)
+})
+
+```
+
+```customts
+scene.setBackgroundColor(13)
+tiles.setTilemap(tilemap`level1`)
+
+```
+
+
+
+```assetjson
+{
+ "README.md": " ",
+ "assets.json": "",
+ "images.g.jres": "{\n \"HR6MQZ`+AH8fF_EGjDHy\": {\n \"data\": \"hwQQABAAAAAAAAAAAAAAAAAAAAAAAAAAAADw////DwAA8P/v7u5NAAD/7//k/v8AAP/ustEe0f8A7+7y3xTR/wDv7kLdFNEPAF/u8t8U0f8AX+Wy0R7R/wD/5f/k/v8AAPD/7+7uTQAAAPD///8PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"displayName\": \"Rockscout\"\n },\n \"*\": {\n \"mimeType\": \"image/x-mkcd-f4\",\n \"dataEncoding\": \"base64\",\n \"namespace\": \"myImages\"\n }\n}",
+ "images.g.ts": "// Auto-generated code. Do not edit.\nnamespace myImages {\n\n helpers._registerFactory(\"image\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n case \"HR6MQZ`+AH8fF_EGjDHy\":\n case \"Rockscout\":return img`\n. . . . . . . . . . . . . . . . \n. . . . . . . . . . . . . . . . \n. . . . f f f f f f f . . . . . \n. . . f f f e e 5 5 f f . . . . \n. . . f f e e e e 5 5 f . . . . \n. . f f e e e e e e e f f . . . \n. . f f f 2 2 2 2 2 f f f . . . \n. . f e f b f 4 f b f e f . . . \n. . f e 4 1 f d f 1 4 e f . . . \n. . f e e d d d d d e e f . . . \n. . f e e e 4 4 4 e e e f . . . \n. . f e f 1 1 1 1 1 f e f . . . \n. . f d f 1 1 1 1 1 f d f . . . \n. . . 4 f d d d d d f 4 . . . . \n. . . . . f f f f f . . . . . . \n. . . . . f f . f f . . . . . . \n`;\n }\n return null;\n })\n\n helpers._registerFactory(\"animation\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n\n }\n return null;\n })\n\n}\n// Auto-generated code. Do not edit.\n",
+ "main.blocks": "PlayerProjectileFoodEnemyrockscoutlist",
+ "main.ts": "\n",
+ "pxt.json": "{\n \"name\": \"80s Rockscout - Assets Only\",\n \"description\": \"\",\n \"dependencies\": {\n \"device\": \"*\",\n \"tilemaps\": \"github:microsoft/pxt-tilemaps#v1.11.0\"\n },\n \"files\": [\n \"main.blocks\",\n \"main.ts\",\n \"README.md\",\n \"assets.json\",\n \"tilemap.g.jres\",\n \"tilemap.g.ts\",\n \"images.g.jres\",\n \"images.g.ts\"\n ],\n \"targetVersions\": {\n \"branch\": \"v1.5.56\",\n \"tag\": \"v1.5.56\",\n \"commits\": \"https://github.com/microsoft/pxt-arcade/commits/fb33e381b78eca2163bc40e2b26bdfdc9e7ebd81\",\n \"target\": \"1.5.56\",\n \"pxt\": \"7.1.35\"\n },\n \"preferredEditor\": \"blocksprj\"\n}\n",
+ "tilemap.g.jres": "{\n \"transparency16\": {\n \"data\": \"hwQQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true\n },\n \"tile4\": {\n \"data\": \"hwQQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8//////////zu7u7u7u7+/P7u7v/u/v787u7+u+/u/vzu7r/M++7+/O7uv8z77v787u7+u+/u/vz+7u7/7v7+/O7u7u7u7v78/////////8zMzMzMzMzMzMzMzMzMzAwAAAAAAAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"instrument3\"\n },\n \"tile5\": {\n \"data\": \"hwQQABAAAAAAwBEREQwAAADAETMRDAAAAMARMRMMAAAAwBEzEQwAAADAERERDAAAAMD87s8MAAAAAPDuwQAAAAD///8RDADA8O/v7h7LDM/P7+///xGM/8/s7vEvEWb///zu8SIRhgD//P7u7v9m/8/8/u7+7o//wP/v7v/uD88A////D/8AwA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"fan1\"\n },\n \"tile6\": {\n \"data\": \"hwQQABAAAAAAwBEREQwAAADAETMRDAAAAMARMRMMAAAAwBEzEQwAAADAERERDAAAAAD/RMwMAAAA8P9EwQAAAAD//7wRDADA8L9PRBvLDM/Pv0/u7hGM/8+8S+EuEWb//8xL4SIRhgD//PtEtMxm/8/8+/S/RIj/wP+7/89EDM8A////D8wAwA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"fan2\"\n },\n \"tile7\": {\n \"data\": \"hwQQABAAAAAAwBEREQwAAADAETMRDAAAAMARMRMMAAAAwBEzEQwAAADAERERDAAAAMDM3cwMAAAAAMDdwQAAAAD7/88RDADA0LXf3RvLDM8dtdzu7hGM/x3R2+EuEWb/XVHb4SIRhgBdUcvdvbtm/x1R+9293Yj/EFW13cvdC88AXVXPDLsAwA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"fan3\"\n },\n \"tile3\": {\n \"data\": \"hwQQABAAAAAAAAAA/+8AAAAAAPD/7g4AAAAA8G5E5AAAAADwRkREDgAA8P9GRETkAAD/L0TuROQAAO9GRORO5AAAb0T+Qk7kAABuRP9PROQAAOBE8k5EDgAA/09EJO4AAPDv7kTkAADw/+4A7g4AAO/kDgAAAAAAT+QAAAAAAADvDgAAAAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"instrument2\"\n },\n \"tile9\": {\n \"data\": \"hwQQABAAAAAAAAAAy8wMAAAAALDb280AAAAA+xHbzQAAALD7G73dDAAA+/0fsd0MALD727/R280A+/3fzBHbzbD727/RHbHMsP3fzBEd3c2w3b/RHbHLDADbzBEd3c0AANvRHbHLDAAAsBEd3c0AAACwHbHLDAAAAAAb3c0AAAAAALvLDAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"instrument4\"\n },\n \"tile10\": {\n \"data\": \"hwQQABAAAAAAwMz8////AAC8LLLMzPwAwLss0sy7/AC8u9zdvMzLD7y7u93f37wPvLvL3dv/vA+8u8vdzf2/D8C7y9v93Pv/wLu73L3////Au7vcvf///MC7u8zMzMz8ALy7MzMzM/sAvDuzu7u7DAC8M7u7u8sAADyzu7u7DAAAwMzMzMwAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"camera\"\n },\n \"tile2\": {\n \"data\": \"hwQQABAAAAAAAAAA/+4AAAAAAPDu7g4AAAAA4G4i4gAAAADwJiIiDgDw7/8mzCLiAP/u/yLcLOIA7yIiIrHN4gAuIiISEcziAC4C8BMRIeIA7gDvPhEiDgAA8O4u4+4AAADvDi7iAADw/+4AIuIAAO/kDgDuDgAAT+QAAAAAAADvDgAAAAAAAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"instrument1\"\n },\n \"tile12\": {\n \"data\": \"hwQQABAAAADM/P//zPzM/Mz8zPzMzMz8zMzM/MzMzPzM/Mz8zPzM/Mz8zPzM/Mz8zPzMzMz8zPzM/MzMzPzMzP//zPzM/MzMzPzM/Mz8zPzM/Mz8zPzM/Mz8zPz//8z8zMzM/Mz8zPzMzMz8zPzM/Mz8zPzM/Mz8zPzMzMz8zMzM/MzMzPz/zw==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"wall\"\n },\n \"tile13\": {\n \"data\": \"hwQQABAAAAD//////////x/RHbHbu9u9H7u7sd3P/L3fu7u9/c/8v9+7u73/zMz/37u7vczMzMzfu7u9zMzMzN+7u73MzMzM37u7vczMzMzfu7u9zMzMzN+7u73MzMzM37u7vf/MzP/fu7u9/c/8vx+7u7Hdz/y9H9Edsdu7273//////////w==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"stack\"\n },\n \"tile11\": {\n \"data\": \"hwQQABAAAAC7iIiIiIiIiLGIERZmZmZmEYhhEWZmZmYRiGdmZoiIZxGIERFmaGZnEYhnZmZoZmcRiBERZmhmZxGIcWdmaGZnEYgWEWZoZmcRiGZmZmhmZxGIEXFmaGZnEYhhEWZIaGcRiGZmZlSFZxGIERFmVIVmsYhxFmZGaGa7iIiIiIiIiA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"stage\"\n },\n \"tile1\": {\n \"data\": \"hwQQABAAAAC77u7u7u7u7rHuIiIiIiIiEe4SESEiIiIR7hIjIe7uIxHuIiIiLiIjEe4SMyEuIiMR7iIRIi4iIxHuEjMhLiIjEe4iIiIuIiMR7hIRIS4iIxHuIiIiLiIjEe4SIiJOLiMR7hIR4VTlIxHuEiLiVOUise4iIiJOLiK77u7u7u7u7g==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"exit\"\n },\n \"tile8\": {\n \"data\": \"hwQQABAAAAAAALALsAsAAAAA27u7vQAAAAC7HdG9DgAAsB0RsfvrALDbEd0R+78O2xvR3RHr/uu7Hd3d0dvuv7AR3R2x3ev+sBEREbu/3e67vRG96/LS7du9u9svIi/tsPvv3fsi8g4Avu++LS8iDwDg++7d8uIAAAC+797tDgAAAOD77g4AAA==\",\n \"mimeType\": \"image/x-mkcd-f4\",\n \"tilemapTile\": true,\n \"displayName\": \"instrument0\"\n },\n \"level1\": {\n \"id\": \"level1\",\n \"mimeType\": \"application/mkcd-tilemap\",\n \"data\": \"MTAxMDAwMTAwMDBhMGEwYTBhMGEwYTBhMGEwYTBhMGEwYTBhMGEwYjBiMGEwMDAwMDAwMDAwMDAwYTAwMDAwMDAwMDAwMDAwMGEwOTAwMGIwYjAwMGEwNTBhMDAwYjAwMGEwMDBiMDAwYTBhMDAwYjBiMDAwYTBhMGEwMDBhMDAwYTAwMGEwMDBhMGEwMDAwMDAwYjBhMDMwYTAwMGEwMDBiMDAwYTAwMGEwYTAwMGEwYTBhMGEwMDBiMDAwYTAwMDAwMDBhMDAwYTBhMDAwMDAwMDAwMDAwMDAwMDBhMDMwYTAwMGEwMDBhMGEwMDA3MGEwYTBhMGEwYjAwMGEwYTBhMDAwYTAwMGEwYTAwMDAwMDBhMDAwNDAwMDAwYTA4MGEwMDBhMDAwYTBhMDAwYTBhMGEwMDBhMGEwYTBhMDAwYjAwMGEwMDBhMGEwMDAwMDAwMDAwMGEwMDAwMDAwMDAwMDAwYTAwMGEwYTAwMGIwYTBhMGEwYjBhMGEwYTBhMGEwNjBhMDAwYTBhMDAwMDAwMDAwYzBhMGIwYjBiMDAwMDAwMGEwMDBhMGEwMDBhMGEwYTBhMGEwYTBhMGEwYTBhMGEwYjAwMGIwYTA2MGEwODAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMTBhMGEwYTBhMGEwYTBhMGEwYTBhMGEwYTBhMGEwYTAyMjIyMjIyMjIyMjIyMjIyMjAyMDAwMDIwMDAwMDAwMjAwMDIyMjAyMDAwMjAwMDIwMDIyMjIwMjIyMDIwMjAyMDAyMDAyMjIwMjAwMDIwMjAwMjIyMjIwMDIwMDAyMDIwMDIwMDAwMDAyMDIwMjAyMDAyMjAyMjIyMjAyMjIwMjAwMjAwMDIwMjIwMjAyMDIwMDIyMjAyMjIyMjAwMjAyMDAyMDAwMDAyMDAwMDIwMjAwMjIwMjIyMjIyMjIyMDIwMDIwMDAwMDIwMDAwMjAyMDAyMjIyMjIyMjIyMjIyMDAwMjAyMDAwMDAwMDAwMDAwMjIyMjIyMjIyMjIyMjIwMg==\",\n \"tileset\": [\n \"myTiles.transparency16\",\n \"myTiles.tile1\",\n \"sprites.castle.tileGrass2\",\n \"myTiles.tile2\",\n \"myTiles.tile4\",\n \"myTiles.tile5\",\n \"myTiles.tile6\",\n \"myTiles.tile7\",\n \"myTiles.tile8\",\n \"myTiles.tile11\",\n \"myTiles.tile12\",\n \"myTiles.tile13\",\n \"myTiles.tile9\"\n ],\n \"displayName\": \"level1\"\n },\n \"*\": {\n \"mimeType\": \"image/x-mkcd-f4\",\n \"dataEncoding\": \"base64\",\n \"namespace\": \"myTiles\"\n }\n}",
+ "tilemap.g.ts": "// Auto-generated code. Do not edit.\nnamespace myTiles {\n //% fixedInstance jres blockIdentity=images._tile\n export const transparency16 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile4 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile5 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile6 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile7 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile3 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile9 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile10 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile2 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile12 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile13 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile11 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile1 = image.ofBuffer(hex``);\n //% fixedInstance jres blockIdentity=images._tile\n export const tile8 = image.ofBuffer(hex``);\n\n helpers._registerFactory(\"tilemap\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n case \"level1\":\n case \"level1\":return tiles.createTilemap(hex`100010000a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0a0000000000000a000000000000000a09000b0b000a050a000b000a000b000a0a000b0b000a0a0a000a000a000a000a0a0000000b0a030a000a000b000a000a0a000a0a0a0a000b000a0000000a000a0a00000000000000000a030a000a000a0a00070a0a0a0a0b000a0a0a000a000a0a0000000a000400000a080a000a000a0a000a0a0a000a0a0a0a000b000a000a0a00000000000a0000000000000a000a0a000b0a0a0a0b0a0a0a0a0a060a000a0a000000000c0a0b0b0b0000000a000a0a000a0a0a0a0a0a0a0a0a0a0a0b000b0a060a080000000000000000000000010a0a0a0a0a0a0a0a0a0a0a0a0a0a0a02`, img`\n2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 \n2 . . . . . . 2 . . . . . . . 2 \n. . 2 2 . 2 . 2 . . . 2 . . . 2 \n2 . 2 2 . 2 2 2 . 2 . 2 . 2 . 2 \n2 . . . 2 2 . 2 . 2 . . . 2 . 2 \n2 . 2 2 2 2 . . . 2 . . . 2 . 2 \n2 . . . . . . . . 2 . 2 . 2 . 2 \n2 . . 2 2 2 2 2 . 2 2 2 . 2 . 2 \n2 . . . 2 . 2 . . 2 . 2 . 2 . 2 \n2 . 2 2 2 . 2 2 2 2 . . . 2 . 2 \n2 . . . . . 2 . . . . . . 2 . 2 \n2 . . 2 2 2 2 2 2 2 2 2 . 2 . 2 \n2 . . . . . 2 . . . . . . 2 . 2 \n2 . 2 2 2 2 2 2 2 2 2 2 2 2 . . \n2 . 2 . . . . . . . . . . . . . \n2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 . \n`, [myTiles.transparency16,myTiles.tile1,sprites.castle.tileGrass2,myTiles.tile2,myTiles.tile4,myTiles.tile5,myTiles.tile6,myTiles.tile7,myTiles.tile8,myTiles.tile11,myTiles.tile12,myTiles.tile13,myTiles.tile9], TileScale.Sixteen);\n }\n return null;\n })\n\n helpers._registerFactory(\"tile\", function(name: string) {\n switch(helpers.stringTrim(name)) {\n case \"transparency16\":return transparency16;\n case \"instrument3\":\n case \"tile4\":return tile4;\n case \"fan1\":\n case \"tile5\":return tile5;\n case \"fan2\":\n case \"tile6\":return tile6;\n case \"fan3\":\n case \"tile7\":return tile7;\n case \"instrument2\":\n case \"tile3\":return tile3;\n case \"instrument4\":\n case \"tile9\":return tile9;\n case \"camera\":\n case \"tile10\":return tile10;\n case \"instrument1\":\n case \"tile2\":return tile2;\n case \"wall\":\n case \"tile12\":return tile12;\n case \"stack\":\n case \"tile13\":return tile13;\n case \"stage\":\n case \"tile11\":return tile11;\n case \"exit\":\n case \"tile1\":return tile1;\n case \"instrument0\":\n case \"tile8\":return tile8;\n }\n return null;\n })\n\n}\n// Auto-generated code. Do not edit.\n"
+}
+```
+
+
+