TurboBuilder is currently in development, some project files may break due to code changing all the time.

Extension
Sprites
Sound
Events
Control
Sensing
Literals
Operators
Conversions
Variables
JSON
Blocks
Menus
Functions
Technical
get sprite namedstageisstagex ofy ofdirection ofstart soundhttps://t.ly/2gHlMeveryseconds doinseconds dowait(ms)wait untilrepeatwhiledoifthenifthenelseifthenelseswitchcasedefaultbreakalertpromptconfirmtime (ms) since 1970current yearis leap year?nulltruefalse(0)'string'blank arrayarray of lengthblank object====><andorxornot+-*÷modulo^logrootsinrandom fromtorandom int fromtojoinsplitwithletteroflength ofto numberto stringmillisecondstomillisecondssettogetset localstoragetoget localstorageisvalid JSON?stringto JSONJSONto stringinsertat end ofsettoin arraymerge arraywithgetfrom arraylength of arraysettoin objectmerge objectwithgetfrom objectkeys of objectvalues of objectcreate blockid:idtext:texttype:blockinputs:function:create inputid:IDtype:stringdefault:create menu inputid:IDmenu:IDcall hatHATIDcurrent spritegetINPUTIDreturncreate menuid:idvalues:allow inputs:truecreate dynamic menuid:idfunction:allow inputs:truereturndefinereturnfunction argumentexecutewithexecutewithlogwarnerrorraw raw // /**/code finished successfully? (runs code)SpritesSoundEventsControlSensingLiteralsOperatorsConversionsVariablesJSONBlocksMenusFunctionsTechnical

Assets

Extra things that will appear under "Extension" in the block list.
These things are not required, so you can leave them empty if you do not need them.

Documentation URL:

Extension Icon:

Extra Icons

Blocks can use their own icons instead of the Extension icon.
Add more images here to use them.

Extension Code

/* This extension was made with TurboBuilder! https://turbobuilder-steel.vercel.app/ */ (async function(Scratch) { const variables = {}; const blocks = []; const menus = {}; if (!Scratch.extensions.unsandboxed) { alert("This extension needs to be unsandboxed to run!") return } function doSound(ab, cd, runtime) { const audioEngine = runtime.audioEngine; const fetchAsArrayBufferWithTimeout = (url) => new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); let timeout = setTimeout(() => { xhr.abort(); reject(new Error("Timed out")); }, 5000); xhr.onload = () => { clearTimeout(timeout); if (xhr.status === 200) { resolve(xhr.response); } else { reject(new Error(`HTTP error ${xhr.status} while fetching ${url}`)); } }; xhr.onerror = () => { clearTimeout(timeout); reject(new Error(`Failed to request ${url}`)); }; xhr.responseType = "arraybuffer"; xhr.open("GET", url); xhr.send(); }); const soundPlayerCache = new Map(); const decodeSoundPlayer = async (url) => { const cached = soundPlayerCache.get(url); if (cached) { if (cached.sound) { return cached.sound; } throw cached.error; } try { const arrayBuffer = await fetchAsArrayBufferWithTimeout(url); const soundPlayer = await audioEngine.decodeSoundPlayer({ data: { buffer: arrayBuffer, }, }); soundPlayerCache.set(url, { sound: soundPlayer, error: null, }); return soundPlayer; } catch (e) { soundPlayerCache.set(url, { sound: null, error: e, }); throw e; } }; const playWithAudioEngine = async (url, target) => { const soundBank = target.sprite.soundBank; let soundPlayer; try { const originalSoundPlayer = await decodeSoundPlayer(url); soundPlayer = originalSoundPlayer.take(); } catch (e) { console.warn( "Could not fetch audio; falling back to primitive approach", e ); return false; } soundBank.addSoundPlayer(soundPlayer); await soundBank.playSound(target, soundPlayer.id); delete soundBank.soundPlayers[soundPlayer.id]; soundBank.playerTargets.delete(soundPlayer.id); soundBank.soundEffects.delete(soundPlayer.id); return true; }; const playWithAudioElement = (url, target) => new Promise((resolve, reject) => { const mediaElement = new Audio(url); mediaElement.volume = target.volume / 100; mediaElement.onended = () => { resolve(); }; mediaElement .play() .then(() => { // Wait for onended }) .catch((err) => { reject(err); }); }); const playSound = async (url, target) => { try { if (!(await Scratch.canFetch(url))) { throw new Error(`Permission to fetch ${url} denied`); } const success = await playWithAudioEngine(url, target); if (!success) { return await playWithAudioElement(url, target); } } catch (e) { console.warn(`All attempts to play ${url} failed`, e); } }; playSound(ab, cd) } class Extension { getInfo() { return { "id": "extensionID", "name": "Extension", "color1": "#0088ff", "color2": "#0063ba", "tbShow": true, "blocks": blocks, "menus": menus } } } Scratch.extensions.register(new Extension()); })(Scratch);