Visual Novel for React

A lightweight, customizable, and easy-to-use Visual Novel framework.

Build rich narratives effortlessly

No new languages, no rigid templates—just your code, your style, and your story.
TypeScript-First Design
Write stories with full type safety and editor support. Define scenes, dialogues, and logic directly in code—no need for custom scripting languages.
Fully Customizable UI
Style every element to match your vision. From dialogue boxes to animations, you have full control over the presentation and interaction.
Lightweight & Scalable
Designed to be minimal and efficient, NarraLeaf scales with your project. Whether you're making a short kinetic novel or a complex branching saga, the framework stays fast and maintainable.
Component-Based Architecture
Build every scene, character, and choice using reusable React components. Customize layouts and behavior just like building any modern web app.

Why TypeScript

Build with Confidence

TypeScript powers smarter development with type safety, IDE support, and seamless integration into your CI/CD pipeline.

Type-safe storytelling
:
Leverage TypeScript's intelligent autocomplete and error checking to write more reliable, maintainable story code.
Powerful logic with a real ecosystem
:
Use JavaScript/TypeScript's full ecosystem to build conditional logic, reusable components, and dynamic narratives.
Elegant and intuitive syntax
:
Experience a beautifully designed syntax that makes story writing feel natural and expressive, while maintaining professional-grade capabilities.
CI/CD and tooling ready
:
Integrate with modern developer workflows—version control, testing, and deployment all fit naturally into your process.
scene.action([
  scene.background.char("/bg_park.png", new Dissolve(500)),
 
  "The sun is shining gently through the trees.",
  "It's already 9 AM, and I somehow woke up feeling more refreshed than usual.",
 
  Emma.show({ duration: 500 })
      .darken(0.3, 500, "easeIn")
      .char("emma_happy.png"),
 
  E`Good morning, Alex!`,
 
  "A girl stands beside me, cheerful as ever.",
  "I'm not sure how she does it, but Emma always seems to be in a good mood.",
 
  A`Emma, how many times have I ${c("TOLD", "#Ff0000")} you not to sneak into my morning walks unannounced?`,
  E`You left the door open—how could I resist?`,
 
  Menu.prompt("What should I do?")
    .choose("Want to go grab some breakfast?", [
      E`Really? You're finally inviting me out? Let's go then!`,
    ])
    .choose("Too early. Let's chill here a bit.", [
      E`Ugh, you're always so boring in the morning.`,
      E`But fine, let's sit. I actually brought something to show you.`,
    ]),
]);
 

Ready to start?

Let's make something cool together!