Skip to content

About

A fan-made Visual Novel of Penacony (Honkai Star Rail)

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 

Repository files navigation

Dreams & Dice

Dreams & Dice is a fan-made interactive visual novel set in a surreal Penacony-inspired dream archive. It combines branching dialogue, investigation, relationship changes, collectible evidence, alternate endings, music-driven atmosphere, and a visual archive of recovered story scenes.

This project is intended for entertainment and creative storytelling. It is not affiliated with, sponsored by, or endorsed by the original rights holders of any referenced characters or settings.

Contents

Project overview

The application is a browser-based React game that can also be packaged as a Windows desktop application with Electron.

At startup, the app displays:

  1. A Yokailab brand/loading screen.
  2. A fan-project disclaimer.
  3. The main game menu.

The game then loads the central Game controller. This controller manages the active scene, dialogue, choices, audio, menus, saves, achievements, casebook data, gallery access, and other gameplay state.

Features

Branching visual novel

  • Scene-based story progression.
  • Dialogue lines with speakers, emotions, backgrounds, music, and visual effects.
  • Player choices that can:
    • Move to another scene.
    • Set story flags.
    • Change relationship values.
    • Add inventory items.
    • Add evidence.
  • Timed choices with configurable timeout routes.
  • Keyboard navigation for dialogue and choices.
  • Auto-play and skip modes.

Multiple story routes

The story is assembled from three authored JSON sources:

  • Main story.
  • The Lost Dreamer side quest.
  • Alternate-ending story content.

The flowchart includes the main route, side-story route, alternate branch, and separate ending nodes, including:

  • Tragic ending scenes.
  • Insanity and other authored ending scenes.
  • The side-story ending.
  • The true alternate conclusion.

Casebook

The casebook provides live views of:

  • Evidence discovered in the story.
  • Inventory items collected by the player.
  • Relationship activity.

Casebook sections can scroll when their content exceeds the available space.

Gallery

The Gallery is the visual archive for recovered story frames.

  • Frames are locked until their corresponding scene is visited.
  • Recovered frames display their actual scene background asset.
  • Images are shown in monochrome for the archive aesthetic.
  • Cards use a responsive 16:9 image ratio.
  • Selecting a recovered frame opens a larger scene-detail preview.
  • The preview uses a liquid-glass background and an opaque overlay so the underlying gallery does not show through.

Flowchart

The flowchart visualizes discovered story routes and connections.

  • Visited scenes are shown as discovered nodes.
  • Unvisited branches remain visually concealed or locked.
  • Runtime-only connections are added for side-story and alternate routes.
  • Ending nodes are marked separately.
  • Zoom-out, zoom-in, and reset controls are available.
  • The current zoom percentage is displayed.

Persistence

The game persists progress in browser localStorage and Electron Chromium storage.

Persisted information includes:

  • Autosave state.
  • Manual save slots.
  • Run history.
  • Settings.
  • Unlocked achievements.
  • Main-story completion state used to unlock side content.

Settings such as the default main-menu music are saved immediately and are restored with precedence over older settings embedded in autosaves.

Audio

  • Background music loops continuously.
  • Scene-specific music can replace the current track.
  • The selected default main-menu track is used when the player is in the main menu.
  • BGM, SFX, and master volume settings are independent.
  • Audio playback is started or resumed in response to browser/Electron autoplay rules.

Achievements

Achievements can be triggered by:

  • Reaching story scenes.
  • Reaching ending scenes.
  • Collecting evidence.
  • Completing the visual gallery.
  • Completing the authored story archive.

Achievement notifications are deduplicated and should only appear when an achievement is newly unlocked.

Electron desktop support

The Electron shell:

  • Opens the built Vite application.
  • Exposes a safe restart API through the preload script.
  • Uses context isolation.
  • Disables Node integration in the renderer.
  • Locks the application window to 1600 x 900.
  • Resets Chromium zoom to 100%.
  • Blocks accidental Ctrl-plus/Ctrl-minus page zoom shortcuts.

Technology

Runtime

  • React 19
  • TypeScript 5.8
  • Vite 6
  • Motion
  • Lucide React
  • Three.js and React Three Fiber
  • Tailwind CSS

Desktop and packaging

  • Electron 36
  • Electron Builder

Testing

  • Vitest
  • Testing Library for React
  • Testing Library Jest DOM
  • JSDOM

Requirements

Install the following before working on the project:

  • Node.js with npm.
  • Windows 10 or newer for Windows packaging.
  • A modern browser for web development.
  • Windows build tools may be required by Electron Builder or native dependencies.

Use an active LTS version of Node.js when possible.

Installation

From the project directory:

npm install

The project does not require a runtime API server or external database. Story content and static assets are included in the repository.

Running the project

Browser development server

npm run dev

Vite starts the development server on port 3000 and listens on all interfaces.

Open:

http://localhost:3000/

Electron development build

npm run dev:electron

This command first creates a production Vite build and then opens it in Electron.

Preview the production web build

npm run build
npm run preview

Available commands

Command Purpose
npm install Install project dependencies.
npm run dev Start Vite development mode on port 3000.
npm run dev:electron Build the web app and launch Electron.
npm run build Create the production Vite build in dist/.
npm run preview Serve the production build locally.
npm run lint Run the TypeScript compiler in no-emit validation mode.
npm test Run the Vitest test suite.
npm run dist:win Build Windows Electron distributions with Electron Builder.
npm run dist:portable Build the portable Windows executable.
npm run release:windows -- 1.0.0 Run validation and create versioned portable, installer, and ZIP artifacts.
npm run clean Remove selected generated build files.

Project structure

.
├── electron/
│   ├── main.cjs              Electron main process and window setup
│   └── preload.cjs           Safe renderer-to-main bridge
├── public/
│   ├── bgm/                  Background music files
│   ├── backgrounds/          Scene background images
│   ├── characters_portraits/ Character portrait assets
│   └── icon.ico              Windows application icon
├── scripts/
│   └── release-windows.cjs   Windows release automation
├── story/
│   └── 1.0 story/
│       ├── main story/
│       └── side quest/
├── src/
│   ├── components/
│   │   ├── Game.tsx          Main game controller and screen rendering
│   │   ├── FlowchartScreen.tsx
│   │   ├── AchievementsScreen.tsx
│   │   ├── RunHistoryScreen.tsx
│   │   ├── Gallery and archive UI in Game.tsx
│   │   └── Shared visual components
│   ├── achievements.ts       Achievement definitions and conditions
│   ├── gameContent.ts         Casebook, cast, and authored content helpers
│   ├── gameStorage.ts         Save validation and localStorage helpers
│   ├── script.ts              Story normalization and runtime SCRIPT map
│   ├── types.ts               Shared game, scene, dialogue, and choice types
│   ├── App.tsx                Startup sequence and Game mounting
│   ├── main.tsx               React entry point
│   ├── index.css              Global layout and visual styling
│   └── App.test.tsx            Application tests
├── backgrounds.json            Background metadata and asset mapping
├── character.json              Character metadata and portrait mapping
├── index.html                  Browser entry document
├── package.json                Scripts, dependencies, and Electron Builder config
└── README.md                   Project documentation

Story and scene data

Source files

Story JSON is imported and merged in src/script.ts:

story/1.0 story/main story/story.json
story/1.0 story/side quest/side-quest-01-lost-dreamer.json
story/1.0 story/main story/story-alt-ending.json

The files are merged into one raw story object. Each object key is a scene ID and each value is an array of story lines.

Story line fields

A story line may contain:

{
  "speaker": "Sparkle",
  "text": "A line of dialogue.",
  "emotion": "smile",
  "bg": "bg_dream_lounge",
  "bgm": "First_Dream.mp3",
  "nextScene": "act1_next",
  "timeLimit": 5,
  "timeoutChoiceId": "ending_insanity",
  "choices": [
    {
      "label": "Choose an answer",
      "nextScene": "act1_branch"
    }
  ]
}

Supported story metadata includes:

  • speaker: Character name or narrator/system speaker.
  • text: Dialogue or narration text.
  • emotion: Portrait emotion key.
  • bg: Background ID from backgrounds.json.
  • bgm: Music filename from public/bgm/.
  • nextScene: Scene to enter after the line.
  • choices: Player choices shown at the end of a scene or line.
  • timeLimit: Timed-choice duration in seconds.
  • timeoutChoiceId: Choice ID or destination scene used when time expires.

Runtime normalization

src/script.ts converts raw JSON into the runtime SCRIPT map. During normalization it:

  • Generates stable dialogue IDs.
  • Resolves character names to character IDs.
  • Applies background fallbacks.
  • Applies scene music overrides.
  • Infers an emotion when no emotion is authored.
  • Adds visual effects for specific text or emotion patterns.
  • Creates terminal end_credits content.
  • Builds the gallery scene list from scenes with authored backgrounds.

When adding a new scene, ensure every nextScene target exists in the merged story data.

How gameplay works

The main game state includes:

  • Current screen.
  • Player name.
  • Current scene ID.
  • Dialogue index.
  • Dialogue history.
  • Visited scene IDs.
  • Unlocked achievement IDs.
  • Dialogue log.
  • Flags.
  • Relationship values.
  • Inventory.
  • Evidence.
  • Settings.

When a choice is selected, the game:

  1. Records the current location in history.
  2. Applies flags.
  3. Adds relationship changes.
  4. Deduplicates inventory items.
  5. Deduplicates evidence.
  6. Moves to the destination scene or advances the current dialogue.

Scene transitions update the visited-scene list. The gallery, flowchart, achievements, and menu statistics derive their information from this live state.

Save data and persistence

Storage keys are defined in src/gameStorage.ts:

Key Contents
penacony_autosave Most recent automatic progress snapshot.
penacony_saves Manual save slots.
penacony_run_history Up to 25 archived run snapshots.
penacony_settings Dedicated persistent settings record.
penacony_main_story_completed Main-story completion flag used for side content unlocks.

Save validation

Before a save is loaded, the game checks that:

  • The value is an object.
  • The scene ID exists in SCRIPT.
  • The dialogue index is an integer.
  • The dialogue index is not negative.

Loaded state is normalized and dialogue indexes are clamped to the selected scene's available dialogue range.

Resetting progress

The Preferences screen's Reset progress action removes:

  • Autosave.
  • Manual saves.
  • Run history.
  • Settings.
  • Main-story completion state.

It also resets the in-memory game state and UI overlays.

Audio system

Music files are stored in public/bgm/ and referenced by filename.

The BGM synchronizer:

  • Chooses menu music from settings.defaultMainMenuBgm.
  • Uses scene-specific BGM when authored.
  • Uses act-level fallbacks when no scene BGM is specified.
  • Loops every active track.
  • Fades between tracks.
  • Applies master and BGM volume settings.

If a track does not play:

  1. Confirm the exact filename and capitalization in public/bgm/.
  2. Confirm the reference includes the .mp3 extension.
  3. Check the browser/Electron console for a failed media request.
  4. Confirm the volume sliders are above zero.
  5. Interact with the page if the browser has blocked autoplay.

Gallery and recovered frames

Gallery metadata is generated from STORY_GALLERY_SCENES in src/script.ts.

Each gallery entry contains:

  • sceneId
  • label
  • background
  • description

Background IDs are resolved through backgrounds.json before being used as CSS image URLs. This is important: bg_dream_lounge is a logical ID, while backgrounds/bg_dream_lounge.png is the actual browser asset.

Recovered-frame presentation:

  • Cards use monochrome filtering.
  • Cards use aspect-ratio: 16 / 9.
  • Unvisited frames remain sealed.
  • Recovered frames can open in a modal preview.
  • The preview uses a liquid-glass overlay and an opaque backdrop.

Flowchart

FlowchartScreen.tsx creates a graph from:

  • Explicit scene choices.
  • Explicit nextScene transitions.
  • Runtime edges for content that is authored separately but connected conceptually at runtime.

Ending IDs are explicitly recognized so separate endings remain separate nodes. If a new side route or ending is added:

  1. Add the scene to the appropriate story JSON file.
  2. Ensure an authored or runtime edge can reach it.
  3. Add it to ending detection if it should be marked as an ending.
  4. Confirm it appears in the flowchart after rebuilding.

Achievements

Achievement definitions live in src/achievements.ts.

Achievement conditions are functions receiving the current game state. Common conditions include:

  • Visiting a scene.
  • Reaching an ending.
  • Collecting evidence.
  • Visiting every gallery scene.
  • Visiting every authored story scene.

Achievement unlock handling is idempotent:

  • Already-unlocked achievements are ignored.
  • Newly unlocked IDs are deduplicated.
  • Notifications are announced once.
  • Unlocks are persisted immediately to autosave.

Accessibility and controls

Keyboard controls

Input Action
Space Advance dialogue or finish typing.
1 to 4 Select the corresponding choice.
Escape Open the pause menu during gameplay.
Ctrl+S Create a quick save.
Ctrl+L Open save/load.
F11 Toggle browser fullscreen when supported.
Ctrl+0 Reset browser zoom in Electron.
Ctrl+Plus / Ctrl+Minus Blocked in Electron to prevent accidental permanent scaling.

Preferences

The game includes options for:

  • Text speed.
  • Auto-play speed.
  • Master volume.
  • BGM volume.
  • SFX volume.
  • Reduced motion.
  • UI scale.
  • Text size.
  • High contrast.
  • Color-blind-safe markers.
  • Focus mode.
  • Default main-menu music.

Testing and validation

Run TypeScript validation:

npm run lint

Run the full test suite:

npm test

Create a production build:

npm run build

Validate the Electron main process syntax:

node --check electron/main.cjs

Before publishing, run at least:

npm run lint
npm test
npm run build
node --check electron/main.cjs

The production build may report a Vite warning about a JavaScript chunk larger than 500 kB. This is a bundle-size warning, not a build failure. Code splitting can be introduced later if startup performance requires it.

Windows packaging and release

Direct Electron Builder commands

Build the standard Windows targets:

npm run dist:win

Build a portable executable:

npm run dist:portable

Release automation

The release script validates the version, updates package.json, runs TypeScript validation and the production build, then creates:

  • Portable .exe.
  • NSIS installer .exe.
  • ZIP containing both executables.

Run it with a semantic version:

npm run release:windows -- 1.0.0

Prerelease versions are also supported:

npm run release:windows -- 1.0.0-beta.1

Artifacts are written to:

release/<version>/

The release script uses temporary staging folders and removes them after packaging.

Troubleshooting

The game appears zoomed out

In the Electron build, restart the application. The main process resets Chromium zoom level and zoom factor to 100%. Ctrl+0 also resets zoom.

The wrong menu music plays

Open Preferences and select the desired default main-menu track. Settings are saved to penacony_settings. If an old autosave contains a different music setting, the dedicated settings record takes precedence.

Music stops after one play

All synchronized BGM tracks are configured to loop. Check the media filename and browser/Electron console if playback still stops.

Gallery images do not appear

Confirm that:

  • The scene has a valid bg ID.
  • The ID exists in backgrounds.json.
  • The mapped asset exists under public/backgrounds/.
  • The production build includes the asset.

Saves do not load

Invalid scene IDs, negative dialogue indexes, and malformed save objects are rejected. Use the save screen to delete a corrupted slot and create a new save.

Side content is unavailable

Some side content depends on main-story completion. Resetting progress removes the completion flag and intentionally locks that content again.

Changes do not appear in Electron

The Electron command loads the dist/ directory. Rebuild before launching:

npm run build
npx electron .

Development guidelines

When adding story content:

  1. Use stable, descriptive scene IDs.
  2. Keep destination scene IDs valid.
  3. Add backgrounds to backgrounds.json.
  4. Add music to public/bgm/ before referencing it.
  5. Add character portrait mappings when introducing new emotions.
  6. Check the flowchart for new branches.
  7. Check the gallery if the scene has a recoverable background.
  8. Add achievement logic only when the unlock condition is deterministic.
  9. Run TypeScript validation and a production build.
  10. Test a fresh game, a resumed game, reset progress, and a route ending.

When modifying UI:

  • Preserve keyboard and screen-reader labels.
  • Keep scrollable sections constrained with min-height: 0.
  • Avoid broad CSS overrides that unintentionally affect modal layers.
  • Verify z-index and opaque backgrounds for overlays.
  • Test both browser development mode and Electron production mode.

License and attribution

The project is governed by the project-specific copyright and fan-work notice in [LICENSE].

YOKAILAB owns the original source code, writing, story structure, scene design, game logic, user-interface work, and other material created specifically for this project, subject to any asset-specific notices.

The character identities, names, designs, portraits, and character artwork derived from Honkai: Star Rail are third-party material. They are used only in this unofficial, non-commercial fan project and are not claimed as YOKAILAB's property. Honkai: Star Rail and related intellectual property belong to their respective rights holders, including HoYoverse/COGNOSPHERE and their licensors, as applicable.

Dreams & Dice is not affiliated with, sponsored by, endorsed by, or approved by HoYoverse, COGNOSPHERE, or any other rights holder. The license does not grant permission to copy, distribute, modify, or commercially use third-party Honkai: Star Rail material. Review the complete [LICENSE] before publishing or redistributing the project.

About

A fan-made Visual Novel of Penacony (Honkai Star Rail)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors