A downloadable tool

Download NowName your own price

The Twine to Ren'Py tool allows you to write a simple Ren'Py game but with the visual outlining of writing in Twine. Convert a Sugarcube Twine html file into rpy files for your Ren'Py game project.


  • Converts Twine-like choices into Ren'Py menus
  • Converts Twine variables and conditionals to Ren'Py
    • (Note that conditional results need to be on a new line to be processed properly. See demo Twine file uploaded as of 7/3)
  • Option to define characters and variables at start of script
  • Replaces special characters and passage titles with Ren'Py safe terms
  • Add custom replacement terms
  • Use passage tags to break up into separate rpy files
  • Includes Sugarcube demo for writing Ren'Py games in Twine

How to use:

  • Unzip the directory
  • Run twine_to_rpy.exe inside the twine_to_rpy directory
  • Select the html file (Demo.html is included for testing) and directory to output rpy files
  • Run!

Curious how to set up your Twine file?

Open the Demo.html in Twine 2 to see how the file is written for tool processing.

Run into a bug?

Drop the steps to reproduce the bug in the comments.


This tool won't be closely supported in the future, but if you have a suggestion for a feature that would help you with a project feel free to let me know in the comments!

Source code

The source code for the tool is here. If you want to run the tool on Mac or Linux, you can download and run the tool using Python 2.7.

Rated 5.0 out of 5 stars
GenreVisual Novel
TagsRen'Py, script, tool, Twine


Download NowName your own price

Click download now to get access to the following files:

twine_to_rpy_1.2.1.zip 17 MB

Development log


Log in with itch.io to leave a comment.

I tried to use this tool to convert an existing project from Twine to Ren'Py format.  The GUI produced no error message, but no Ren'Py files were generated, either.  When the tool is run from the terminal, though, this error message is outputted:

Traceback (most recent call last):
  File "twine_to_rpy\twine_to_rpy.py", line 465, in run
  File "twine_to_rpy\twine_to_rpy_model.py", line 276, in run
ValueError: too many values to unpack

On my end, converting the demo file does work as expected (except for the part where the start.rpy file outputs test_character (without quotes) instead of either defining a character called test_character earlier in the file or outputting "test_character" (with quotes), leading to a Ren'Py error message at runtime unless the start.rpy file is manually edited).

Thanks for the bug report! I'll take a look into what might be causing the ValueError. WRT defining characters, the tool does not automatically do that, so unfortunately that's just a demonstration of how users should format their scripts with speaking characters.  What I could do instead is add an option to output the "first" .rpy file as something other than start.rpy, which allows users to enter that part of the script themselves and leaves any code in start.rpy alone, including scripts that users might add later. I think this sounds more useful for all cases, but let me know if you're thinking an option to define characters when generated makes more sense or seems like an expected option otherwise.

I think the characters thing could benefit from a dropdown setting with the following options (possibly excepting the second):

* Generate character variables, and include those character variable declarations and uses in the output.  (This would make a file that runs, and the user would be able to adjust the character variable assignments if they cared to.)
* Output character names in quotes so that they'd be strings rather than variable names. (This would make a file that runs, but with no formatting on speaker names; on the other hand, there'd be no conflict with already defined character names.)
* Use variables for character names, but do not generate a definition for them.  (This would make a file that does /not/ run unless the user has generated a separate file with character variable declarations or adds the same to a generated file after the fact.)

 The first two options would be useful for someone who wanted the generated files to "just work", and the third would be useful for someone who wanted to run the conversion tool iteratively, but didn't want to repeatedly respecify the formatting for character text output.

I'm inclined to think that one of the first two options should be the default setting.  A new user who uses the default settings on the sample Twine file should be able to end up with something that works as expected in Ren'Py (otherwise, the new user might think the tool is "broken", even if the tool is performing exactly the intended behavior).

Thank you for the detailed suggestions! They sound possibly doable, but I won't promise anything just yet until I look at it. I didn't plan to support this tool much, but I may come back to it for some other updates that I could possibly wrap into one release.

Also, in case this helps your debugging, one of the perhaps atypical aspects of the Twine file that I tried to convert is that some of the <tw-passagedata> blocks within it are of type tags="Twine.image", and they contain base64-encoded .png data rather than standard Twine scenes.  It occurred to me that the conversion tool might be choking on this type of data.

This might be easier for me to debug with a repro. If you don't mind could I ask you to send an example file to jbtuason/gmail? You can trim to just the passage with encoded strings, or just send the encoded strings + tags on their own.

The project I was trying to convert is https://azulookami.itch.io/finding-a-place (NSFW project, SFW project page).  At the time I first tried using the Twine to Ren'Py tool, the project artist had said in the comments that they were looking to convert the Twine project to Ren'Py, and were looking to pay someone to perform that conversion.  Since then, the project artist has apparently found someone to pay for that conversion (that person is not me), so my warrant for trying to do the conversion myself (getting that project rolling again faster) has been effectively obsoleted.

You should be able to find a relevant <tw-passagedata> block by doing a search for (tags="Twine.image") (without the parentheses).

(1 edit)

Thanks! Looks like the problem had to do with passages that had no links whatsoever (which coincidentally were the Twine.image ones). It's not too hard to add an option to skip them and maybe throw in options for other tagged passages to be skipped as well. However, even after that addition it looks like for this project in particular there are other possibly non-standard characters that would cause problems with the decode as well as custom macros that wouldn't make this a simple conversion.

Great tool! Thank you! I'm using twine as a first prototyping system for a visual novel and the software works great!

Sorry for the late response--Really glad to hear that!

(1 edit)

Is there a way to get the menu option to display your text while the options are up? ie:


     "What do you pick?"

          "I pick 1":

jump to option1

     "I pick 2":

jump to option2

Sorry for the late reply! Currently the tool does not support this directly out of Twine conversion (you would have to nudge lines around in Ren'Py)--and I don't know if there is a good way to translate an "equivalent" in Twine, but I am curious if you like this format for all menus or only some of them?

(1 edit) (+1)

in your demo needs to be 
"test_character" to work properly or you get a 
test character is not defined error. 

[Edit: I was a dum and forgot to put the second script in the scripts section. I copied the error here, then figured it out like 10 seconds later.]

Sorry, confused by the edit—did you get this figured out or are you still seeing the error?

Yeah, I figured my 2nd part out. Thanks :) I love this tool btw. 
I'm only getting started with Ren'py, but this will def help me keep my thoughts in order. 

Really happy to hear that!! It's helped with organizing our project so I'm glad other people are able to get use out of it!

(1 edit)

Great Job!!
One little detail, I could'nt use the converter because can't support some latin caracter, (for example: ó)

Thanks for the heads up--I've had some difficulty implementing a proper encode/decode for special characters so I'll make a note to dig into it again in the future to see if there's a better way to handle it.

Deleted post

Wow! This is a really clever workaround. What I might try to do is add these characters to the hidden replace terms (which are used for the Twine to Ren'Py conversion in the first place). It's been a second since I've sat down at my computer with this script though, but it'll be slated into whenever I can manage an update for sure.

This is a great idea! 

You may want to add a note about story format support. The demo is in Sugarcube. I tried it on a Harlowe file, and somethings worked well, but it didn't always translate the links in a way that made sense. 


Ah, knew I was forgetting something important. Thanks for the feedback! I've added to the info that the demo is for Sugarcube, but I'll make a personal note to look into support for Harlowe in the future.

Great, thank you!

uhmmm I'm trying to load the demo, I have no idea of what I'm doing and it looks like if I try and open start.rpy inside the demo folder it will say 'directory name not valid' and won't open it. Can anyone tell me how you do that? If I had screenshots of examples, I'd really appreciate that!

(1 edit)

This is a really strange error that sounds unrelated to the tool. From a quick search it sounds like something might be wrong with your directory or you might be having some disk errors. Where is the demo folder--are you saving it to a USB drive? If not, can you skim this list to see if any of them seem relevant?


This is so cool!

I always have trouble organizing different timelines so this really helps /~\

I'm gonna try it later!

I'm glad it could be helpful!


How cool!?!

Thank you!

Any idea why this may be happening? I'm trying to transport one particular TWINE project - it did have a lot of javascript and stuff in it but... here's the traceback error

Traceback (most recent call last):

  File "twine_to_rpy\twine_to_rpy.py", line 465, in run

  File "twine_to_rpy\twine_to_rpy_model.py", line 209, in run

AttributeError: 'NoneType' object has no attribute 'encode'

It does work with other simpler projects without a lot of TWINE coding (Sugarcube - variables and the like) in it. Maybe it's because I have too many passages for it to parse or some weird code (JS) I should clean out before transferring? 

This tool is designed to write simple Ren'Py games in Twine (already written in Ren'Py language but using the passage jumps of Twine). It will not blanket transform any Twine game into a ready made Ren'Py VN. If you need this for a project I can take a look at the Twine html for testing, feel free to reach out to me at jbtuason/gmail. I have not tested it with any projects using JS.


Ah, that does make sense. I had a TWINE game with 498 passages. LOL. No worries. :) It is a good program though. It does work with my simpler/shorter TWINE games.

omg I'm glad to hear that! I didn't have a wide range of tests outside of our own Twine/VN so that's cool to know.

I tend to think it was the JS code I had put in it - or at least that in combination with a *high* amount of Passages that the program had to try to transcribe. Looking at the output - the code that I managed to transcribe to .rpy file was fine, so I really think It was the amount of passages or the JS code. I had an array in the StoryInit Passage which could have made the program choke or something. 


Oh, this is absolutely fantastic!  I have a hard time writing in Ren'py because it's just blocks and blocks of text, so being able to organize things with Twine should make things exponentially easier.

(1 edit)

My writer had the exact same problem and found it much easier working this way. I hope it's helpful for you too!

(1 edit) (+1)

What a nice idea ^^

(1 edit) (+1)

Thank you so much!


Oh! This seems neat!

(1 edit)

Thank you!