Getting Started

To contribute to TruchiEmu, you will need:

  • macOS: 14.0 (Sonoma) or later with Swift 5.9+
  • Xcode: Latest stable version
  • XcodeGen: brew install xcodegen
  • C++ Standard: gnu++17 / gnu17

See the Building from Source guide for a full step-by-step setup and the Contributing guide for conventions and workflow.

Build Pipeline

TruchiEmu uses XcodeGen to manage the project structure dynamically from project.yml. This prevents merge conflicts in the .xcodeproj file.

Standard Build Workflow

# 1. Clone the repository
git clone https://github.com/JuanchoGithub/truchiemu.git
cd truchiemu

# 2. Generate the Xcode project
xcodegen generate

# 3. Build
xcodebuild -project TruchiEmu.xcodeproj -scheme TruchiEmu -configuration Debug build

Or open in Xcode: open TruchiEmu.xcodeproj and press ⌘+B.

Adding Source Files

New source files under TruchiEmu/ and resources under TruchiEmu/Resources/ are automatically included via recursive paths in project.yml. Simply add your file and run xcodegen generate to regenerate the Xcode project.

If you need to exclude a directory from the build, edit project.yml and regenerate.

⚠️ Important: Only edit project.yml when adding or removing directories from the build. New source files within existing directories are auto-detected.

Project Architecture

TruchiEmu follows a modular architecture that separates the emulation engine from the native macOS UI.

App Layer

TruchiEmu/App/ Application entrypoint, window management, and ContentView.

Core Engine

TruchiEmu/Core/Engine/ Mixed Objective-C++ and C. Interfaces with libretro via a bridging header.

SwiftUI Layer

TruchiEmu/Views/ and TruchiEmu/Features/ All user interaction and visual presentation.

Services Layer

TruchiEmu/Services/ Business logic: save directories, ROM identification, API integrations.

Data Layer

TruchiEmu/Core/Models/ SwiftData models for game library, settings, and persistence.

Shared Utilities

TruchiEmu/Shared/ Cross-cutting code: theme manager, design tokens, image cache.

Emulation Core System

TruchiEmu uses a core-based architecture powered by libretro, allowing support for multiple emulation backends. Each core is an independent emulator engine that runs as a plugin.

How Cores Work

  • Specialized: Each core targets one system or family of systems
  • Independently Developed: Cores come from the libretro community
  • Regular Updates: Cores update independently of TruchiEmu
  • Swappable: Multiple cores for the same system are supported

Default Core Assignments

System Core Accuracy Performance
NES/FamicomMesen⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
SNESSnes9x⭐⭐⭐⭐⭐⭐⭐⭐⭐
Game Boy/ColorGambatte⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Game Boy AdvancemGBA⭐⭐⭐⭐⭐⭐⭐⭐
Genesis/Mega DriveGenesis Plus GX⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Nintendo 64ParaLLEl⭐⭐⭐⭐⭐⭐⭐
PlayStation 1DuckStation⭐⭐⭐⭐⭐⭐⭐⭐
ArcadeMAME 2003+⭐⭐⭐⭐⭐⭐⭐

Core Options

Each core exposes configurable options (video, audio, system-specific settings) parsed by CoreOptionsManager. Users can set overrides at multiple levels with increasing priority: core default → app default → app system default → system override → game override. Override values are persisted as .cfg files in TruchiEmu/CoreOptions/. See the Core Options documentation for the full override hierarchy.

Core Management

The integrated Core Downloader provides one-click install and update for all cores. Core options can be configured per-core, per-system, and per-game. The Swift ↔ ObjC bridge for core communication lives in LibretroBridge.mm / LibretroBridgeSwift.swift.

Swift ↔ ObjC Bridge

The emulation engine is written in Objective-C++/C for direct libretro API access. Swift code communicates with it through LibretroBridge.mm / LibretroBridgeSwift.swift, with symbols exposed through TruchiEmu-Bridging-Header.h.

Save State Integration

The core system integrates with SaveStateManager for LZ4-compressed snapshots with TCS2 headers, and SaveDirectoryManager for path resolution. Battery saves are handled automatically by the emulation core.

Deep Dive: For a detailed walkthrough of a real bug fix involving core option lifecycles, see Debugging Dreamcast VMU Saves.

Shader Pipeline

The shader system uses custom Metal shaders compiled at runtime, running directly on the GPU through Apple's Metal framework.

Key Components

  • Shader Compiler: Runtime compilation of .metal shader files with error handling
  • Parameter System: Real-time adjustment of shader uniforms via SwiftUI controls

Shader Files

Metal shaders live in TruchiEmu/Core/Shaders/. The slang/, internal/, and all_shaders.metal directories are excluded from the Xcode build these are runtime-loaded resources from TruchiEmu_Resources/core_shaders/.

Performance Characteristics

Passthrough, Scale Smooth, and Vignette have minimal GPU impact. CRT shaders (Multipass, Lottes) and LCD simulations use more GPU resources.

Theme System

The theme engine provides accent color theming across the entire app interface, powered by a pipeline of three core types.

Architecture

AccentColorTheme ThemeManager AppColors SwiftUI Views
  • AccentColorTheme Enum with 16 curated cases plus .custom (17 total). Each defines accent, dimmed (84%), dark (70%), and secondary colors for light and dark modes. Includes a migratedRawValue() system for renamed themes.
  • ThemeManager Singleton @MainActor ObservableObject that owns current theme, appearance mode, custom accent color, toolbar accent toggle, and tinted surfaces toggle. Persists all state via AppSettings (SwiftData).
  • AppColors Static semantic color tokens in DesignSystem.swift that views consume. Auto-resolves via NSApp.effectiveAppearance. Preview-safe *ForScheme variants available.
  • App Restart Theme changes call ThemeManager.relaunchApp(), spawning a new process and terminating the current one. The settings UI enforces this with confirmation dialogs and unsaved-change interception.

Adding a New Theme

  1. Add a case to AccentColorTheme enum
  2. Define accent, accentDimmed, accentDark, secondaryAccent (and optional light/dark variants)
  3. Add icon asset to Assets.xcassets/ThemeIcons/
  4. Add localization keys: settings.theme.<name> to all language JSON files
  5. If renaming, add migration mapping in migratedRawValue()

Theming Conventions

All views must use AppColors semantic tokens never hardcode color values. Tokens automatically blend the current theme's accent into surfaces, text, and borders. Check ThemeManager.shared.toolbarAccentEnabled and tintedSurfacesEnabled when applying accent colors to icons and background surfaces.

CLI Reference

TruchiEmu provides a command-line interface for launching games directly from the terminal. Handled by CLIManager and CLILauncher in the Services layer.

Launch a ROM

./TruchiEmu "/path/to/game.nes"

Testing & QA

No test target currently exists in the project. When adding tests:

  1. Create a test target in project.yml and run xcodegen generate
  2. Add test files under TruchiEmuTests/
  3. Link the SwiftData framework in the test target
  4. Some tests may require network access (LaunchBox, thumbnail services)

Further Reading

📖 Building from Source

Detailed setup instructions and troubleshooting.

Building Guide

🤝 Contributing

Conventions, code review, and pull request workflow.

Contributing

🐛 Dreamcast VMU Deep Dive

Postmortem of a complex core integration bug.

Deep Dive
Last updated: May 2026