Thank you for your interest in contributing to RustyNES! We welcome contributions from developers of all skill levels.
- Code of Conduct
- How Can I Contribute?
- Development Setup
- Coding Standards
- Pull Request Process
- Getting Help
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to parobek@gmail.com.
- Use the Bug Report template
- Search existing issues first to avoid duplicates
- Include system information, ROM details, and reproduction steps
- Provide logs when possible (
RUST_LOG=debug)
- Use the Feature Request template
- Clearly describe the problem and proposed solution
- Explain use cases and benefits
- Check the ROADMAP for alignment with project goals
- Use the Mapper Request template
- Provide mapper number, games that use it, and technical references
- Include NESdev wiki links and test ROM information
Areas where we especially need help:
-
Core Emulation (Phase 1 focus):
- CPU: 6502 instruction implementation
- PPU: Rendering pipeline and timing
- APU: Audio channel synthesis
- Mappers: NROM, MMC1, MMC3 implementation
-
Testing:
- Test ROM integration
- Property-based tests
- Game compatibility testing
- Benchmarking
-
Documentation:
- Code documentation (rustdoc comments)
- Examples and tutorials
- Technical specification clarifications
-
Tooling:
- CI/CD improvements
- Build scripts
- Development utilities
- Rust 1.75 or newer (install via rustup)
- SDL2 development libraries
- Git
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y build-essential git libsdl2-devFedora:
sudo dnf install gcc git SDL2-develmacOS:
brew install git sdl2Windows:
- Install Visual Studio 2019+ with C++ tools
- Download SDL2 development libraries from libsdl.org
- Set
SDL2_PATHenvironment variable
# Fork the repository on GitHub first, then:
git clone https://github.com/YOUR_USERNAME/RustyNES.git
cd RustyNES
git remote add upstream https://github.com/doublegate/RustyNES.git# Build the project
cargo build --workspace
# Run tests
cargo test --workspace
# Run a specific crate's tests
cargo test -p rustynes-cpu
# Run with optimizations
cargo build --release --workspace# Check formatting
cargo fmt --all -- --check
# Run linter
cargo clippy --workspace -- -D warnings
# Generate documentation
cargo doc --workspace --no-deps --open- Format: Use
cargo fmt(rustfmt default settings) - Lint: Pass
cargo clippy -- -D warningswithout warnings - Edition: Rust 2021
- MSRV: Minimum Supported Rust Version is 1.75
- Follow Rust naming conventions (snake_case, PascalCase)
- Use meaningful variable and function names
- Keep functions focused and concise
- Organize imports: std → external crates → internal modules
All public APIs must have documentation comments:
/// Executes one CPU instruction
///
/// This function reads the opcode at the program counter, decodes it,
/// executes the corresponding instruction, and returns the number of
/// cycles consumed.
///
/// # Arguments
///
/// * `bus` - The memory bus for reading/writing
///
/// # Returns
///
/// Number of CPU cycles consumed by the instruction
///
/// # Examples
///
/// ```
/// let mut cpu = Cpu::new();
/// let mut bus = Bus::new();
/// let cycles = cpu.step(&mut bus);
/// assert!(cycles >= 2);
/// ```
pub fn step(&mut self, bus: &mut Bus) -> u8 {
// Implementation
}- Unit tests for new functions and modules
- Integration tests for component interactions
- Test ROMs for emulation accuracy
- Minimum 80% code coverage for new code
Follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringtest: Adding/updating testschore: Build/tooling changes
Examples:
feat(cpu): implement ADC instruction with decimal mode
Adds the ADC (Add with Carry) instruction including proper
handling of the decimal flag for BCD arithmetic.
Closes #42
fix(ppu): correct sprite 0 hit timing
Sprite 0 hit was occurring one cycle too late. Adjusted
detection to occur at cycle 257 of the scanline.
Fixes #85
-
Update from upstream:
git fetch upstream git rebase upstream/main
-
Run all checks:
cargo fmt --all cargo clippy --workspace -- -D warnings cargo test --workspace -
Update documentation:
- Add/update rustdoc comments
- Update relevant markdown files in
docs/ - Add changelog entry if significant change
-
Push your branch:
git push origin feature/my-feature
-
Open a Pull Request on GitHub
-
Fill out the PR template completely
-
Ensure CI passes (automated checks must succeed)
-
Respond to review feedback promptly
- Maintainers will review your PR within 3-14 days
- Automated checks (CI) must pass
- At least one maintainer approval required
- Address all review comments
- Keep the PR scope focused
Your contribution will be:
- Included in the next release
- Documented in CHANGELOG.md
- Credited in release notes
- Documentation: docs/ folder
- Detailed Contributing Guide: docs/dev/CONTRIBUTING.md
- Build Instructions: docs/dev/BUILD.md
- Testing Guide: docs/dev/TESTING.md
- Style Guide: docs/dev/STYLE_GUIDE.md
- GitHub Discussions: General questions and ideas
- GitHub Issues: Bug reports and feature requests
- NESdev Forums: NES hardware questions
- Check issues labeled
good first issue - Check issues labeled
help wanted - Review the ROADMAP for upcoming features
- Ask in Discussions what needs help
# 1. Create a feature branch
git checkout -b feature/my-feature
# 2. Make changes
# ... edit files ...
# 3. Write tests (TDD approach recommended)
# ... add tests in src/ or tests/ ...
# 4. Run tests
cargo test
# 5. Format and lint
cargo fmt
cargo clippy -- -D warnings
# 6. Commit changes
git add .
git commit -m "feat(component): add my feature"
# 7. Push and create PR
git push origin feature/my-featureWe strongly encourage TDD:
- Write a failing test
- Implement the feature
- Make the test pass
- Refactor if needed
- Repeat
Example:
#[test]
fn test_lda_immediate() {
let mut cpu = Cpu::new();
let mut bus = Bus::new();
// LDA #$42
bus.write(0x0000, 0xA9);
bus.write(0x0001, 0x42);
let cycles = cpu.step(&mut bus);
assert_eq!(cpu.a, 0x42);
assert_eq!(cycles, 2);
assert!(!cpu.p.zero);
assert!(!cpu.p.negative);
}rustynes/
├── crates/
│ ├── rustynes-core/ # Core emulation engine
│ ├── rustynes-cpu/ # 6502 CPU
│ ├── rustynes-ppu/ # 2C02 PPU
│ ├── rustynes-apu/ # 2A03 APU
│ ├── rustynes-mappers/ # Mapper implementations
│ ├── rustynes-desktop/ # Desktop GUI
│ └── ...
├── docs/ # Documentation
├── tests/ # Integration tests
├── benches/ # Benchmarks
└── examples/ # Usage examples
See ARCHITECTURE.md for detailed system design.
Contributors will be recognized in:
- Release notes for each version
- CHANGELOG.md for significant contributions
- Project README (for substantial contributions)
By contributing to RustyNES, you agree that your contributions will be licensed under both:
- MIT License
- Apache License 2.0
See LICENSE-MIT and LICENSE-APACHE for details.
Thank you for contributing to RustyNES! Your efforts help preserve video game history and create an amazing emulation platform.
For more detailed guidelines, see docs/dev/CONTRIBUTING.md.