https://github.com/hiibolt/sabi
Bevy-based Visual Novel game engine with a custom theatre-script like language with advanced customization features.
https://github.com/hiibolt/sabi
bevy-engine pest rust visual-novel
Last synced: 2 months ago
JSON representation
Bevy-based Visual Novel game engine with a custom theatre-script like language with advanced customization features.
- Host: GitHub
- URL: https://github.com/hiibolt/sabi
- Owner: hiibolt
- License: agpl-3.0
- Created: 2023-06-15T18:45:58.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2026-01-11T19:59:22.000Z (5 months ago)
- Last Synced: 2026-03-01T19:47:32.537Z (4 months ago)
- Topics: bevy-engine, pest, rust, visual-novel
- Language: Rust
- Homepage:
- Size: 15.5 MB
- Stars: 15
- Watchers: 1
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Sabi
Sabi is a visual novel engine built on Rust and Bevy ECS. It provides a domain-specific scripting language with stage direction syntax, a modular character system with emotion-based sprites, and runtime asset management through Bevy's asset pipeline.


## Features
**Scripting Language**
- Pest-based parser with stage direction syntax inspired by theatrical scripts
- Scene-based organization with named transitions
- Expression evaluation supporting string concatenation and variable substitution
- Inline emotion changes during dialogue
**Actor System**
- JSON-based character definitions with sprite mappings per emotion and outfit
- Frame-based sprite sheet animations with configurable FPS
- Character positioning system using percentage-based coordinates that scale with window size
- Fade in/out and directional facing with automatic sprite flipping
- Actor movement with interpolation between positions
**Rendering**
- ECS-based architecture separating character state from visual representation
- Background management with transition support
- Customizable GUI elements (textbox, namebox) with 9-slice and auto scaling
- Text rendering with character-by-character reveal animation
- History system tracking all dialogue and stage directions
**Development Environment**
- Nix flake for reproducible builds
- Hot-reloadable assets during development
- Six example projects demonstrating different features
- Modular plugin architecture for extending functionality
## Getting Started
### Prerequisites
- Rust toolchain (1.80+)
- Cargo
### Running Examples
```bash
cargo run --example basic_startup
cargo run --example character_operations
cargo run --example animation
cargo run --example background
cargo run --example ui
cargo run --example infotext
```
### Using Nix
```bash
nix develop
cargo run --example basic_startup
```
## Script Language
Sabi scripts use a `.sabi` extension and organize content into scenes with stage directions:
```
SCENE opening
(GUI textbox changes to "TEXTBOX_DEFAULT")
(Background changes to "classroom_day")
(Nayu appears center)
Nayu: "This is dialogue."
Nayu: (happy) "Emotions can change inline."
MC: "Player character speaks like this."
(Nayu moves right)
(Nayu looks left)
(Nayu fade out)
(Scene "next_scene" begins)
CURTAIN
```
### Supported Commands
**Character Operations**
- `(Character appears [position] [looking direction] [emotion])`
- `(Character disappears)`
- `(Character fade in/out)`
- `(Character moves position)`
- `(Character looks left/right)`
**Positions**: `center`, `left`, `right`, `far left`, `far right`, `invisible left`, `invisible right`
**Scene Management**
- `(Scene "scene_name" begins)` - Jump to different scene
- `(Background changes to "background_id")`
- `(GUI element changes to "sprite_id" [sliced|auto])` - Customize textbox/namebox
**Animations**
- `(Animated "animation_id" appears position scale N)`
- `(Animated "animation_id" fade in/out)`
- `(Animated "animation_id" moves position)`
- `(Animated "animation_id" looks left/right)`
**Dialogue**
- `Character: "dialogue text"` - Named character speaks
- `Character: (emotion) "dialogue"` - Inline emotion change
- `MC: "dialogue"` - Main character (substitutes player name)
- `info: "text"` - Narrator/info text
**Logging**
- `{log "debug message"}` - Console output for development
## Project Structure
```
src/
├── actor/ # Character and animation controllers
├── background/ # Background rendering system
├── chat/ # Dialogue box and text animation
├── compiler/ # Script parser and AST
└── loader/ # Asset loaders for JSON and .sabi files
assets/sabi/
├── acts/ # Script files organized by chapter
├── animations/ # Animation sprite sheets (JSON)
├── backgrounds/ # Background images
├── characters/ # Character sprites and configs
├── fonts/ # Text rendering fonts
└── ui/ # UI element sprites
```
## Integration
Add Sabi to your Bevy app:
```rust
use sabi::*;
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(SabiPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
mut msg_writer: MessageWriter,
mut user_defined_constants: ResMut,
) {
user_defined_constants.playername = "Player".into();
commands.spawn(Camera2d::default());
msg_writer.write(SabiStart(ScriptId {
chapter: "chapter1".into(),
act: "opening".into()
}));
}
```
## Architecture
Sabi uses Bevy's ECS with a plugin-based architecture:
- **Compiler Plugin**: Parses `.sabi` scripts into an AST, evaluates expressions, manages scene transitions and game state
- **Character Controller**: Spawns/despawns actors, handles movement interpolation, manages fade effects and sprite switching
- **Chat Controller**: Renders dialogue boxes, implements text reveal animation, maintains conversation history
- **Background Controller**: Loads and transitions between background images
The system uses Bevy's message passing for coordination between plugins and resource-based state management for the script execution cursor and character configurations.
## Asset Configuration
**Character Definition** (`character.json`):
```json
{
"name": "Nayu",
"outfits": {
"uniform": {
"emotions": {
"neutral": "nayu_neutral.png",
"happy": "nayu_happy.png",
"concerned": "nayu_concerned.png"
}
}
}
}
```
**Animation Definition** (`animation.json`):
```json
{
"name": "fire",
"spritesheet": "fire_sheet.png",
"frames": 8,
"fps": 12,
"frame_width": 64,
"frame_height": 64
}
```
## Current Limitations
- No save/load system
- Audio not implemented
- No branching/choice system
- Text input requires external implementation
- Asset paths are hardcoded relative to `assets/sabi/`
## License
See [LICENSE.md](LICENSE.md)
## Credits
- UI Panels by [BDragon1727](https://bdragon1727.itch.io/custom-border-and-panels-menu-all-part)
- Fire animation by [Devkidd](https://devkidd.itch.io/pixel-fire-asset-pack)