Pretty good logo! Better than whatever I’d do. I was actually planning to make a modding system, call it Snap!Mods, even started working on it. Better give that up! I agree with making it blue and yellow, for the Snap! logo of course. I think the line (for the c) and the mini lambda logo should be the blue, and the rest yellow. Maybe the other way around to make it EVEN similar to the Snap! logo. Anyway that’s enough logo talk. Make I could help? I would make it a browser extension kinda like Scratch Addons (that’s actually how I wanted to make Snap!Mods). Maybe use a seperate button, using Morphic’s SymbolMorph’s “cross” icon (that’s how I did it in Snap!Mods! I should probably shut up about that now). Heres a little planning from me:
- Extension loads up, waits for Snap! to be loaded (probably waiting for a “world” variable (a WorldMorph) and one child in it, which is what Snap! creates. Then wait a bit after to make sure its loaded.
- Do a little patching on the IDE to add the mod button
- Create a global variable, e.g. “__crackle__”, using “window.__crackle__ = {…}” (maybe you can omit the “window.” part, I had to do that in Snap!Mods as I used a main function
- And then, add mods and such to that
For the mods themselves, I think they should simply be a return statement, with a object containing the mod info and functions. And then, you should be able to refer to “this”; not as the object you returned (although it would copy some stuff from that) as a Mod object, which contains a “api” variable, containing the Crackle API. That could define a function to create a menu (in the mod button menu), a function to register a cleanup function, another to register events, and so on and so on. I’m actually going to share a couple snippets of code from my Snap!Mods project that might help:
Function (use with ‘await’) to wait for Snap! to be ready
function waitForSnapReady() {
return new Promise(resolve => {
const check = setInterval(() => {
if (typeof world !== "undefined" && world.children.length > 0) {
clearInterval(check);
resolve();
}
}, 100);
});
}
Code I used to add the mod button (you can tweak it with your menu options)
function adjustLabel() {
controlBar.label.setPosition(
new Point(
controlBar.label.left() + BUTTON_OFFSET + modButton.width(),
controlBar.label.top()
)
);
controlBar.label.children[0].setPosition(controlBar.label.position());
}
// create mod button
const settingsButtonIndex = controlBar.children.findIndex(
child => child instanceof PushButtonMorph && child.action === "settingsMenu"
);
const modButton = controlBar.children[settingsButtonIndex].fullCopy();
controlBar.addChild(modButton);
Object.assign(modButton, {
about() {
new DialogBoxMorph().inform(
"About Snap!Mods",
`Snap!Mods, a modding framework for Snap!\n` +
`Developed by codingisfun2831\n` +
`Version ${window._snap_mods_.version}`,
world
);
},
loadMod() {
new DialogBoxMorph(
this,
(input) => {
try {
window._snap_mods_.loadMod(input);
ide.showMessage(`Mod $loaded successfully!`);
} catch (e) {
ide.showMessage(`Failed to load mod:\n${e}. Check the console for more details.`);
console.error(e);
}
},
this
).promptCode(
"Load mod from code",
"// Paste your mod code here",
world
);
},
loadModFile() {
const input = document.createElement("input");
input.type = "file";
input.accept = ".js,text/javascript,application/javascript";
input.onchange = (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
try {
let mod = window._snap_mods_.loadMod(e.target.result);
ide.showMessage(`Mod "${mod.name}" loaded successfully!`);
} catch (e) {
ide.showMessage(`Failed to load mod:\n${e}`);
}
};
reader.readAsText(file);
};
input.click();
},
manageMods: manageLoadedMods,
action() {
const menu = new MenuMorph(modButton);
menu.addItem("About Snap!Mods...", "about");
menu.addLine();
menu.addItem("Load mod from code...", "loadMod");
menu.addItem("Load mod from file...", "loadModFile");
menu.addItem("Manage loaded mods...", "manageMods");
let menus = {};
for (let mod of window.snap_mods.loadedMods) {
if (mod.doMenu) {
menus[mod.name] = mod.menu;
}
}
if (Object.keys(menus).length > 0) {
menu.addLine();
for (let [title, modMenu] of Object.entries(menus)) {
menu.addMenu(title, modMenu);
}
}
menu.popup(world, modButton.bottomLeft());
}
});
modButton.children[0].name = "cross";
modButton.setPosition(new Point(
controlBar.children[settingsButtonIndex].right() + BUTTON_OFFSET,
controlBar.children[settingsButtonIndex].top()
));
adjustLabel();
// label updates
const originalUpdateLabel = controlBar.updateLabel;
controlBar.updateLabel = function() {
originalUpdateLabel.call(this);
adjustLabel();
};
Here’s the GitHub repo I made for it before giving up on it, also.
I would recommend making the project on Github. Also, learn git before instead of just uploading files to GitHub. Hope I can help with it!