Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Sprite Effects (More Sprite AND Canvas Effects) #1184

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e810b77
Create Sprite-Effects.js
SharkPool-SP Dec 6, 2023
90aa50d
Update Sprite-Effects.js
SharkPool-SP Dec 6, 2023
0230643
Update Sprite-Effects.js
SharkPool-SP Dec 6, 2023
04135c8
Update Sprite-Effects.js
SharkPool-SP Dec 6, 2023
8a5d411
Create Sprite-Effects.svg
SharkPool-SP Dec 6, 2023
fef91f6
Update Sprite-Effects.svg
SharkPool-SP Dec 6, 2023
68e8ba0
Update Sprite-Effects.svg
SharkPool-SP Dec 6, 2023
6cdf6cd
Update Sprite-Effects.js
SharkPool-SP Dec 8, 2023
6fda92d
Update Sprite-Effects.js
SharkPool-SP Dec 8, 2023
cab3297
Update Sprite-Effects.js
SharkPool-SP Dec 12, 2023
7801c66
Update Sprite-Effects.svg
SharkPool-SP Dec 12, 2023
cf2db53
Update Sprite-Effects.js
SharkPool-SP Jan 10, 2024
0539885
Update Sprite-Effects.js
SharkPool-SP Jan 30, 2024
b651f65
Update Sprite-Effects.js
SharkPool-SP Feb 19, 2024
57b0ecf
Update Sprite-Effects.js
SharkPool-SP Feb 19, 2024
af9308f
Update Sprite-Effects.js
SharkPool-SP Feb 20, 2024
7406e21
Update Sprite-Effects.js
SharkPool-SP Mar 17, 2024
16e6bd4
Update Sprite-Effects.js
SharkPool-SP Mar 19, 2024
27efda6
Update Sprite-Effects.js
SharkPool-SP Mar 19, 2024
96afcec
Update Sprite-Effects.js
SharkPool-SP Mar 20, 2024
093c1e4
dont auto load skins
SharkPool-SP Mar 20, 2024
0622006
Update Sprite-Effects.js
SharkPool-SP Mar 23, 2024
53b84cf
Update Sprite-Effects.js
SharkPool-SP Apr 6, 2024
10387dc
Update Sprite-Effects.js
SharkPool-SP May 15, 2024
9b31545
Update Sprite-Effects.js
SharkPool-SP May 15, 2024
2f3209a
Sprite-Effects -- Remove Paper Data
SharkPool-SP Jul 13, 2024
0cb525c
Sprite-Effects -- V1.7.0
SharkPool-SP Aug 16, 2024
cf3579f
Sprite-Effects -- fix a silly wittle buggie wuggie
SharkPool-SP Aug 22, 2024
215d8c3
Sprite-Effects -- Simplify & Better Canvas Filter Handling
SharkPool-SP Oct 2, 2024
5f1b880
run workflows plz
SharkPool-SP Oct 2, 2024
a0c7aee
Sprite-Effects -- Better Filter Applier
SharkPool-SP Oct 3, 2024
b751516
Sprite-Effects -- Mega Bug Fix Update
SharkPool-SP Nov 1, 2024
7e119ab
forgot abt this one thing
SharkPool-SP Nov 1, 2024
15cfda7
Sprite-Effects -- Rewrite and Fix
SharkPool-SP Nov 24, 2024
d968b02
shut
SharkPool-SP Nov 24, 2024
76de295
Sprite-Effects -- Allow Alpha Channel for Outlines
SharkPool-SP Dec 1, 2024
4ec00f6
Update Sprite-Effects.js
SharkPool-SP Dec 1, 2024
af63f19
Sprite-Effects -- Fix Skew Issue
SharkPool-SP Jan 12, 2025
058eb3d
Sprite-Effects -- tutorial button
SharkPool-SP Feb 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update Sprite-Effects.js
  • Loading branch information
SharkPool-SP authored Apr 6, 2024
commit 53b84cf03fc569857daf25805ccbb09ae1ae489e
122 changes: 105 additions & 17 deletions extensions/SharkPool/Sprite-Effects.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
// Description: Apply New Non-Vanilla Effects to Sprites and the Canvas!
// By: SharkPool

// Version V.1.5.0
// Version V.1.6.0

(function (Scratch) {
"use strict";
@@ -295,6 +295,28 @@
Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }
},
},
{
opcode: "ditherSprite",
blockType: Scratch.BlockType.REPORTER,
text: "apply dither effect to [SPRITE] width [W] height [H]",
hideFromPalette: !sprite,
arguments: {
SPRITE: { type: Scratch.ArgumentType.STRING, menu: "TARGETS" },
W: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 },
H: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }
},
},
{
opcode: "ditherImage",
blockType: Scratch.BlockType.REPORTER,
text: "apply dither effect to [SPRITE] width [W] height [H]",
hideFromPalette: sprite,
arguments: {
SPRITE: { type: Scratch.ArgumentType.STRING, defaultValue: "data URI or <svg content>" },
W: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 },
H: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }
},
},
"---",
{
opcode: "distortSprite",
@@ -357,6 +379,30 @@
},
},
{ blockType: Scratch.BlockType.LABEL, text: "Formatting" },
{
opcode: "patternSprite",
blockType: Scratch.BlockType.REPORTER,
text: "replace [COLOR] with pattern [PAT] scale [SIZE] in [SPRITE]",
hideFromPalette: !sprite,
arguments: {
PAT: { type: Scratch.ArgumentType.STRING, defaultValue: "data URI or <svg content>" },
SPRITE: { type: Scratch.ArgumentType.STRING, menu: "TARGETS" },
SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 },
COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" }
},
},
{
opcode: "patternImage",
blockType: Scratch.BlockType.REPORTER,
text: "replace [COLOR] with pattern [PAT] scale [SIZE] in [SPRITE]",
hideFromPalette: sprite,
arguments: {
PAT: { type: Scratch.ArgumentType.STRING, defaultValue: "data URI or <svg content>" },
SPRITE: { type: Scratch.ArgumentType.STRING, defaultValue: "data URI or <svg content>" },
SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 },
COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" }
},
},
{
opcode: "outlineSprite",
blockType: Scratch.BlockType.REPORTER,
@@ -706,7 +752,7 @@

sourceSwitch() { sprite = sprite ? false : true, Scratch.vm.extensionManager.refreshBlocks() }
filterWarn() {
alert(`Unfortunately, due to various limitations, not ALL effects (especially the Formatting Blocks) will work on the Canvas...
alert(`Unfortunately, due to various limitations, not ALL effects (like some Formatting Blocks) will work on the Canvas...
\nYou are welcome to experiment by making your own svg filters and using them on the canvas!`);
}

@@ -719,7 +765,6 @@

setSpriteEffect(args, util) { return this.setMainEffect(args, false, util) }
async setImageEffect(args) { return await this.setMainEffect(args, true) }

applyCustomSprite(args, util) { return this.customFilter(args, false, util) }
async applyCustomImage(args) { return await this.customFilter(args, true) }

@@ -728,26 +773,18 @@

setSpriteBlend(args, util) { return this.blendType(args, false, util) }
async setImageBlend(args) { return await this.blendType(args, true) }

hueSprite(args, util) { return this.setHue(args, false, util) }
async hueImage(args) { return await this.setHue(args, true) }

spriteShadow(args, util) { return this.addShadow(args, false, util) }
async imageShadow(args) { return await this.addShadow(args, true) }

outlineSprite(args, util) { return this.addOutline(args, false, util) }
async outlineImage(args) { return await this.addOutline(args, true) }

splitSprite(args, util) { return this.colorSplit(args, false, util) }
async splitImage(args) { return await this.colorSplit(args, true) }

waveSprite(args, util) { return this.waveEffect(args, false, util) }
async waveImage(args) { return await this.waveEffect(args, true) }

distortSprite(args, util) { return this.setDistort(args, false, false, util) }
async distortImage(args) { return await this.setDistort(args, true, false) }
distortSpriteImage(args, util) { return this.setDistort(args, false, true, util) }
async distortImageImage(args) { return await this.setDistort(args, true, true) }
waveSprite(args, util) { return this.waveEffect(args, false, util) }
async waveImage(args) { return await this.waveEffect(args, true) }

glitchSprite(args, util) { return this.setGlitch(args, false, util) }
async glitchImage(args) { return await this.setGlitch(args, true) }
@@ -758,15 +795,23 @@
vhsSprite(args, util) { return this.setVHS(args, false, util) }
async vhsImage(args) { return await this.setVHS(args, true) }

ditherSprite(args, util) { return this.dither(args, false, util) }
async ditherImage(args) { return await this.dither(args, true) }

patternSprite(args, util) { return this.addPattern(args, false, util) }
async patternImage(args) { return await this.addPattern(args, true) }

outlineSprite(args, util) { return this.addOutline(args, false, util) }
async outlineImage(args) { return await this.addOutline(args, true) }
applySpriteLight(args, util) { return this.lighting(args, false, util) }
async applyImageLight(args) { return await this.lighting(args, true) }
advSpriteLight(args, util) { return this.advLighting(args, false, util) }
async advImageLight(args) { return await this.advLighting(args, true) }
spriteShadow(args, util) { return this.addShadow(args, false, util) }
async imageShadow(args) { return await this.addShadow(args, true) }

maskSprite(args, util) { return this.mask(args, false, util) }
async maskImage(args) { return await this.mask(args, true) }

unClipSPR(args, util) { return this.updateView(args, false, util) }
async unClipIMG(args) { return await this.updateView(args, true) }

@@ -983,13 +1028,44 @@
Scratch.Cast.toNumber(atts[1] ? parseFloat(atts[1][1]) : 100)
];
const amts = [Math.abs(100 - Scratch.Cast.toNumber(args.NUM)), Scratch.Cast.toNumber(args.x), Scratch.Cast.toNumber(args.y)];
const filterElement =
`<filter id="tile"><feImage x="${amts[1]}" y="${amts[2]}" width="${amts[0] / atts[0] * 100}%" height="${amts[0] / atts[1] * 100}%" xlink:href="${await this.svgToBitmap(svg, atts[0], atts[1])}"/><feTile /></filter>`;
const filterElement =
`<filter id="tile"><feImage x="${amts[1]}" y="${amts[2]}" width="${amts[0] / atts[0] * 100}%" height="${amts[0] / atts[1] * 100}%" xlink:href="${await this.svgToBitmap(svg, atts[0], atts[1])}"/><feTile /></filter>`;
return this.filterApplier(svg, filterElement, "tile");
}
return svg;
}

async addPattern(args, isImage, util) {
let svg;
if (args.SPRITE === "_myself_") svg = await this.findAsset(util);
else svg = isImage ? await this.getImage(args.SPRITE) : await this.getSVG(args.SPRITE);
let svg2 = await this.getImage(args.PAT);
if (svg && svg2) {
let atts = [/width="([^"]*)"/.exec(svg2), /height="([^"]*)"/.exec(svg2)];
atts = [
Scratch.Cast.toNumber(atts[0] ? parseFloat(atts[0][1]) : 100),
Scratch.Cast.toNumber(atts[1] ? parseFloat(atts[1][1]) : 100),
Scratch.Cast.toNumber(args.SIZE) / 100
];
const nameGen = `pat-${Math.random()}`; // People may use multiple patterns
const pattern =`<defs><pattern id="${nameGen}" patternUnits="userSpaceOnUse" width="${atts[0]}" height="${atts[1]}" patternTransform="scale(${atts[2]})"><image xlink:href="${await this.svgToBitmap(svg2, atts[0], atts[1])}" x="0" y="0" width="${atts[0]}" height="${atts[1]}" /></pattern></defs>`;
return this.patternApply(svg, pattern, nameGen, args.COLOR);
}
return svg;
}
patternApply(svg, pattern, name, color) {
if (nameOffset > 100) nameOffset = 0;
let svgTag = svg.indexOf(">");
if (svgTag > -1) {
svgTag = svg.indexOf(">");
let appliedSVG = `${svg.substring(0, svgTag)} >${pattern.slice(0, -1)}${svg.slice(svgTag)}`;
appliedSVG = appliedSVG.replaceAll(color, `url(#${name})`);
// replace needs to be repeated twice to avoid the new name being used in other namespaces
return appliedSVG.replace(`#${name})`, `#${name}${nameOffset})`).replace(`"${name}"`, `"${name}${nameOffset}"`);
}
return svg;
}

async lighting(args, isImage, util) {
let svg;
if (args.SPRITE === "_myself_") svg = await this.findAsset(util);
@@ -1091,6 +1167,18 @@
return svg;
}

async dither(args, isImage, util) {
let svg;
if (args.SPRITE === "_myself_") svg = await this.findAsset(util);
else svg = isImage ? await this.getImage(args.SPRITE) : await this.getSVG(args.SPRITE);
if (svg) {
const size = [Scratch.Cast.toNumber(args.W), Scratch.Cast.toNumber(args.H)];
const filterElement = `<filter id="dither" color-interpolation-filters="sRGB" x="0" y="0" width="100%" height="100%"><feImage width="${size[0]}" height="${size[1]}" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAASElEQVR42gXBgQAAIAxFwW8QwhBCCCGEIYQQQgghhBBCCEMYwutOkphzYmbsvdG9l9YaEYG7o1or5xxKKay1UGYyxuC9R++dD7yGJkTj6F0HAAAAAElFTkSuQmCC"/><feTile/><feComposite operator="in" in2="SourceGraphic"/><feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="-0.5" in="SourceGraphic"/><feComponentTransfer><feFuncR type="discrete" tableValues="0 1"/><feFuncG type="discrete" tableValues="0 1"/><feFuncB type="discrete" tableValues="0 1"/></feComponentTransfer></filter>`
return this.filterApplier(svg, filterElement, "dither");
}
return svg;
}

async mask(args, isImage, util) {
let svg;
if (args.SPRITE === "_myself_") svg = await this.findAsset(util);
@@ -1342,7 +1430,7 @@
nameOffset++;
if (nameOffset > 100) nameOffset = 0;
let svgTag = svg.indexOf(">");
if (svgTag !== -1) {
if (svgTag > -1) {
let url = `filter="url(#${name})"`;
if (svg.includes("filter=\"url(")) {
const regex = /filter="url\([^"]+\)"/g;
Loading