How to make local images work for Twine (for "play", "test", and "publish")

A Guide to Making Twine Local Images Work

This is my attempt to make an easy guide for a question I see people ask all the time on the various Twine forums.

The problem

People have a hard time getting images to work for their Twine games while testing and when publishing.

Twine files are HTML. Twine images are HTML <img src="image-location.jpg"> tags. When you press the “play” or “test” button, twine creates a brand new HTML file in a temporary location. When people “publish”, they put the file in a different location. That means that images and media don’t “just work” for novice users.

One fix: a pointer from one folder to another

For each Twine game you create, make a “publishing” folder where you’re going to put your published twine files, and put an image directory there. Then make a “pointer” from Twine’s “scratch” directory to your publishing folder’s directory.

Step one: create a “publishing” folder

In this example, I put the folder on your desktop, but you can put it anywhere, and my example game is called “Gamey”. Wherever you see Gamey, just change it to the name of your game. So create a folder called:

Desktop/Gamey <= this is where you publish your Twine files

This directory is what you will ZIP up for publishing to itch.io or upload to other hosting to share it with other people.

Then, create a folder inside that one:

Desktop/Gamey/gamey-images <= this is where you put your images

Step two: put an image in your game

Now, inside your new Twine game, just make your images like this:
<img src="gamey-images/pretty-picture.jpg">

This will make your images work for published games, but not when you hit the “test” and “play” button.

Step three: make a pointer in Twine’s temporary folder

When you press “play” or “test”, twine creates a new HTML file in a special folder and opens that file in a browser. We can create a “pointer” folder to your publishing folder, also called a “symbolic link”. This will let the temporary directory “see” your publishing folder.

This is done differently on Mac OS and Linux vs. Windows, but on both you need to open a “terminal” Window: a special window where you can give the computer text commands.

Mac OS and Linux

Launch “terminal”. On Mac OS you can search in “spotlight” for “Terminal”, on Linux hopefully you know how to do it for your distro. :rofl:

This is the command to create “pointer” or “symbolic link” on Mac OS and Linux. Change the folder names to your actual locations:

ln -s ~/Desktop/Gamey/gamey-images/ ~/Documents/Twine/Scratch/gamey-images

If you did it right, you won’t see any feedback that it was successful.

Windows

Windows is a little harder, because the ability to do this is turned off by default. So first, you need to turn on “Developer Mode”.

First, make sure “dev mode” is enbled or you aren’t allowed to do this:
Settings >> For developers >> Developer Mode >> on
(tested on Windows 10, anyone have Windows 11 instructions?)

Open a terminal window by clicking on Search and entering “Command Prompt” and launching it.

In Windows you have to know what your “home directory” is. It’s usually:
C:\Users\YOUR USERNAME\. When you launch “Command Prompt” you will see that directory with a “>” after it. Replace my example with your actual home directory and then paste your version of this command:

mklink /D "C:\Users\YOUR USERNAME\Documents\Twine\Scratch\gamey-images" "C:\Users\YOUR USERNAME\Desktop\Gamey\gamey-images"

Windows should output something like this:

symbolic link created for C:\Users\YOUR USERNAME\Documents\Twine\Scratch\gamey-images <<===>> C:\Users\YOUR USERNAME\Desktop\Gamey\gamey-images

Older versions of Twine

This works for versions of Twine 2.8 and up. If you are using an older version of Twine, update your Twine. If you can’t, you can still make this solution work, but instead of:

C:/Users/YOUR USERNAME/Documents/Scratch

the scratch folder is at:

C:/Users/YOUR USERNAME/AppData/Local/Temp

(does someone know the older location on Mac OS?)

Now, it should work

Now if you put images in your publish folder, they should work for your published HTML files AND when you press the “test” or “play version”.

You’ll need to do this process once for each new Twine game you create.

Please point people with this question to the thread, and please let me know any corrections or better solutions. Thanks.

3 Likes

A better approach (because it doesn’t involve symlinks that Twine may overwrite) is to have the game know if it is being run in test mode or not, and then change the URL.

To do that, you can either check the protocol to see if the file is being run locally:

if (window.location.protocol == "file:") { ... // running in test mode }

Or check the directory the game is running in:

const twUrls = [
	'AppData/Local', 'var/folders', '/tmp', // OS temp paths for older versions of Twine
	'Twine/Scratch', // 2.8 scratch folder
	'twinery' // website
]
if (!twUrls.find(p => location.href.includes(p))) return;

Once you know that you are running in test mode you can set an HTML <base> element to make your game’s relative URL’s work correctly.

const base = document.createElement('base');
base.setAttribute('href', url);
document.head.append(base);

Or you can manually set a variable that will be used to prefix all your URLs and then substitute it into your stylesheets.

Maliface has an example of the URL + Base element approach as a plugin here: Mali-s-Scripts/twine-scripts/url-fixer at main · MalifaciousGames/Mali-s-Scripts · GitHub

I personally use the other approach (checking for the protocol and adding a variable) in my games, like this:

if (window.location.protocol == "file:") {
	setup.images = "../../IF/IB/images/"; // whatever url works for your test files
	setup.fonts  = "../../IF/IB/fonts/";
} else {
	setup.images = "images/";
	setup.fonts  = "fonts/";
}
let style = Scripting.evalTwineScript('`'+$("#style-story").text()+'`');
$("#style-story").text(style);

And then in my stylesheet:

.tool-item.settings { 
  background-image: url("${setup.images}tools/cog-sheet-200.png");
}
1 Like

Can not Twine “publish” fix the urls as part of it’s copy. I would of expected this to be quite basic.

Perhaps, but Twine seems to consider itself a text-based format and really hands of responsibility of media to HTML. If you understand HTML and how it resolves URL’s it’s not too hard to come up with your own system.

The Twine authors possibly don’t realize how devoted users are to using media in their games or how many people don’t understand how html URL locations work because I see this question quite commonly.

Twine itself doesn’t really think about external resources. This is especially true since Twine 2 dropped the default support for media passages. It just publishes html files, how they interact with anything outside that file is left to the author.

But I agree with @danieltalsky that this is a common issue

I finally figured out this pipeline and am happy with it. I don’t connect my media to see when working in Twine, opting instead to publish to an HTML if I want to test media and playtest it from the index.html file in the publish directory which contains the media folder.

I put an alias/shortcut in the Mac Finder sidebar for simplicity. From Twine, when you navigate to that folder when publishing, it usually remembers the location. The default publish filename will default to your game/filename, but I always choose to save as index.html and always replace that file since that’s what itch looks for in the zip to play online.

So the game publish folder PB contains the media folder with all sounds and images. In Twine, they are all called by relative URLs to the media folder. I can playtest locally with media from the index.html which I’m constantly updating (publish>save as replacing index.html in Twine) but the media folder only needs to be updated when I drop in a new picture or sound.

To publish for real, I compress/zip the index.html file and the media folder to a zip file and name it with the game title, or the file name I’m uploading to itch - in this case poolboy.zip.