From 2600025c3f290ef561f7d4b25eaa130ff97ca936 Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Sat, 19 Aug 2023 20:53:37 -0500 Subject: [PATCH] Declarative extension list (#905) index.ejs is gone, replaced by extension.json and in-source header comments Also added a JSON file, to be used for something else soon --- CONTRIBUTING.md | 15 +- development/builder.js | 252 +++++-- development/homepage-template.ejs | 334 +++++++++ development/parse-extension-metadata.js | 103 +++ development/server.js | 8 +- extensions/-SIPC-/consoles.js | 4 + extensions/-SIPC-/time.js | 4 + extensions/0832/rxFS2.js | 4 + extensions/Alestore/nfcwarp.js | 4 + extensions/CST1229/zip.js | 4 + extensions/CubesterYT/TurboHook.js | 4 + extensions/DT/cameracontrols.js | 4 + extensions/JeremyGamer13/tween.js | 4 + extensions/Lily/AllMenus.js | 4 + extensions/Lily/Cast.js | 4 + extensions/Lily/ClonesPlus.js | 4 + extensions/Lily/CommentBlocks.js | 4 + extensions/Lily/LooksPlus.js | 4 + extensions/Lily/McUtils.js | 4 + extensions/Lily/MoreTimers.js | 4 + extensions/Lily/Skins.js | 4 + extensions/Lily/TempVariables2.js | 4 + extensions/Longboost/color_channels.js | 3 + extensions/NOname-awa/graphics2d.js | 4 + extensions/NOname-awa/more-comparisons.js | 4 + extensions/NexusKitten/moremotion.js | 4 + extensions/NexusKitten/sgrab.js | 4 + extensions/Skyhigh173/bigint.js | 4 + extensions/Skyhigh173/json.js | 4 + extensions/TheShovel/CanvasEffects.js | 4 + extensions/TheShovel/CustomStyles.js | 4 + extensions/TheShovel/LZ-String.js | 3 + extensions/TheShovel/ShovelUtils.js | 4 + extensions/Xeltalliv/clippingblending.js | 4 + extensions/XeroName/Deltatime.js | 4 + extensions/ZXMushroom63/searchApi.js | 4 + extensions/ar.js | 4 + extensions/battery.js | 3 + extensions/bitwise.js | 4 + extensions/box2d.js | 4 + extensions/clipboard.js | 3 + extensions/clouddata-ping.js | 4 + extensions/cloudlink.js | 4 + extensions/cs2627883/numericalencoding.js | 4 + extensions/cursor.js | 3 + extensions/encoding.js | 4 + extensions/extensions.json | 72 ++ extensions/fetch.js | 3 + extensions/files.js | 3 + extensions/gamejolt.js | 4 + extensions/gamepad.js | 3 + extensions/godslayerakp/http.js | 4 + extensions/itchio.js | 4 + extensions/lab/text.js | 3 + extensions/local-storage.js | 3 + extensions/mdwalters/notifications.js | 3 + extensions/navigator.js | 3 + extensions/obviousAlexC/SensingPlus.js | 4 + extensions/obviousAlexC/newgroundsIO.js | 4 + extensions/penplus.js | 4 + extensions/pointerlock.js | 3 + extensions/qxsck/data-analysis.js | 4 + extensions/qxsck/var-and-list.js | 4 + extensions/rixxyx.js | 4 + extensions/runtime-options.js | 3 + extensions/sound.js | 3 + extensions/stretch.js | 3 + extensions/text.js | 6 +- extensions/true-fantom/base.js | 4 + extensions/true-fantom/couplers.js | 4 + extensions/true-fantom/math.js | 4 + extensions/true-fantom/network.js | 4 + extensions/true-fantom/regexp.js | 4 + extensions/utilities.js | 4 + extensions/veggiecan/LongmanDictionary.js | 5 +- extensions/vercte/dictionaries.js | 4 + website/index.ejs | 810 ---------------------- 77 files changed, 963 insertions(+), 898 deletions(-) create mode 100644 development/homepage-template.ejs create mode 100644 development/parse-extension-metadata.js create mode 100644 extensions/extensions.json delete mode 100644 website/index.ejs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3967ac4389..9af7a91309 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,13 +39,24 @@ Extensions must be self-contained. All libraries and hardcoded resources should ## Website stuff -To add an extension to the website homepage, modify [`website/index.ejs`](website/index.ejs). See the existing entries for a template to copy. Place your extension wherever you want in the list. We will move it for you if we disagree. +To add an extension to the homepage, you need to add metadata comments at the very start of the extension's JavaScript, and add the extension's path (without .js) to `extensions/extensions.json`. The order of that list determines the order of the library. Don't worry about putting it in the right spot, we'll move it if we disagree. + +The header comments look like this: + +```js +// Name: Example Extension +// Description: Does a very cool thing. This must have punctuation at the end! +// By: GarboMuffin +// Original: TestMuffin +``` + +Remember, this has to be the *very first* thing in the JS file. `Name` and `Description` are required. You can have zero or more `By` and `Original`. Put credit links in `` if you have one. It must point to a Scratch user profile. The parser is pretty loose, but try not to deviate too far from this format. New extensions do not *need* images, but they are highly encouraged. Save the image in the `images` folder with the same folder name and file name (but different file extension) as the extension's source code. For example, if your extension is located in `extensions/TestMuffin/fetch.js`, save the image as `images/TestMuffin/fetch.svg` or `images/TestMuffin/fetch.png`. The homepage generator will detect it automatically. Images are displayed in a 2:1 aspect ratio. SVG (preferred), PNG, or JPG are accepted. PNG or JPG should be 600x300 in resolution. Please add proper attribution to `images/README.md` for *any* resources that were not made by you. Most extensions shouldn't need external documentation -- it should be obvious what to do just by looking at the blocks. That said, some do need more explanation. Documentation is written in markdown and placed in the `docs` folder with a similar layout to images. For example, documentation for `extensions/TestMuffin/fetch.js` would be saved as `docs/TestMuffin/fetch.md`. Our version of markdown is slightly extended to allow rendering [scratchblocks](https://scratchblocks.github.io/). Just look at the existing documentation for syntax examples. It's not a perfect experience: block colors have to be manually copied, and icons aren't supported, but it's better than what we had before. Once you put your markdown there, you can set a `docsURI` like `https://extensions.turbowarp.org/TestMuffin/fetch`. -Static resources, such as example links, go in the `website` folder. This is where some example assets used by extensions such as fetch are placed. +Static resources such as example resources used by extensions go in the `website` folder. ## Banned APIs diff --git a/development/builder.js b/development/builder.js index a5613ecee1..a9c735b62c 100644 --- a/development/builder.js +++ b/development/builder.js @@ -4,6 +4,8 @@ const sizeOfImage = require('image-size'); const renderTemplate = require('./render-template'); const renderDocs = require('./render-docs'); const compatibilityAliases = require('./compatibility-aliases'); +const parseMetadata = require('./parse-extension-metadata'); +const featuredExtensionsIDs = require('../extensions/extensions.json'); /** * @typedef {'development'|'production'|'desktop'} Mode @@ -15,7 +17,7 @@ const compatibilityAliases = require('./compatibility-aliases'); * @returns {Array<[string, string]>} List of tuples [name, absolutePath]. * The return result includes files in subdirectories, but not the subdirectories themselves. */ -const readDirectory = (directory) => { +const recursiveReadDirectory = (directory) => { const result = []; for (const name of fs.readdirSync(directory)) { if (name.startsWith('.')) { @@ -25,7 +27,7 @@ const readDirectory = (directory) => { const absolutePath = pathUtil.join(directory, name); const stat = fs.statSync(absolutePath); if (stat.isDirectory()) { - for (const [relativeToChildName, childAbsolutePath] of readDirectory(absolutePath)) { + for (const [relativeToChildName, childAbsolutePath] of recursiveReadDirectory(absolutePath)) { // This always needs to use / on all systems result.push([`${name}/${relativeToChildName}`, childAbsolutePath]); } @@ -36,55 +38,160 @@ const readDirectory = (directory) => { return result; }; -class DiskFile { - constructor (path) { - this.path = path; +class BuildFile { + constructor (source) { + this.sourcePath = source; } - getDiskPath () { - return this.path; + getType () { + return pathUtil.extname(this.sourcePath); } getLastModified () { - return fs.statSync(this.path).mtimeMs; + return fs.statSync(this.sourcePath).mtimeMs; } read () { - return fs.readFileSync(this.path); + return fs.readFileSync(this.sourcePath); } validate () { - // no-op + // no-op by default } } -class ExtensionFile extends DiskFile { - constructor (relativePath, path) { - super(path); - this.relativePath = relativePath; +class ExtensionFile extends BuildFile { + constructor (absolutePath, featured) { + super(absolutePath); + this.featured = featured; + } + + getMetadata () { + const data = fs.readFileSync(this.sourcePath, 'utf-8'); + return parseMetadata(data); } - // TODO: we can add some code to eg. show a message when the extension was modified on disk? + validate () { + if (!this.featured) { + return; + } + + const metadata = this.getMetadata(); + + if (!metadata.name) { + throw new Error('Missing // Name:'); + } + + if (!metadata.description) { + throw new Error('Missing // Description:'); + } + + const PUNCTUATION = ['.', '!', '?']; + if (!PUNCTUATION.some((punctuation) => metadata.description.endsWith(punctuation))) { + throw new Error(`Description is missing punctuation: ${metadata.description}`); + } + + for (const person of [...metadata.by, ...metadata.original]) { + if (!person.name) { + throw new Error('Person is missing name'); + } + if (person.link && !person.link.startsWith('https://scratch.mit.edu/users/')) { + throw new Error(`Link for ${person.name} does not point to a Scratch user`); + } + } + } } -class HTMLFile extends DiskFile { - constructor (path, data) { - super(path); - this.data = data; - // force development server to use read() - this.getDiskPath = null; +class HomepageFile extends BuildFile { + constructor (extensionFiles, extensionImages, mode) { + super(pathUtil.join(__dirname, 'homepage-template.ejs')); + + /** @type {Record} */ + this.extensionFiles = extensionFiles; + + /** @type {Record} */ + this.extensionImages = extensionImages; + + /** @type {Mode} */ + this.mode = mode; + + this.host = mode === 'development' ? 'http://localhost:8000/' : 'https://extensions.turbowarp.org/'; } getType () { return '.html'; } + getFullExtensionURL (extensionID) { + return `${this.host}${extensionID}.js`; + } + + getRunExtensionURL (extensionID) { + return `https://turbowarp.org/editor?extension=${this.getFullExtensionURL(extensionID)}`; + } + + read () { + const mostRecentExtensions = Object.entries(this.extensionFiles) + .sort((a, b) => b[1].getLastModified() - a[1].getLastModified()) + .slice(0, 5) + .map((i) => i[0]); + + const extensionMetadata = Object.fromEntries(featuredExtensionsIDs.map((id) => [ + id, + this.extensionFiles[id].getMetadata() + ])); + + return renderTemplate(this.sourcePath, { + mode: this.mode, + mostRecentExtensions, + extensionImages: this.extensionImages, + extensionMetadata, + getFullExtensionURL: this.getFullExtensionURL.bind(this), + getRunExtensionURL: this.getRunExtensionURL.bind(this) + }); + } +} + +class JSONMetadataFile extends BuildFile { + constructor (extensionFiles, extensionImages) { + super(null); + + /** @type {Record} */ + this.extensionFiles = extensionFiles; + + /** @type {Record} */ + this.extensionImages = extensionImages; + } + + getType () { + return '.json'; + } + read () { - return renderTemplate(this.path, this.data); + const extensions = []; + for (const extensionID of featuredExtensionsIDs) { + const extension = {}; + const file = this.extensionFiles[extensionID]; + const metadata = file.getMetadata(); + const image = this.extensionImages[extensionID]; + + extension.id = extensionID; + extension.name = metadata.name; + extension.description = metadata.description; + if (image) { + extension.image = image; + } + extensions.push(extension); + } + + const data = { + extensions + }; + return JSON.stringify(data); } } -class ImageFile extends DiskFile { +class ImageFile extends BuildFile { validate () { const contents = this.read(); const {width, height} = sizeOfImage(contents); @@ -106,10 +213,9 @@ class SVGFile extends ImageFile { } } -class SitemapFile extends DiskFile { +class SitemapFile extends BuildFile { constructor (build) { super(null); - this.getDiskPath = null; this.build = build; } @@ -144,11 +250,10 @@ IMAGE_FORMATS.set('.png', ImageFile); IMAGE_FORMATS.set('.jpg', ImageFile); IMAGE_FORMATS.set('.svg', SVGFile); -class DocsFile extends DiskFile { - constructor (path, extensionId) { - super(path); +class DocsFile extends BuildFile { + constructor (absolutePath, extensionId) { + super(absolutePath); this.extensionId = extensionId; - this.getDiskPath = null; } read () { @@ -162,7 +267,10 @@ class DocsFile extends DiskFile { } class Build { - constructor () { + constructor (mode) { + /** @type {Mode} */ + this.mode = mode; + this.files = {}; } @@ -182,6 +290,10 @@ class Build { } for (const [relativePath, file] of Object.entries(this.files)) { + if (this.mode === 'desktop' && relativePath.endsWith('.html')) { + continue; + } + const directoryName = pathUtil.dirname(relativePath); fs.mkdirSync(pathUtil.join(root, directoryName), { recursive: true @@ -207,78 +319,65 @@ class Builder { this.mode = mode; } - this.extensionsRoot = pathUtil.join(__dirname, '..', 'extensions'); - this.websiteRoot = pathUtil.join(__dirname, '..', 'website'); - this.imagesRoot = pathUtil.join(__dirname, '..', 'images'); - this.docsRoot = pathUtil.join(__dirname, '..', 'docs'); + this.extensionsRoot = pathUtil.join(__dirname, '../extensions'); + this.websiteRoot = pathUtil.join(__dirname, '../website'); + this.imagesRoot = pathUtil.join(__dirname, '../images'); + this.docsRoot = pathUtil.join(__dirname, '../docs'); } build () { - const build = new Build(); + const build = new Build(this.mode); - const images = {}; - for (const [imageFilename, path] of readDirectory(this.imagesRoot)) { - const extension = pathUtil.extname(imageFilename); + /** @type {Record} */ + const extensionImages = {}; + for (const [filename, absolutePath] of recursiveReadDirectory(this.imagesRoot)) { + const extension = pathUtil.extname(filename); const ImageFileClass = IMAGE_FORMATS.get(extension); if (!ImageFileClass) { continue; } - const extensionId = imageFilename.split('.')[0]; + const extensionId = filename.split('.')[0]; if (extensionId !== 'unknown') { - images[extensionId] = imageFilename; + extensionImages[extensionId] = `images/${filename}`; } - build.files[`/images/${imageFilename}`] = new ImageFileClass(path); + build.files[`/images/${filename}`] = new ImageFileClass(absolutePath); } - for (const [docsFilename, path] of readDirectory(this.docsRoot)) { - if (!docsFilename.endsWith('.md')) { + for (const [filename, absolutePath] of recursiveReadDirectory(this.docsRoot)) { + if (!filename.endsWith('.md')) { continue; } - const extensionId = docsFilename.split('.')[0]; - build.files[`/${extensionId}.html`] = new DocsFile(path, extensionId); + const extensionId = filename.split('.')[0]; + build.files[`/${extensionId}.html`] = new DocsFile(absolutePath, extensionId); } const scratchblocksPath = pathUtil.join(__dirname, '../node_modules/scratchblocks/build/scratchblocks.min.js'); - build.files['/docs-internal/scratchblocks.js'] = new DiskFile(scratchblocksPath); + build.files['/docs-internal/scratchblocks.js'] = new BuildFile(scratchblocksPath); - const extensionFiles = []; - for (const [extensionFilename, path] of readDirectory(this.extensionsRoot)) { - if (!extensionFilename.endsWith('.js')) { + /** @type {Record} */ + const extensionFiles = {}; + for (const [filename, absolutePath] of recursiveReadDirectory(this.extensionsRoot)) { + if (!filename.endsWith('.js')) { continue; } - const file = new ExtensionFile(extensionFilename, path); - extensionFiles.push(file); - build.files[`/${extensionFilename}`] = file; + const extensionId = filename.split('.')[0]; + const featured = featuredExtensionsIDs.includes(extensionId); + const file = new ExtensionFile(absolutePath, featured); + extensionFiles[extensionId] = file; + build.files[`/${filename}`] = file; } for (const [oldPath, newPath] of Object.entries(compatibilityAliases)) { build.files[oldPath] = build.files[newPath]; } - if (this.mode !== 'desktop') { - build.files['/sitemap.xml'] = new SitemapFile(build); + for (const [filename, absolutePath] of recursiveReadDirectory(this.websiteRoot)) { + build.files[`/${filename}`] = new BuildFile(absolutePath); } - const mostRecentExtensions = extensionFiles - .sort((a, b) => b.getLastModified() - a.getLastModified()) - .slice(0, 5) - .map((file) => file.relativePath); - - const ejsData = { - mode: this.mode, - host: this.mode === 'development' ? 'http://localhost:8000/' : 'https://extensions.turbowarp.org/', - mostRecentExtensions: mostRecentExtensions, - extensionImages: images - }; - - for (const [websiteFilename, path] of readDirectory(this.websiteRoot)) { - if (websiteFilename.endsWith('.ejs')) { - const realFilename = websiteFilename.replace('.ejs', '.html'); - build.files[`/${realFilename}`] = new HTMLFile(path, ejsData); - } else { - build.files[`/${websiteFilename}`] = new DiskFile(path); - } - } + build.files['/index.html'] = new HomepageFile(extensionFiles, extensionImages, this.mode); + build.files['/generated-metadata/extensions-v0.json'] = new JSONMetadataFile(extensionFiles, extensionImages); + build.files['/sitemap.xml'] = new SitemapFile(build); return build; } @@ -292,10 +391,11 @@ class Builder { const time = Date.now() - start.getTime(); console.log(`done in ${time}ms`); return build; - } catch (e) { + } catch (error) { console.log('error'); - console.error(e); + console.error(error); } + return null; } diff --git a/development/homepage-template.ejs b/development/homepage-template.ejs new file mode 100644 index 0000000000..ad693af7a2 --- /dev/null +++ b/development/homepage-template.ejs @@ -0,0 +1,334 @@ + + + + + + TurboWarp Extension Gallery + + + + + + +
+

+ +
TurboWarp Extension Gallery
+

+ +

Unlike custom extensions on other websites, these aren't limited by the extension sandbox, so they are a lot more powerful. All extensions are reviewed for safety.

+

+ To use multiple of these extensions in TurboWarp, hover over the extension and press the button to copy its URL. Then go to the editor, open the extension chooser, then choose the "Custom Extension" option at the bottom, and enter the URL. +

+ +
+
These extensions are not compatible with Scratch.
+ Projects that use these extensions can't be uploaded to the Scratch website. + They can, however, be used in the packager. +
+ +
+ For compatibility, security, and offline support, each TurboWarp Desktop update contains an offline copy of these extensions from its release date, so some extensions may be outdated or missing. + Use the latest update for best results. +
+
+ + <% if (mode === "development") { %> +
+
+

Development Server Tools

+

+ Most recently modified extensions: + <% for (const extensionID of mostRecentExtensions) { %> + <%= extensionID %>.js + <% } %> +

+
+
+ <% } %> + + + +
+
+ <% + const peopleToHTML = (people) => { + let result = ''; + for (let i = 0; i < people.length; i++) { + result += people[i].toHTML(); + if (i === people.length - 1) { + // do nothing + } else if (i === people.length - 2) { + if (people.length > 2) { + result += ','; + } + result += ' and '; + } else { + result += ', '; + } + } + return result; + }; + %> + <% for (const [extensionID, metadata] of Object.entries(extensionMetadata)) { %> +
+
+ <% const image = extensionImages[extensionID] || 'images/unknown.svg'; %> + + +
+ + Open Extension +
+
+ +

<%= metadata.name %>

+

+ <%= metadata.description %> + <%- metadata.by.length ? `Created by ${peopleToHTML(metadata.by)}.` : '' %> + <%- metadata.original.length ? `Originally created by ${peopleToHTML(metadata.original)}.` : '' %> +

+
+ <% } %> +
+
+ + + + diff --git a/development/parse-extension-metadata.js b/development/parse-extension-metadata.js new file mode 100644 index 0000000000..a640b2ef33 --- /dev/null +++ b/development/parse-extension-metadata.js @@ -0,0 +1,103 @@ +class Person { + constructor (name, link) { + /** @type {string} */ + this.name = name; + /** @type {string|null} */ + this.link = link; + } + + toHTML () { + // Don't need to bother escaping here. There's no vulnerability. + if (this.link) { + return `${this.name}`; + } + return this.name; + } +} + +class Extension { + constructor () { + this.id = ''; + this.name = ''; + this.description = ''; + /** @type {Person[]} */ + this.by = []; + /** @type {Person[]} */ + this.original = []; + } +} + +/** + * @param {string} string + * @param {string} split + * @returns {string[]} + */ +const splitFirst = (string, split) => { + const idx = string.indexOf(split); + if (idx === -1) { + return [string]; + } + return [string.substring(0, idx), string.substring(idx + split.length)]; +}; + +/** + * @param {string} person + * @returns {Person} + */ +const parsePerson = (person) => { + const parts = splitFirst(person, '<'); + if (parts.length === 1) { + return new Person(person, null); + } + + const name = parts[0].trim(); + const link = parts[1].replace('>', ''); + return new Person(name, link); +}; + +/** + * @param {string} extensionCode + * @return {Extension} + */ +const parseMetadata = (extensionCode) => { + const metadata = new Extension(); + + for (const line of extensionCode.split('\n')) { + if (!line.startsWith('//')) { + // End of header. + break; + } + + const withoutComment = line.substring(2).trim(); + const parts = splitFirst(withoutComment, ':'); + if (parts.length === 1) { + // Invalid. + continue; + } + + const key = parts[0].toLowerCase().trim(); + const value = parts[1].trim(); + + switch (key) { + case 'name': + metadata.name = value; + break; + case 'description': + metadata.description = value; + break; + case 'by': + metadata.by.push(parsePerson(value)); + break; + case 'original': + metadata.original.push(parsePerson(value)); + break; + default: + // TODO + break; + } + } + + return metadata; +}; + +module.exports = parseMetadata; diff --git a/development/server.js b/development/server.js index 4f80d73dd3..e0bdfee855 100644 --- a/development/server.js +++ b/development/server.js @@ -49,12 +49,8 @@ app.get('/*', (req, res, next) => { return next(); } - if (fileInBuild.getDiskPath) { - res.sendFile(fileInBuild.getDiskPath()); - } else { - res.contentType(fileInBuild.getType()); - res.send(fileInBuild.read()); - } + res.contentType(fileInBuild.getType()); + res.send(fileInBuild.read()); }); app.use((req, res) => { diff --git a/extensions/-SIPC-/consoles.js b/extensions/-SIPC-/consoles.js index ccfa67059f..4591507ace 100644 --- a/extensions/-SIPC-/consoles.js +++ b/extensions/-SIPC-/consoles.js @@ -1,3 +1,7 @@ +// Name: Consoles +// Description: Blocks that interact the JavaScript console built in to your browser's developer tools. +// By: -SIPC- + (function (Scratch) { 'use strict'; const icon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4MS41NTIwNyIgaGVpZ2h0PSI4MC42MDMwOCIgdmlld0JveD0iMCwwLDgxLjU1MjA3LDgwLjYwMzA4Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTk5LjIyMzk3LC0xNDAuNjk4NDYpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSJub25lIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtZGFzaGFycmF5PSIiIHN0cm9rZS1kYXNob2Zmc2V0PSIwIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6IG5vcm1hbCI+PHBhdGggZD0iTTI4MC43NzYwMywxODFjMCwyMi4yNTc5MiAtMTguMjU2MDUsNDAuMzAxNTQgLTQwLjc3NjAzLDQwLjMwMTU0Yy0yMi41MTk5OCwwIC00MC43NzYwMywtMTguMDQzNjEgLTQwLjc3NjAzLC00MC4zMDE1NGMwLC0yMi4yNTc5MiAxOC4yNTYwNSwtNDAuMzAxNTQgNDAuNzc2MDMsLTQwLjMwMTU0YzIyLjUxOTk4LDAgNDAuNzc2MDMsMTguMDQzNjEgNDAuNzc2MDMsNDAuMzAxNTR6IiBmaWxsPSIjODA4MDgwIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMjY2LjE2NTgzLDE2Mi4xOTM1NnYyOS4yMDMwMWMwLDIuMjU4MzMgLTEuODMwNTksNC4wODg0MSAtNC4wODg0MSw0LjA4ODQxaC00NC4xNTQ4NWMtMi4yNTgzMywwIC00LjA4ODQxLC0xLjgzMDA3IC00LjA4ODQxLC00LjA4ODQxdi0yOS4yMDMwMWMwLC0yLjI1ODMzIDEuODMwMDcsLTQuMDg4NDEgNC4wODg0MSwtNC4wODg0MWg0NC4xNTQ4NWMyLjI1NzgzLDAgNC4wODg0MSwxLjgzMDA3IDQuMDg4NDEsNC4wODg0MXpNMjYyLjM1NTk1LDE2NC42NDUwOGMwLC0xLjM0MjAyIC0xLjA4ODAzLC0yLjQzMDA1IC0yLjQzMDA1LC0yLjQzMDA1aC0zOS44NTEyOGMtMS4zNDIwMiwwIC0yLjQzMDA1LDEuMDg4MDMgLTIuNDMwMDUsMi40MzAwNXYyNC4yOTk0N2MwLDEuMzQyMDIgMS4wODgwMywyLjQzMDA1IDIuNDMwMDUsMi40MzAwNWg3Ljc3NDYzdi0xMC4yMDU2OWMwLC0xLjM0MjU0IDEuMDg4MDMsLTIuNDMwMDUgMi40MzAwNSwtMi40MzAwNWMxLjM0MjU0LDAgMi40MzAwNSwxLjA4ODAzIDIuNDMwMDUsMi40MzAwNXYxMC4yMDU2OWg0Ljg2MDF2LTE4Ljk1Mzg4YzAsLTEuMzQyMDIgMS4wODgwMywtMi40MzAwNSAyLjQzMDA1LC0yLjQzMDA1YzEuMzQyNTQsMCAyLjQzMDA1LDEuMDg4MDMgMi40MzAwNSwyLjQzMDA1djE4Ljk1Mzg4aDQuODYwMXYtMTQuMDkzNzhjMCwtMS4zNDIwMiAxLjA4ODAzLC0yLjQzMDA1IDIuNDMwMDUsLTIuNDMwMDVjMS4zNDI1NCwwIDIuNDMwMDUsMS4wODgwMyAyLjQzMDA1LDIuNDMwMDV2MTQuMDkzNzhoNy43NzYxNmMxLjM0MjAyLDAgMi40MzAwNSwtMS4wODgwMyAyLjQzMDA1LC0yLjQzMDA1ek0yNTMuMDgyOTIsMjAxLjU1ODgzYzAsMS4yOTA0MSAtMS4wNDYxMiwyLjMzNjAyIC0yLjMzNjAyLDIuMzM2MDJoLTIxLjQ5MzhjLTEuMjg5ODksMCAtMi4zMzYwMiwtMS4wNDU2MSAtMi4zMzYwMiwtMi4zMzYwMmMwLC0xLjI4OTg5IDEuMDQ1NjEsLTIuMzM2MDIgMi4zMzYwMiwtMi4zMzYwMmgyMS40OTM4YzEuMjg5ODksMCAyLjMzNjAyLDEuMDQ2MTMgMi4zMzYwMiwyLjMzNjAyek0yNTAuNzQ2OSwxOTkuMjIyODEiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQwLjc3NjAzMzMzMzMzMzQ6MzkuMzAxNTM5OTk5OTk5OTYtLT4='; diff --git a/extensions/-SIPC-/time.js b/extensions/-SIPC-/time.js index 778f94c0c5..f6ed303f4a 100644 --- a/extensions/-SIPC-/time.js +++ b/extensions/-SIPC-/time.js @@ -1,3 +1,7 @@ +// Name: Time +// Description: Blocks for interacting with unix timestamps and other date strings. +// By: -SIPC- + (function (Scratch) { 'use strict'; const icon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4MS44ODU0IiBoZWlnaHQ9IjgwLjYwMzA4IiB2aWV3Qm94PSIwLDAsODEuODg1NCw4MC42MDMwOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5OS4wNTczLC0xMzkuNjk4NDYpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSJub25lIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtZGFzaGFycmF5PSIiIHN0cm9rZS1kYXNob2Zmc2V0PSIwIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6IG5vcm1hbCI+PHBhdGggZD0iTTI4MC45NDI3LDE4MGMwLDIyLjI1NzkyIC0xOC4zMzA2Nyw0MC4zMDE1NCAtNDAuOTQyNyw0MC4zMDE1NGMtMjIuNjEyMDMsMCAtNDAuOTQyNywtMTguMDQzNjEgLTQwLjk0MjcsLTQwLjMwMTU0YzAsLTIyLjI1NzkyIDE4LjMzMDY3LC00MC4zMDE1NCA0MC45NDI3LC00MC4zMDE1NGMyMi42MTIwMywwIDQwLjk0MjcsMTguMDQzNjEgNDAuOTQyNyw0MC4zMDE1NHoiIGZpbGw9IiNmZjgwMDAiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yNjYuNTM0MzcsMTgwYzAsMTQuNjQxMjkgLTExLjg5MzA4LDI2LjUzNDM3IC0yNi41MzQzNywyNi41MzQzN2MtMTQuNjQxMjksMCAtMjYuNTM0MzcsLTExLjg5MzA4IC0yNi41MzQzNywtMjYuNTM0MzdjMCwtMTQuNjQxMjkgMTEuODkzMDgsLTI2LjUzNDM3IDI2LjUzNDM3LC0yNi41MzQzN2MxNC42NDEyOSwwIDI2LjUzNDM3LDExLjg5MzA4IDI2LjUzNDM3LDI2LjUzNDM3ek0yNTMuMjE5OCwxODUuOTcwMjNsLTExLjMyNDQ5LC02LjUzODgzdi0xNC41OTM5aC0zLjc5MDYydjE3LjA1NzgxaDAuNTIxMjFsMTIuNjk4NTksNy4zNDQzM3oiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQwLjk0MjY5NjA1MzgwMTE0OjQwLjMwMTUzNTI2NTQ4NjcwNi0tPg=='; diff --git a/extensions/0832/rxFS2.js b/extensions/0832/rxFS2.js index 0651762905..5f1a514945 100644 --- a/extensions/0832/rxFS2.js +++ b/extensions/0832/rxFS2.js @@ -1,3 +1,7 @@ +// Name: rxFS +// Description: Blocks for interacting with a virtual in-memory filesystem. +// By: 0832 + /*! * Made by 0832 * This file was originally under the rxLI Version 2.1 license: diff --git a/extensions/Alestore/nfcwarp.js b/extensions/Alestore/nfcwarp.js index c731f04095..1976fe7349 100644 --- a/extensions/Alestore/nfcwarp.js +++ b/extensions/Alestore/nfcwarp.js @@ -1,3 +1,7 @@ +// Name: NFCWarp +// Description: Allows reading data from NFC (NDEF) devices. Only works in Chrome on Android. +// By: Alestore Games + (function(Scratch) { 'use strict'; diff --git a/extensions/CST1229/zip.js b/extensions/CST1229/zip.js index 0ee8cca7d1..d573367947 100644 --- a/extensions/CST1229/zip.js +++ b/extensions/CST1229/zip.js @@ -1,3 +1,7 @@ +// Name: Zip +// Description: Create and edit .zip format files, including .sb3 files. +// By: CST1229 + (function (Scratch) { "use strict"; diff --git a/extensions/CubesterYT/TurboHook.js b/extensions/CubesterYT/TurboHook.js index d3d81cae59..e7995a2f81 100644 --- a/extensions/CubesterYT/TurboHook.js +++ b/extensions/CubesterYT/TurboHook.js @@ -1,3 +1,7 @@ +// Name: TurboHook +// Description: Allows you to use webhooks. +// By: CubesterYT + (function (Scratch) { "use strict"; diff --git a/extensions/DT/cameracontrols.js b/extensions/DT/cameracontrols.js index 960dca6c99..d8bbc94788 100644 --- a/extensions/DT/cameracontrols.js +++ b/extensions/DT/cameracontrols.js @@ -1,3 +1,7 @@ +// Name: Camera Controls +// Description: Move the visible part of the stage. +// By: DT + (Scratch => { 'use strict'; diff --git a/extensions/JeremyGamer13/tween.js b/extensions/JeremyGamer13/tween.js index 5b6fe513e4..0850f41f98 100644 --- a/extensions/JeremyGamer13/tween.js +++ b/extensions/JeremyGamer13/tween.js @@ -1,3 +1,7 @@ +// Name: Tween +// Description: Easing methods for smooth animations. +// By: JeremyGamer13 + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/AllMenus.js b/extensions/Lily/AllMenus.js index b81746d39b..31755ccf58 100644 --- a/extensions/Lily/AllMenus.js +++ b/extensions/Lily/AllMenus.js @@ -1,3 +1,7 @@ +// Name: All Menus +// Description: Special category with every menu from every Scratch category and extensions. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/Cast.js b/extensions/Lily/Cast.js index 5035acae5a..fda432c8b7 100644 --- a/extensions/Lily/Cast.js +++ b/extensions/Lily/Cast.js @@ -1,3 +1,7 @@ +// Name: Cast +// Description: Convert values between types. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/ClonesPlus.js b/extensions/Lily/ClonesPlus.js index f98fb470bf..655fa8e9cc 100644 --- a/extensions/Lily/ClonesPlus.js +++ b/extensions/Lily/ClonesPlus.js @@ -1,3 +1,7 @@ +// Name: Clones Plus +// Description: Expansion of Scratch's clone features. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/CommentBlocks.js b/extensions/Lily/CommentBlocks.js index bd831f0b4f..f94fbf668a 100644 --- a/extensions/Lily/CommentBlocks.js +++ b/extensions/Lily/CommentBlocks.js @@ -1,3 +1,7 @@ +// Name: Comment Blocks +// Description: Annotate your scripts. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/LooksPlus.js b/extensions/Lily/LooksPlus.js index 6c4c193c99..65d3a94e7d 100644 --- a/extensions/Lily/LooksPlus.js +++ b/extensions/Lily/LooksPlus.js @@ -1,3 +1,7 @@ +// Name: Looks Plus +// Description: Expands upon the looks category, allowing you to show/hide, get costume data and edit SVG skins on sprites. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/McUtils.js b/extensions/Lily/McUtils.js index 5303bc39e7..a51f7000b5 100644 --- a/extensions/Lily/McUtils.js +++ b/extensions/Lily/McUtils.js @@ -1,3 +1,7 @@ +// Name: McUtils +// Description: Helpful utilities for any fast food employee. +// By: LilyMakesThings + /*! * Credit to NexusKitten (NamelessCat) for the idea */ diff --git a/extensions/Lily/MoreTimers.js b/extensions/Lily/MoreTimers.js index 6878a4bcde..fad8572c82 100644 --- a/extensions/Lily/MoreTimers.js +++ b/extensions/Lily/MoreTimers.js @@ -1,3 +1,7 @@ +// Name: More Timers +// Description: Control several timers at once. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/Skins.js b/extensions/Lily/Skins.js index 5592ea9109..7449ed2995 100644 --- a/extensions/Lily/Skins.js +++ b/extensions/Lily/Skins.js @@ -1,3 +1,7 @@ +// Name: Skins +// Description: Have your sprites render as other images or costumes. +// By: LilyMakesThings + (function (Scratch) { 'use strict'; diff --git a/extensions/Lily/TempVariables2.js b/extensions/Lily/TempVariables2.js index 13912281f8..959fb6c89b 100644 --- a/extensions/Lily/TempVariables2.js +++ b/extensions/Lily/TempVariables2.js @@ -1,3 +1,7 @@ +// Name: Temporary Variables +// Description: Create disposable runtime or thread variables. +// By: LilyMakesThings + (function(Scratch) { 'use strict'; diff --git a/extensions/Longboost/color_channels.js b/extensions/Longboost/color_channels.js index 71c8aea841..0a3bd925cc 100644 --- a/extensions/Longboost/color_channels.js +++ b/extensions/Longboost/color_channels.js @@ -1,3 +1,6 @@ +// Name: RGB Channels +// Description: Only render or stamp certain RGB channels. + (function(Scratch) { 'use strict'; const renderer = Scratch.vm.renderer; diff --git a/extensions/NOname-awa/graphics2d.js b/extensions/NOname-awa/graphics2d.js index 3eec30f6ed..929c86c41f 100644 --- a/extensions/NOname-awa/graphics2d.js +++ b/extensions/NOname-awa/graphics2d.js @@ -1,3 +1,7 @@ +// Name: Graphics 2D +// Description: Blocks to compute lengths, angles, and areas in two dimensions. +// By: NOname-awa + (function (Scratch) { 'use strict'; Scratch.translate.setup({ diff --git a/extensions/NOname-awa/more-comparisons.js b/extensions/NOname-awa/more-comparisons.js index 38dc0e5aa7..342a3cfc33 100644 --- a/extensions/NOname-awa/more-comparisons.js +++ b/extensions/NOname-awa/more-comparisons.js @@ -1,3 +1,7 @@ +// Name: More Comparisons +// Description: More comparison blocks. +// By: NOname-awa + (function(Scratch) { 'use strict'; const quadrilateral = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3Ny4wMjc4MSIgaGVpZ2h0PSI1NC44MDY1NCIgdmlld0JveD0iMCwwLDc3LjAyNzgxLDU0LjgwNjU0Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAxLjUwNDMsLTE1Mi4yMTk3MykiPjxnIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2lzUGFpbnRpbmdMYXllciZxdW90Ozp0cnVlfSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJub256ZXJvIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMjI4LjE3ODc4LDE1NS40NzM3NGw0Ni40MDEwMywxOS44ODYxNmwtMjIuNTM3NjQsMjkuMTY2MzZoLTQ2LjYyMTk5eiIvPjwvZz48L2c+PC9zdmc+"; diff --git a/extensions/NexusKitten/moremotion.js b/extensions/NexusKitten/moremotion.js index fef57e9f43..0d6e1fe507 100644 --- a/extensions/NexusKitten/moremotion.js +++ b/extensions/NexusKitten/moremotion.js @@ -1,3 +1,7 @@ +// Name: More Motion +// Description: More motion-related blocks. +// By: NamelessCat + (function(Scratch) { 'use strict'; diff --git a/extensions/NexusKitten/sgrab.js b/extensions/NexusKitten/sgrab.js index 6443180b21..594401326c 100644 --- a/extensions/NexusKitten/sgrab.js +++ b/extensions/NexusKitten/sgrab.js @@ -1,3 +1,7 @@ +// Name: S-Grab +// Description: Get information about Scratch projects and Scratch users. +// By: NamelessCat + (function(Scratch) { 'use strict'; diff --git a/extensions/Skyhigh173/bigint.js b/extensions/Skyhigh173/bigint.js index 14f137d6ca..30679902ab 100644 --- a/extensions/Skyhigh173/bigint.js +++ b/extensions/Skyhigh173/bigint.js @@ -1,3 +1,7 @@ +// Name: BigInt +// Description: Math blocks that work on infinitely large integers (no decimals). +// By: Skyhigh173 + (function(Scratch){ 'use strict'; diff --git a/extensions/Skyhigh173/json.js b/extensions/Skyhigh173/json.js index 65496e698d..9ea47b5cd0 100644 --- a/extensions/Skyhigh173/json.js +++ b/extensions/Skyhigh173/json.js @@ -1,3 +1,7 @@ +// Name: JSON +// Description: Handle JSON strings and arrays. +// By: Skyhigh173 + (function(Scratch) { 'use strict'; /* diff --git a/extensions/TheShovel/CanvasEffects.js b/extensions/TheShovel/CanvasEffects.js index ed9c7552e0..572483c3e5 100644 --- a/extensions/TheShovel/CanvasEffects.js +++ b/extensions/TheShovel/CanvasEffects.js @@ -1,3 +1,7 @@ +// Name: Canvas Effects +// Description: Apply visual effects to the entire stage. +// By: TheShovel + (function(Scratch) { 'use strict'; if (!Scratch.extensions.unsandboxed) { diff --git a/extensions/TheShovel/CustomStyles.js b/extensions/TheShovel/CustomStyles.js index 656b6bb29f..979f8c6d7a 100644 --- a/extensions/TheShovel/CustomStyles.js +++ b/extensions/TheShovel/CustomStyles.js @@ -1,3 +1,7 @@ +// Name: Custom Styles +// Description: Customize the appearance of variable monitors and prompts in your project. +// By: TheShovel + // Thanks LilyMakesThings for the awesome banner! (function(Scratch) { 'use strict'; diff --git a/extensions/TheShovel/LZ-String.js b/extensions/TheShovel/LZ-String.js index c69aecb91e..73095e6709 100644 --- a/extensions/TheShovel/LZ-String.js +++ b/extensions/TheShovel/LZ-String.js @@ -1,3 +1,6 @@ +// Name: LZ Compress +// Description: Compress and decompress text using lz-string. + (function(Scratch) { 'use strict'; diff --git a/extensions/TheShovel/ShovelUtils.js b/extensions/TheShovel/ShovelUtils.js index 8533cfdb22..f667a302c9 100644 --- a/extensions/TheShovel/ShovelUtils.js +++ b/extensions/TheShovel/ShovelUtils.js @@ -1,3 +1,7 @@ +// Name: ShovelUtils +// Description: A bunch of miscellaneous blocks. +// By: TheShovel + (function (Scratch) { 'use strict'; if (!Scratch.extensions.unsandboxed) { diff --git a/extensions/Xeltalliv/clippingblending.js b/extensions/Xeltalliv/clippingblending.js index 9eb79bb8e5..e307bbc77a 100644 --- a/extensions/Xeltalliv/clippingblending.js +++ b/extensions/Xeltalliv/clippingblending.js @@ -1,3 +1,7 @@ +// Name: Clipping & Blending +// Description: Clipping outside of a specified rectangular area and additive color blending. +// By: Vadik1 + (function(Scratch) { 'use strict'; diff --git a/extensions/XeroName/Deltatime.js b/extensions/XeroName/Deltatime.js index ce8c487365..3e01ec6473 100644 --- a/extensions/XeroName/Deltatime.js +++ b/extensions/XeroName/Deltatime.js @@ -1,3 +1,7 @@ +// Name: Deltatime +// Description: Precise delta timing blocks. +// By: XeroName + (function (Scratch) { 'use strict'; diff --git a/extensions/ZXMushroom63/searchApi.js b/extensions/ZXMushroom63/searchApi.js index 060096f0a5..cd4274710f 100644 --- a/extensions/ZXMushroom63/searchApi.js +++ b/extensions/ZXMushroom63/searchApi.js @@ -1,3 +1,7 @@ +// Name: Search Params +// Description: Interact with URL search parameters: the part of the URL after a question mark. +// By: ZXMushroom63 + (function (Scratch) { "use strict"; if (!Scratch.extensions.unsandboxed) { diff --git a/extensions/ar.js b/extensions/ar.js index 88d36e132d..597df3757c 100644 --- a/extensions/ar.js +++ b/extensions/ar.js @@ -1,3 +1,7 @@ +// Name: Augmented Reality +// Description: Shows image from camera and performs motion tracking, allowing 3D projects to correctly overlay virtual objects on real world. +// By: Vadik1 + (function(Scratch) { "use strict"; diff --git a/extensions/battery.js b/extensions/battery.js index 4804b7adca..7e491ea656 100644 --- a/extensions/battery.js +++ b/extensions/battery.js @@ -1,3 +1,6 @@ +// Name: Battery +// Description: Access information about the battery of phones or laptops. May not work on all devices and browsers. + (function (Scratch) { 'use strict'; diff --git a/extensions/bitwise.js b/extensions/bitwise.js index 7db593e79f..b9208ed3c0 100644 --- a/extensions/bitwise.js +++ b/extensions/bitwise.js @@ -1,3 +1,7 @@ +// Name: Bitwise +// Description: Blocks that operate on the binary representation of numbers in computers. +// By: TrueFantom + (Scratch => { 'use strict'; diff --git a/extensions/box2d.js b/extensions/box2d.js index 9c2bd1eb63..d554534600 100644 --- a/extensions/box2d.js +++ b/extensions/box2d.js @@ -1,3 +1,7 @@ +// Name: Box2D Physics +// Description: Two dimensional physics. +// Original: griffpatch + /*! * This is based on https://github.com/griffpatch/scratch-vm/tree/box2d/src/extensions/scratch3_griffpatch */ diff --git a/extensions/clipboard.js b/extensions/clipboard.js index 3d59c56336..7169483623 100644 --- a/extensions/clipboard.js +++ b/extensions/clipboard.js @@ -1,3 +1,6 @@ +// Name: Clipboard +// Description: Read and write from the system clipboard. + /*! * Copyright 2023 tomyo-code + AdamMady * diff --git a/extensions/clouddata-ping.js b/extensions/clouddata-ping.js index 0947f40315..9defe28429 100644 --- a/extensions/clouddata-ping.js +++ b/extensions/clouddata-ping.js @@ -1,3 +1,7 @@ +// Name: Ping Cloud Data +// Description: Determine whether a cloud variable server is probably up. +// Original: TheShovel + (function (Scratch) { "use strict"; diff --git a/extensions/cloudlink.js b/extensions/cloudlink.js index 618b1ae0bf..5db7711f5e 100644 --- a/extensions/cloudlink.js +++ b/extensions/cloudlink.js @@ -1,3 +1,7 @@ +// Name: Cloudlink +// Description: Powerful WebSocket extension for Scratch 3. +// By: MikeDEV + // Copy of S4-0_nosuite.js as of 10/31/2022 /* eslint-disable */ diff --git a/extensions/cs2627883/numericalencoding.js b/extensions/cs2627883/numericalencoding.js index 0f23332264..c3204b2bb8 100644 --- a/extensions/cs2627883/numericalencoding.js +++ b/extensions/cs2627883/numericalencoding.js @@ -1,3 +1,7 @@ +// Name: Numerical Encoding +// Description: Encode strings as numbers for cloud variables. +// By: cs2627883 + // https://github.com/CS2627883/Turbowarp-Encoding-Extension/blob/main/Encoding.js (function(Scratch) { diff --git a/extensions/cursor.js b/extensions/cursor.js index 4b9420e9f8..9c011998b3 100644 --- a/extensions/cursor.js +++ b/extensions/cursor.js @@ -1,3 +1,6 @@ +// Name: Mouse Cursor +// Description: Use custom cursors or hide the cursor. Also allows replacing the cursor with any costume image. + (function (Scratch) { 'use strict'; diff --git a/extensions/encoding.js b/extensions/encoding.js index 9613e965c7..d2ad7bc1a1 100644 --- a/extensions/encoding.js +++ b/extensions/encoding.js @@ -1,3 +1,7 @@ +// Name: Encoding +// Description: Encode and decode strings into their unicode numbers, base 64, or URLs. +// By: -SIPC- + (function (Scratch) { 'use strict'; const icon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzcuNzk1MDYiIGhlaWdodD0iMTM0LjIzNzA3IiB2aWV3Qm94PSIwLDAsMTM3Ljc5NTA2LDEzNC4yMzcwNyI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE1Mi44OTU4NiwtMTMwLjM3OTg5KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI2ZmZmZmZiIgc3Ryb2tlLXdpZHRoPSIyMCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0xOTkuMzA5MDgsMjE5LjYyMDExdi03OS4yNDAyMmg4MS4zODE4NHY3OS4yNDAyMnoiLz48cGF0aCBkPSJNMTYyLjg5NTg2LDI1NC42MTY5NnYtNzkuMjQwMjJoODEuMzgxODR2NzkuMjQwMjJ6Ii8+PC9nPjwvZz48L3N2Zz48IS0tcm90YXRpb25DZW50ZXI6ODcuMTA0MTQwMTg0NTE2NDQ6NDkuNjIwMTA4MzQwNzA3OTYtLT4='; diff --git a/extensions/extensions.json b/extensions/extensions.json new file mode 100644 index 0000000000..7ec0ffa91d --- /dev/null +++ b/extensions/extensions.json @@ -0,0 +1,72 @@ +[ + "lab/text", + "stretch", + "gamepad", + "box2d", + "files", + "pointerlock", + "cursor", + "runtime-options", + "fetch", + "text", + "local-storage", + "true-fantom/base", + "bitwise", + "Skyhigh173/bigint", + "utilities", + "sound", + "Xeltalliv/clippingblending", + "clipboard", + "penplus", + "Lily/Skins", + "obviousAlexC/SensingPlus", + "Lily/ClonesPlus", + "Lily/LooksPlus", + "NexusKitten/moremotion", + "navigator", + "battery", + "TheShovel/CustomStyles", + "mdwalters/notifications", + "XeroName/Deltatime", + "ar", + "encoding", + "Lily/TempVariables2", + "Lily/MoreTimers", + "clouddata-ping", + "cloudlink", + "true-fantom/network", + "true-fantom/math", + "true-fantom/regexp", + "true-fantom/couplers", + "Lily/AllMenus", + "Lily/Cast", + "-SIPC-/time", + "-SIPC-/consoles", + "ZXMushroom63/searchApi", + "TheShovel/ShovelUtils", + "Skyhigh173/json", + "cs2627883/numericalencoding", + "DT/cameracontrols", + "TheShovel/CanvasEffects", + "Longboost/color_channels", + "CST1229/zip", + "TheShovel/LZ-String", + "0832/rxFS2", + "NexusKitten/sgrab", + "NOname-awa/graphics2d", + "NOname-awa/more-comparisons", + "JeremyGamer13/tween", + "rixxyx", + "qxsck/data-analysis", + "qxsck/var-and-list", + "vercte/dictionaries", + "godslayerakp/http", + "Lily/CommentBlocks", + "veggiecan/LongmanDictionary", + "CubesterYT/TurboHook", + "Alestore/nfcwarp", + "itchio", + "gamejolt", + "obviousAlexC/newgroundsIO", + "Lily/McUtils" +] \ No newline at end of file diff --git a/extensions/fetch.js b/extensions/fetch.js index 0340ad3aec..04646a942e 100644 --- a/extensions/fetch.js +++ b/extensions/fetch.js @@ -1,3 +1,6 @@ +// Name: Fetch +// Description: Make requests to the broader internet. + (function(Scratch) { 'use strict'; diff --git a/extensions/files.js b/extensions/files.js index 2d1cea7860..e381f6637e 100644 --- a/extensions/files.js +++ b/extensions/files.js @@ -1,3 +1,6 @@ +// Name: Files +// Description: Read and download files. + (function(Scratch) { 'use strict'; diff --git a/extensions/gamejolt.js b/extensions/gamejolt.js index 0cdc6a8541..ca115ef80e 100644 --- a/extensions/gamejolt.js +++ b/extensions/gamejolt.js @@ -1,3 +1,7 @@ +// Name: GameJolt +// Description: Blocks that allow games to interact with the GameJolt API. Unofficial. +// By: softed + (Scratch => { 'use strict'; diff --git a/extensions/gamepad.js b/extensions/gamepad.js index c476387163..a2d8a3d343 100644 --- a/extensions/gamepad.js +++ b/extensions/gamepad.js @@ -1,3 +1,6 @@ +// Name: Gamepad +// Description: Directly access gamepads instead of just mapping buttons to keys. + // Some parts of this scripts are based on or designed to be compatible-ish with: // https://arpruss.github.io/gamepad.js (MIT Licensed) diff --git a/extensions/godslayerakp/http.js b/extensions/godslayerakp/http.js index 107b01bd62..3dd8f9c1f2 100644 --- a/extensions/godslayerakp/http.js +++ b/extensions/godslayerakp/http.js @@ -1,3 +1,7 @@ +// Name: HTTP +// Description: Comprehensive extension for interacting with external websites. +// By: RedMan13 + (function(Scratch) { 'use strict'; if (!Scratch.extensions.unsandboxed) throw new Error('can not load out side unsandboxed mode'); diff --git a/extensions/itchio.js b/extensions/itchio.js index be296c56bb..38b20b13be 100644 --- a/extensions/itchio.js +++ b/extensions/itchio.js @@ -1,3 +1,7 @@ +// Name: itch.io +// Description: Blocks that interact with the itch.io website. Unofficial. +// By: softed + (Scratch => { 'use strict'; diff --git a/extensions/lab/text.js b/extensions/lab/text.js index 799ae78bdb..d20687b423 100644 --- a/extensions/lab/text.js +++ b/extensions/lab/text.js @@ -1,3 +1,6 @@ +// Name: Animated Text +// Description: An easy way to display and animate text. Compatible with Scratch Lab's Animated Text experiment. + (function(Scratch) { 'use strict'; diff --git a/extensions/local-storage.js b/extensions/local-storage.js index 563d12a7ee..232d0c6c1a 100644 --- a/extensions/local-storage.js +++ b/extensions/local-storage.js @@ -1,3 +1,6 @@ +// Name: Local Storage +// Description: Store data persistently. Like cookies, but better. + (function (Scratch) { 'use strict'; diff --git a/extensions/mdwalters/notifications.js b/extensions/mdwalters/notifications.js index 9e41d5bd03..4e15f31299 100644 --- a/extensions/mdwalters/notifications.js +++ b/extensions/mdwalters/notifications.js @@ -1,3 +1,6 @@ +// Name: Notifications +// Description: Display notifications. + (function(Scratch) { 'use strict'; diff --git a/extensions/navigator.js b/extensions/navigator.js index bbb615e75d..1a2c289a3b 100644 --- a/extensions/navigator.js +++ b/extensions/navigator.js @@ -1,3 +1,6 @@ +// Name: Navigator +// Description: Details about the user's browser and operating system. + (function(Scratch) { 'use strict'; diff --git a/extensions/obviousAlexC/SensingPlus.js b/extensions/obviousAlexC/SensingPlus.js index f3559037f1..0bd800d369 100644 --- a/extensions/obviousAlexC/SensingPlus.js +++ b/extensions/obviousAlexC/SensingPlus.js @@ -1,3 +1,7 @@ +// Name: Sensing Plus +// Description: An extension to the sensing category. +// By: ObviousAlexC + (function (Scratch) { "use strict"; diff --git a/extensions/obviousAlexC/newgroundsIO.js b/extensions/obviousAlexC/newgroundsIO.js index e14fa5b1e7..f25c705a3d 100644 --- a/extensions/obviousAlexC/newgroundsIO.js +++ b/extensions/obviousAlexC/newgroundsIO.js @@ -1,3 +1,7 @@ +// Name: Newgrounds +// Description: Blocks that allow games to interact with the Newgrounds API. Unofficial. +// By: ObviousAlexC + (function (Scratch) { "use strict"; diff --git a/extensions/penplus.js b/extensions/penplus.js index 3f5f54e0b4..2537dc97cc 100644 --- a/extensions/penplus.js +++ b/extensions/penplus.js @@ -1,3 +1,7 @@ +// Name: Pen Plus +// Description: Advanced rendering capabilities. +// By: ObviousAlexC + /* eslint-disable no-empty-pattern */ /* eslint-disable no-prototype-builtins */ /* diff --git a/extensions/pointerlock.js b/extensions/pointerlock.js index 967c5084cc..e41c7f27af 100644 --- a/extensions/pointerlock.js +++ b/extensions/pointerlock.js @@ -1,3 +1,6 @@ +// Name: Pointerlock +// Description: Adds blocks for mouse locking. Mouse x & y blocks will report the change since the previous frame while the pointer is locked. Replaces the pointerlock experiment. + (function(Scratch) { 'use strict'; diff --git a/extensions/qxsck/data-analysis.js b/extensions/qxsck/data-analysis.js index 1afbece9bc..3bf8adf6c5 100644 --- a/extensions/qxsck/data-analysis.js +++ b/extensions/qxsck/data-analysis.js @@ -1,3 +1,7 @@ +// Name: Data Analysis +// Description: Blocks to compute means, medians, maximums, minimums, variances, and modes. +// By: qxsck + (function(Scratch) { 'use strict'; Scratch.translate.setup({ diff --git a/extensions/qxsck/var-and-list.js b/extensions/qxsck/var-and-list.js index 83ef8aa0cd..faf39bf90b 100644 --- a/extensions/qxsck/var-and-list.js +++ b/extensions/qxsck/var-and-list.js @@ -1,3 +1,7 @@ +// Name: Variable and list +// Description: More blocks related to variables and lists. +// By: qxsck + (function(Scratch) { 'use strict'; Scratch.translate.setup({ diff --git a/extensions/rixxyx.js b/extensions/rixxyx.js index 394076d43e..deef646546 100644 --- a/extensions/rixxyx.js +++ b/extensions/rixxyx.js @@ -1,3 +1,7 @@ +// Name: RixxyX +// Description: Various utility blocks. +// By: RixTheTyrunt + /*! * Originally created by https://scratch.mit.edu/users/RixTheTyrunt/ * This file is available under an informal "use with credit" license. diff --git a/extensions/runtime-options.js b/extensions/runtime-options.js index 5d4df75b22..89d0652988 100644 --- a/extensions/runtime-options.js +++ b/extensions/runtime-options.js @@ -1,3 +1,6 @@ +// Name: Runtime Options +// Description: Get and modify turbo mode, framerate, interpolation, clone limit, stage size, and more. + (function (Scratch) { 'use strict'; diff --git a/extensions/sound.js b/extensions/sound.js index 57228fc0b5..e86bc6804c 100644 --- a/extensions/sound.js +++ b/extensions/sound.js @@ -1,3 +1,6 @@ +// Name: Sound +// Description: Play sounds from URLs. + (Scratch => { 'use strict'; diff --git a/extensions/stretch.js b/extensions/stretch.js index 9bb4dd6e81..7597880bb9 100644 --- a/extensions/stretch.js +++ b/extensions/stretch.js @@ -1,3 +1,6 @@ +// Name: Stretch +// Description: Stretch sprites horizontally or vertically. + (function (Scratch) { 'use strict'; diff --git a/extensions/text.js b/extensions/text.js index beed9dcc82..488a9fb1a3 100644 --- a/extensions/text.js +++ b/extensions/text.js @@ -1,6 +1,6 @@ - -// Made by CST1229 -// Modified port of an extension from a mod I worked on. +// Name: Text +// Description: Manipulate characters and text. +// Original: CST1229 (function(Scratch) { "use strict"; diff --git a/extensions/true-fantom/base.js b/extensions/true-fantom/base.js index 8eb6297bf1..42b95bd840 100644 --- a/extensions/true-fantom/base.js +++ b/extensions/true-fantom/base.js @@ -1,3 +1,7 @@ +// Name: Base +// Description: Convert numbers between bases. +// By: TrueFantom + (Scratch => { 'use strict'; diff --git a/extensions/true-fantom/couplers.js b/extensions/true-fantom/couplers.js index bf2438ef8c..0862319533 100644 --- a/extensions/true-fantom/couplers.js +++ b/extensions/true-fantom/couplers.js @@ -1,3 +1,7 @@ +// Name: Couplers +// Description: A few adapter blocks. +// By: TrueFantom + (Scratch => { 'use strict'; diff --git a/extensions/true-fantom/math.js b/extensions/true-fantom/math.js index 2c3db8675e..8047238bd0 100644 --- a/extensions/true-fantom/math.js +++ b/extensions/true-fantom/math.js @@ -1,3 +1,7 @@ +// Name: Math +// Description: A lot of operators blocks, from exponentiation to trigonometric functions. +// By: TrueFantom + (Scratch => { 'use strict'; diff --git a/extensions/true-fantom/network.js b/extensions/true-fantom/network.js index 510e3027dd..0654c8a43f 100644 --- a/extensions/true-fantom/network.js +++ b/extensions/true-fantom/network.js @@ -1,3 +1,7 @@ +// Name: Network +// Description: Various blocks for interacting with the network. +// By: TrueFantom + (Scratch => { 'use strict'; diff --git a/extensions/true-fantom/regexp.js b/extensions/true-fantom/regexp.js index 0b6c2bfe35..104a9d48e3 100644 --- a/extensions/true-fantom/regexp.js +++ b/extensions/true-fantom/regexp.js @@ -1,3 +1,7 @@ +// Name: RegExp +// Description: Full interface for working with Regular Expressions. +// By: TrueFantom + (Scratch => { 'use strict'; diff --git a/extensions/utilities.js b/extensions/utilities.js index ea2c9ae6a7..f453b11cf9 100644 --- a/extensions/utilities.js +++ b/extensions/utilities.js @@ -1,3 +1,7 @@ +// Name: Utilities +// Description: A bunch of interesting blocks. +// Original: Sheep_maker + /*! * This is based on: * https://github.com/SheepTester/sheeptester.github.io/blob/master/javascripts/utilities.js diff --git a/extensions/veggiecan/LongmanDictionary.js b/extensions/veggiecan/LongmanDictionary.js index ad03884d34..aad9ddffd7 100644 --- a/extensions/veggiecan/LongmanDictionary.js +++ b/extensions/veggiecan/LongmanDictionary.js @@ -1,4 +1,7 @@ -//Created by veggiecan0419 +// Name: Longman Dictionary +// Description: Get the definitions of words from the Longman Dictionary in your projects. +// By: veggiecan0419 + (function(Scratch) { 'use strict'; diff --git a/extensions/vercte/dictionaries.js b/extensions/vercte/dictionaries.js index 87915135b5..da9434b38d 100644 --- a/extensions/vercte/dictionaries.js +++ b/extensions/vercte/dictionaries.js @@ -1,3 +1,7 @@ +// Name: Dictionaries +// Description: Use the power of dictionaries in your project. +// By: Vercte + (function(Scratch) { 'use strict'; let dictionaries = new Map(); diff --git a/website/index.ejs b/website/index.ejs deleted file mode 100644 index 4e7f852871..0000000000 --- a/website/index.ejs +++ /dev/null @@ -1,810 +0,0 @@ - - - - - - TurboWarp Extension Gallery - - - - - - -
-

- -
TurboWarp Extension Gallery
-

- -

Unlike custom extensions on other websites, these aren't limited by the extension sandbox, so they are a lot more powerful. All extensions are reviewed for safety.

-

- <% if (mode === 'desktop') { %> - To use these extensions in TurboWarp Desktop, hover over the extension and press the add button. - <% } else { %> - To use multiple of these extensions in TurboWarp, hover over the extension and press the button to copy its URL. Then go to the editor, open the extension chooser, then choose the "Custom Extension" option at the bottom, and enter the URL. - <% } %> -

- -
-
These extensions are not compatible with Scratch.
- Projects that use these extensions can't be uploaded to the Scratch website. - They can, however, be used in the packager. -
- -
- <% if (mode === 'desktop') { %> -
Some extensions may be outdated or missing.
- <% - const now = new Date(); - const date = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}`; - %> - For compatibility, security, and offline support, TurboWarp Desktop includes an offline copy of extensions.turbowarp.org from this update's release date (<%= date %>). - Compared to the live website, some extensions may be missing or outdated. - <% } else { %> -
Some extensions may not work in TurboWarp Desktop.
- For compatibility, security, and offline support, each TurboWarp Desktop update contains an offline copy of these extensions from its release date, so some extensions may be outdated or missing. - Use the latest update for best results. - <% } %> -
-
- - <% - const getLinkToRun = (extensionPath) => `https://turbowarp.org/editor?extension=${host}${extensionPath}`; - %> - - <% if (mode === "development") { %> -
-
-

Development Server Tools

-

- Most recently modified extensions: - <% for (const extension of mostRecentExtensions) { %> - <%= extension %> - <% } %> -

-
-
- <% } %> - - - - <% if (mode === 'desktop') { %> - - <% } %> - - <% - const banner = (extensionFile, options = {}) => { - if (extensionFile.endsWith('.js')) { - return `Do not add .js when calling banner(): ${extensionFile}`; - } - const imageSource = extensionImages[extensionFile] ? `images/${extensionImages[extensionFile]}` : 'images/unknown.svg'; - const imageClasses = ["extension-image"]; - if (options.invertDark) imageClasses.push("invert-dark"); - return ` -
- -
- - ${mode === "desktop" ? (` - - `) : (` - Open Extension - `)} -
-
` - }; - - const img = (extensionFile) => { - if (extensionImages[extensionFile]) return `images/${extensionImages[extensionFile]}`; - return 'images/unknown.svg'; - }; - %> - -
-
-
- <%- banner('lab/text') %> -

Animated Text

-

An easy way to display and animate text. Compatible with Scratch Lab's Animated Text experiment.

-
- -
- <%- banner('stretch') %> -

Stretch

-

Stretch sprites horizontally or vertically.

-
- -
- <%- banner('gamepad') %> -

Gamepad

-

Directly access gamepads instead of just mapping buttons to keys.

-
- -
- <%- banner('box2d') %> -

Box2D Physics

-

Two dimensional physics. Originally created by griffpatch.

-
- -
- <%- banner('files') %> -

Files

-

Read and download files.

-
- -
- <%- banner('pointerlock') %> -

Pointerlock

-

Adds blocks for mouse locking. Mouse x & y blocks will report the change since the previous frame while the pointer is locked. Replaces the pointerlock experiment.

-
- -
- <%- banner('cursor') %> -

Mouse Cursor

-

Use custom cursors or hide the cursor. Also allows replacing the cursor with any costume image.

-
- -
- <%- banner('runtime-options') %> -

Runtime Options

-

Get and modify turbo mode, framerate, interpolation, clone limit, stage size, and more.

-
- -
- <%- banner('fetch') %> -

Fetch

-

Make requests to the broader internet.

-
- -
- <%- banner('text') %> -

Text

-

Manipulate characters and text. Originally created by CST1229.

-
- -
- <%- banner('local-storage') %> -

Local Storage

-

Store data persistently. Like cookies, but better.

-
- -
- <%- banner('true-fantom/base') %> -

Base

-

Convert numbers between bases. Created by TrueFantom.

-
- -
- <%- banner('bitwise') %> -

Bitwise

-

Blocks that operate on the binary representation of numbers in computers. Modified by TrueFantom.

-
- -
- <%- banner('Skyhigh173/bigint') %> -

BigInt

-

Math blocks that work on infinitely large integers (no decimals). Created by Skyhigh173.

-
- -
- <%- banner('utilities') %> -

Utilities

-

A bunch of interesting blocks. Originally created by Sheep_maker.

-
- -
- <%- banner('sound') %> -

Sound

-

Play sounds from URLs.

-
- -
- <%- banner('Xeltalliv/clippingblending') %> -

Clipping & Blending

-

Clipping outside of a specified rectangular area and additive color blending. Created by Vadik1.

-
- -
- <%- banner('clipboard') %> -

Clipboard

-

Read and write from the system clipboard.

-
- -
- <%- banner('penplus') %> -

Pen Plus

-

Advanced rendering capabilities. Created by ObviousAlexC.

-
- -
- <%- banner('Lily/Skins') %> -

Skins

-

Have your sprites render as other images or costumes. Created by LilyMakesThings.

-
- -
- <%- banner('obviousAlexC/SensingPlus') %> -

Sensing Plus

-

An extension to the sensing category. Created by ObviousAlexC.

-
- -
- <%- banner('Lily/ClonesPlus') %> -

Clones Plus

-

Expansion of Scratch's clone features. Created by LilyMakesThings.

-
- -
- <%- banner('Lily/LooksPlus') %> -

Looks Plus

-

Expands upon the looks category, allowing you to show/hide, get costume data and edit SVG skins on sprites. Created by LilyMakesThings.

-
- -
- <%- banner('NexusKitten/moremotion') %> -

More Motion

-

More motion-related blocks. Created by NamelessCat.

-
- -
- <%- banner('navigator') %> -

Navigator

-

Details about the user's browser and operating system.

-
- -
- <%- banner('battery') %> -

Battery

-

Access information about the battery of phones or laptops. May not work on all devices and browsers.

-
- -
- <%- banner('TheShovel/CustomStyles') %> -

Custom Styles

-

Customize the appearance of variable monitors and prompts in your project. Created by TheShovel.

-
- -
- <%- banner('mdwalters/notifications') %> -

Notifications

-

Display notifications.

-
- -
- <%- banner('XeroName/Deltatime') %> -

Deltatime

-

Precise delta timing blocks. Created by XeroName.

-
- -
- <%- banner('ar') %> -

Augmented Reality

-

Shows image from camera and performs motion tracking, allowing 3D projects to correctly overlay virtual objects on real world. Created by Vadik1.

-
- -
- <%- banner('encoding') %> -

Encoding

-

Encode and decode strings into their unicode numbers, base 64, or URLs. Created by -SIPC-.

-
- -
- <%- banner('Lily/TempVariables2') %> -

Temporary Variables

-

Create disposable runtime or thread variables. Created by LilyMakesThings.

-
- -
- <%- banner('Lily/MoreTimers') %> -

More Timers

-

Control several timers at once. Created by LilyMakesThings.

-
- -
- <%- banner('clouddata-ping') %> -

Ping Cloud Data

-

Determine whether a cloud variable server is probably up. Originally created by TheShovel.

-
- -
- <%- banner('cloudlink') %> -

Cloudlink

-

Powerful WebSocket extension for Scratch 3. Created by MikeDEV.

-
- -
- <%- banner('true-fantom/network') %> -

Network

-

Various blocks for interacting with the network. Created by TrueFantom.

-
- -
- <%- banner('true-fantom/math') %> -

Math

-

A lot of operators blocks, from exponentiation to trigonometric functions. Created by TrueFantom.

-
- -
- <%- banner('true-fantom/regexp') %> -

RegExp

-

Full interface for working with Regular Expressions. Created by TrueFantom.

-
- -
- <%- banner('true-fantom/couplers') %> -

Couplers

-

A few adapter blocks. Created by TrueFantom.

-
- -
- <%- banner('Lily/AllMenus') %> -

All Menus

-

Special category with every menu from every Scratch category and extensions. Created by LilyMakesThings

-
- -
- <%- banner('Lily/Cast') %> -

Cast

-

Convert values between types. Created by LilyMakesThings

-
- -
- <%- banner('-SIPC-/time') %> -

Time

-

Blocks for interacting with unix timestamps and other date strings. Created by -SIPC-.

-
- -
- <%- banner('-SIPC-/consoles') %> -

Consoles

-

Blocks that interact the JavaScript console built in to your browser's developer tools. Created by -SIPC-.

-
- -
- <%- banner('ZXMushroom63/searchApi') %> -

Search Params

-

Interact with URL search parameters: the part of the URL after a question mark. Created by ZXMushroom63.

-
- -
- <%- banner('TheShovel/ShovelUtils') %> -

ShovelUtils

-

A bunch of miscellaneous blocks. Created by TheShovel.

-
- -
- <%- banner('Skyhigh173/json') %> -

JSON

-

Handle JSON strings and arrays. Created by Skyhigh173.

-
- -
- <%- banner('cs2627883/numericalencoding') %> -

Numerical Encoding

-

Encode strings as numbers for cloud variables. Created by cs2627883.

-
- -
- <%- banner('DT/cameracontrols') %> -

Camera Controls

-

Move the visible part of the stage. Created by DT.

-
- -
- <%- banner('TheShovel/CanvasEffects') %> -

Canvas Effects

-

Apply visual effects to the entire stage. Created by TheShovel.

-
- -
- <%- banner('Longboost/color_channels') %> -

RGB Channels

-

Only render or stamp certain RGB channels.

-
- -
- <%- banner('CST1229/zip') %> -

Zip

-

Create and edit .zip format files, including .sb3 files. Created by CST1229.

-
- -
- <%- banner('TheShovel/LZ-String') %> -

LZ Compress

-

Compress and decompress text using lz-string.

-
- -
- <%- banner('0832/rxFS2') %> -

rxFS

-

Blocks for interacting with a virtual in-memory filesystem. Created by 0832.

-
- -
- <%- banner('NexusKitten/sgrab') %> -

S-Grab

-

Get information about Scratch projects and Scratch users. Created by NamelessCat.

-
- -
- <%- banner('NOname-awa/graphics2d') %> -

Graphics 2D

-

Blocks to compute lengths, angles, and areas in two dimensions. Created by NOname-awa.

-
- -
- <%- banner('NOname-awa/more-comparisons') %> -

More Comparisons

-

More comparison blocks. Created by NOname-awa.

-
- -
- <%- banner('JeremyGamer13/tween') %> -

Tween

-

Easing methods for smooth animations. Created by JeremyGamer13

-
- -
- <%- banner('rixxyx') %> -

RixxyX

-

Various utility blocks. Created by RixTheTyrunt.

-
- -
- <%- banner('qxsck/data-analysis') %> -

Data Analysis

-

Blocks to compute means, medians, maximums, minimums, variances, and modes. Created by qxsck.

-
- -
- <%- banner('qxsck/var-and-list') %> -

Variable and list

-

More blocks related to variables and lists. Created by qxsck.

-
- -
- <%- banner('vercte/dictionaries') %> -

Dictionaries

-

Use the power of dictionaries in your project. Created by Vercte.

-
- -
- <%- banner('godslayerakp/http') %> -

HTTP

-

Comprehensive extension for interacting with external websites. Created by RedMan13.

-
- -
- <%- banner('Lily/CommentBlocks') %> -

Comment Blocks

-

Annotate your scripts. Created by LilyMakesThings.

-
- -
- <%- banner('veggiecan/LongmanDictionary') %> -

Longman Dictionary

-

Get the definitions of words from the Longman Dictionary in your projects. Created by veggiecan0419

-
- -
- <%- banner('CubesterYT/TurboHook') %> -

TurboHook

-

Allows you to use webhooks. Created by CubesterYT.

-
- -
- <%- banner('Alestore/nfcwarp') %> -

NFCWarp

-

Allows reading data from NFC (NDEF) devices. Only works in Chrome on Android. Created by Alestore Games.

-
- -
- <%- banner('itchio') %> -

itch.io

-

Blocks that interact with the itch.io website. Unofficial. Created by softed.

-
- -
- <%- banner('gamejolt') %> -

GameJolt

-

Blocks that allow games to interact with the GameJolt API. Unofficial. Created by softed.

-
- -
- <%- banner('obviousAlexC/newgroundsIO') %> -

Newgrounds

-

Blocks that allow games to interact with the Newgrounds API. Unofficial. Created by ObviousAlexC.

-
- -
- <%- banner('Lily/McUtils') %> -

McUtils

-

Helpful utilities for any fast food employee. Created by LilyMakesThings.

-
-
-
- - - -