0 votes
by (230 points)
I've been digging through posts on the subject of using external .js files to split up Story JavaScript, and so far, every solution for Twine 2 is woefully complex and beyond my skill level. The thing is, I'm having trouble imagining that the Twine developers wouldn't think people might want to split up the thousands of lines of code a more in-depth game will inevitably have.

So, I'd like to know if there is something I'm missing, whether these threads I've been reading are outdated and there is now a better way to divide up story scripts. I would really love to be able to use my own IDE to make changes to sections of code, save it, and have the changes imported when testing, butt even having to copy/paste code into various passages would be better than the massive file I've got going here.

If not, oh well. I would just appreciate the updated information and hope that this functionality is integrated later on.

2 Answers

0 votes
by (63.1k points)

The issue with massive amounts of JavaScript is that at some point you probably should, even if you are dead set on using the Twine 2 editor, write your scripts externally and run them through linting and minification. Same with CSS, generally you want minification and autoprefixing and validation, if not a whole preprocessor like sass or such, when you're going to be adding massive amounts of code.

Another issue with multiple files in both cases is that load order matters. The old Twine 1 editor gave users multiple passages to write scripts and stylesheets but gave no options for ordering them. 

Your options are based on whether you like Twine's IDE. If the answer is yes then I suggest using the IDE only to edit passages and then export archives and use a CLI compiler (Tweego or Entwine, for example) to compile these project files with your external JavaScript and CSS. 

If you don't like the Twine IDE as much, you can do the same thing with Twee files. 

If this seems over your head, here is my build process with instructions for set up using Tweego and Nodejs: https://github.com/ChapelR/tweego-setup

by (230 points)
I'll give that link a look to see if it's something I could do, but I barely understood most of what you said in your answer, I'm afraid. Take me outside of pure web coding (HTML, CSS, JavaScript) and I just don't know what anything is. Right now, I'm writing my code in Notepad++ and copy/pastng it into the Twine 2 desktop app, as--while I like Twine--editing code directly in the program is not efficient.

Again, I'll give that link a look, and thanks for the help, but I really don't understand what you were telling me i had to do.
by (63.1k points)
If you have specific questions or concerns I'm happy to answer them, but I'm not sure what exactly is confusing you.
0 votes
by (44.7k points)
edited by

If you want to load an external JavaScript (.js) file into Twine 2, you can use something like the following code:

if (window.hasOwnProperty("storyFormat")) {
	// Change this to the path where your HTML file is
	// located if you want to run this from inside Twine.
	setup.Path = "C:/Games/MyGameDirectory/";  // Running inside Twine application
} else {
	setup.Path = "";  // Running in a browser
}
setup.JSLoaded = false;
importScripts(setup.Path + "YourExternalCode.js")
	.then(function() {
		setup.JSLoaded = true;
	}).catch(function(error) {  // eslint-disable-line
		alert("Error: Could not find file 'YourExternalCode.js'.");
	}
);

Just change "C:/Games/MyGameDirectory/" to the directory where your HTML and JavaScript files are located, and change "YourExternalCode.js" to the name of the JavaScript file you want to access.

The code doesn't get loaded immediately by importScripts(), so you can check the value of "setup.JSLoaded" (set in the above code) to tell if it has loaded properly yet or not before executing any code which depends on that JavaScript.  For example:

var IntervalID = 0;
if (setup.JSLoaded) {
	SomeFunction();
} else {
	clearInterval(IntervalID);
	IntervalID = setInterval(JSWait, 100);  // Starts waiting for external JavaScript to load.
}
function JSWait() {  // Checks to see if JavaScript has loaded yet.
	if (setup.JSLoaded) {
		clearInterval(IntervalID);  // Stop waiting
		SomeFunction();
	}
}
function SomeFunction() {
	// Your code that depends on the loaded JavaScript here.
}

That code checks to see if the external JavaScript has loaded yet or not, and if it hasn't, then it waits until it has before triggering the "SomeFunction()" function.

Also note that your external files will need to put "SugarCube." in front of SugarCube functions and properties.  So if you had code that used "State.variables" to get SugarCube variables, then in the external JavaScript you'd have to do "SugarCube.State.variables" instead.

That said, the simpler solution to deal with lots of JavaScript is to just use an external editor (like Visual Studio Code), and copy and paste it into the JavaScript section from that editor.  (I used to use Notepad++ for this too, but VSCode has extensions to check your JavaScript code.  I recommend the "DeepScan", "ESLint", "JSHint", and "Numbered Bookmarks" extensions.)

Hope that helps!  :-)

by (230 points)
Thank you! This is still a bit... convoluted, but it's the simplest method I've seen so far. I was digging around in the Sugarcube documentation again recently after becoming more familiar with Twine and JavaScript, and I noticed the "importScripts" method. However, the documentation assumes you know how to use a Promise object, and all the tutorials on that melted my brain because I've never worked with things like AJAX and they all assume you have.

I have been using that last method, and it works alright. I was just hoping to find a solution that would allow me to work with smaller pieces. I will give this a try and see if I can get it to work (my earlier experiments with "importScript" were utter failtures, but I didn't quite know how to make the program hang until everything was loaded)

I appreciate all the help!
by (230 points)
Actually, I just noticed another potential issue: the path has to change whether the game is being run in Twine or in teh browser. Should I worry about the fact that this would prevent the end-user from running the game in Twine?
by (44.7k points)
Generally speaking, the end user shouldn't be running the game in Twine, they should be running it in their browser, so that shouldn't be a problem.
by (63.1k points)
Remember that importScripts() imports the script outside of SugarCube's scope. That's fine for web libraries and such, but most addons people write specifically for SugarCube are designed to be run from within the engine's scope.
by (230 points)
Say I wanted to just put all my "database" information in external files. I'm making an RPG, so there is a ton of data on items, descriptions, and things like that. I'm assigning them to the "setup" object that is already defined. Can I do this directly in my external script, or do I need the SugarCube reference before each call to "setup"?
by (159k points)

WARNING: Based on previous statements made by TheMadExile

The undocumented special SugarCube namespace reference (that is accessable via the web-browser Console) is meant for debugging purposes, not as a means for external third-party JavaScript libraries to access the internals of the SugarCube engine.

by (44.7k points)
edited by

Despite greyelf's rather hyperbolic warning, there's no reason it should be a problem to access the setup object by using "SugarCube.setup".

But yes, you would need to reference the setup object as a property of the SugarCube object in the scripts you import.  This is what I was referring to when I said, "Also note that your external files will need to put "SugarCube." in front of SugarCube functions and properties."

 

by (63.1k points)
It is undocumented, but I doubt TME will change the name or functionality of the name space or something. If you're using most of the scripts you can find in answers on this site or out on the web, or addons on SugarCube's site, etc, that could create issues, especially since most of those scripts will be minified. It's not the end of the world, just want to make sure the OP knows that they'll need to use the script area for most addons and such still.
...