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 4.6 out of 5 stars
(14 total ratings)
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.2_demofix.zip 17 MB

Development log


Log in with itch.io to leave a comment.

Hey! Does this tool support cyrillic languages?

Traceback (most recent call last):

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

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

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)

Hi! TL;DR: Not currently, but it might in the future.

Unfortunately because the tool was originally written in Python 2.7 it cannot process some ascii characters, likely including Cyrillic ones. I have a longterm roadmap to port the tool to Python 3 at some point which I believe will be able to fix some of these limitations, but it would require a bit of an overhaul because of the library differences.

Is there a way to set variable when linking to a passage?
I would like to avoid having 2 pages for setting variable.

I tried this but it breaks when using tool to convert to RenPy, while works fine in Twine:

<<set $myVariable = false>>

[[Click me to go to NextPassage and set variable to true|NextPassage][$myVariable to true]]

The tool doesn’t currently account for this, but a simple workaround would be to set the variable to true at the beginning of the passage. It would be a slightly trickier feature to add because this type of statement doesn’t explicitly exist in Ren’Py or Python to my knowledge, but let me know if you had an equivalent statement in mind + how important this is to your current workflow.

Hmm actually, I lied, I forgot that menus can be multiline. I can take a look at this, but it may take some time to find a solution.

Thanks for replying so quickly.

I wouldn't say it's crucial for my workflow. I would just need to redo some paths when I convert to renpy.

Probably in most cases you would set variable depending on choice in next passage. In my case I have some examples where I would set different bool state for variable but for both choices would take to same passage.

Like this:

<<set $hasFeature= false>>

"Would you like to have this feature?"

[[Yes, I would like to have that feature|Game Start][$hasFeature to true]]

[[No|Game Start][$hasFeature to false]]

So, if you don't see this useful for other projects, don't bother. I'll just redo these instances when converted to renpy.

Nah, I can definitely see a use for this. I didn't thoroughly test this one but here's a quick shot at it if you have some time to try it out.

It's working great now! Thanks for the quick update!

Actually I found one issue that happens on 1.2.3 version and not on 1.2.2

When I have this in Twine:

[[Try last option|Last_Option]]

In 1.2.2 it transformes properly to:


        "Try last option":

            jump last_option

while in 1.2.3 it transforms to:


        "Try last option":

    last_option        jump


Does it support RenPy 8+?
I tried Demo project and when I run it I get an error

Hey! Sorry about that--I checked the latest demo file and looks like I didn't do a thorough final check with one that was provided to me for testing. That line in the Twine source file should have " quotes around it, but if they are added the tool converts properly. I fixed it up and re-uploaded a zip with fixed demo files. Let me know if those work for you!

Hey, thanks! It works now.

this looks incredibly helpful however i dont have a windows device, would you ever consider making a version for mac? if not does anyone know anything similar for mac (im a bit too smallbrain to figure out renpy on my own haha)

It's possible to run on Mac by downloading Python 2 and just downloading the source code and running the twine_to_rpy.py.

Hi, I'm having a hard time finding information on how to use twine to renpy. So far I have achieved several "successes" by trial and error. I would really appreciate if there is any guide that can help me. Right now I'm trying to find out, if you can use accents in the text somehow, or define and use numeric variables. I have seen that <<set $variable=1>> or <<set $variable=$variable +1>>, doesn't work either, even if I define the variable in twine as <<set $variable to 1>>

Hi! Sorry to hear you've been having a hard time with the tool. Have you imported the "Demo.html" into Twine 2? Is there anything confusing about how it's set up? Or do you find the options in the tool the confusing part?

Secondly, I'm not able to repro an error when "<<set $variable to 1>>" is used. Do you have "Define variables" enabled under "Characters and variables" in the Twine to Ren'Py UI? If so and you're still seeing problems, if you're comfortable giving me the file or an isolated repro case, that'd help me in narrowing down what might be wrong! If you can export the Twine to file, get the incorrect .rpy output files, and a screenshot of your tool settings before you hit run,  you can send them to jbtuason at gmail dot com, and I'll take a look.

Thank you very much for your answer, I think I have managed to understand how I should do twinw to be able to use it in renpy, except for the numerical variables, which I cannot find the way to perform calculations with them, such as sum of variables. I am sending you the file by mail, but I wanted to thank you openly for your quick response, and this tool that will help me a lot to try to create my visual novel in an orderly manner.

So if I'm reading this right, it auto covers sugarcube 2 to renpy code (so it's converting twee to python?) 

So variables / passage links should remain valid then, right?

Would be nice if I can use this to change my existing game to renpy without recoding it and only have to update images. 

Thanks in advance :) 

Not sure what you mean by twee to python (I haven’t really looked at what Twine 2 does with twee) so that is likely a no, but yes on a sugarcube 2 Twine game’s exported HTML to Ren’py code for most basic games. Variables are converted to inline Python for Ren’py and passage links are converted to menus and labels. For existing Twine games you will likely want to use “Twine mode”.

Let me know if you run into any issues!

Thanks for the response. It'd be great if I could convert all the sugarcube 2 code I wrote so I don't have to recode everything if I wanted to remake my game into a visual novel. 

Though I'm not entirely sure if this will work for that (will need to look into it more and try it out)


If it doesn't feel free to send me a trimmed test case Twine project with what you're trying to do and I can take a look to see if it's within the scope of the tool.

cool thanks!  I started remaking it from scratch. Almost done with the first chapter. Let me finish that first. :)

I added this as a feature directly inside yarn editor


Awesome! Really glad the tool could be helpful! I know quite a few VN devs who also use yarn and def passing along.

Thank you :) I plan to continue extending it and even making a demo renpy project with it

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.

Hello! I think that this is related to custom links anchors, like:

[[Text option to the reader|DestinationLink123]]

[[Text option to the reader-->DestinationLink123]]

The demo version and other test I did with the simple link syntax are ok. So for now, anything created with this kind of links return this error.

Hope that this help!

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!