Developer Guide
A technical reference for contributors architecture, emulation cores, build pipeline, and deep dives
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/Famicom | Mesen | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| SNES | Snes9x | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Game Boy/Color | Gambatte | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Game Boy Advance | mGBA | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Genesis/Mega Drive | Genesis Plus GX | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Nintendo 64 | ParaLLEl | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| PlayStation 1 | DuckStation | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Arcade | MAME 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
.metalshader 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 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 amigratedRawValue()system for renamed themes. - ThemeManager Singleton
@MainActor ObservableObjectthat owns current theme, appearance mode, custom accent color, toolbar accent toggle, and tinted surfaces toggle. Persists all state viaAppSettings(SwiftData). - AppColors Static semantic color tokens in
DesignSystem.swiftthat views consume. Auto-resolves viaNSApp.effectiveAppearance. Preview-safe*ForSchemevariants 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
- Add a case to
AccentColorThemeenum - Define accent, accentDimmed, accentDark, secondaryAccent (and optional light/dark variants)
- Add icon asset to
Assets.xcassets/ThemeIcons/ - Add localization keys:
settings.theme.<name>to all language JSON files - 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:
- Create a test target in
project.ymland runxcodegen generate - Add test files under
TruchiEmuTests/ - Link the
SwiftDataframework in the test target - Some tests may require network access (LaunchBox, thumbnail services)