# Contributing to Pixelsrc
Welcome! Pixelsrc is designed to be approachable for contributors, including AI agents.
---
## Quick Start
### Prerequisites
- Rust (stable, 1.70+)
- Cargo
### Setup
```bash
# Clone the repo
git clone <repo-url>
cd pixelsrc
# Build
cargo build
# Run tests
cargo test
# Run the CLI
cargo run -- render examples/coin.jsonl -o coin.png
```
---
## Project Structure
```
pixelsrc/
├── docs/
│ ├── VISION.md # Why we're building this, core tenets
│ ├── ANNOUNCEMENT.md # Product positioning
│ ├── spec/
│ │ └── format.md # Formal JSONL specification
│ └── plan/ # Implementation phases (see README.md)
├── CONTRIBUTING.md # This file
├── Cargo.toml # Rust package config
├── src/
│ ├── main.rs # Entry point
│ ├── cli.rs # Clap-based CLI
│ ├── parser.rs # JSONL parsing + validation
│ ├── renderer.rs # PNG/GIF generation via `image` crate
│ └── models.rs # Serde structs for palette, sprite, animation
├── examples/ # Example .jsonl files
├── tests/
│ └── fixtures/
│ ├── valid/ # Files that should parse successfully
│ ├── invalid/ # Files that should fail (missing fields, bad JSON)
│ └── lenient/ # Files with warnings (work in default, fail in --strict)
```
---
## Key Documents
Before contributing, read these:
1. **docs/VISION.md** - Understand the "why" and core tenets
2. **docs/spec/format.md** - Formal specification for the JSONL format
3. **docs/plan/README.md** - See what phase we're in and what's planned
4. **docs/plan/phase-0-mvp.md** - Detailed task breakdown for MVP
---
## Code Conventions
### Rust Style
- Follow standard `rustfmt` formatting
- Use `clippy` for linting: `cargo clippy`
- Prefer explicit error types over `unwrap()` in library code
- `unwrap()` is acceptable in tests and examples
### Error Handling
Pixelsrc has two modes:
- **Lenient (default)**: Fill gaps, warn, continue
- **Strict (`--strict`)**: Fail on first warning
When implementing error handling:
```rust
// Good: Return a warning that can be collected
fn parse_row(...) -> (Vec<Token>, Vec<Warning>) { ... }
// Let the caller decide: warn or fail based on mode
```
### Testing
- Add fixtures for new features in `tests/fixtures/`
- Valid fixtures go in `valid/`
- Invalid fixtures (should error) go in `invalid/`
- Lenient fixtures (warn but succeed) go in `lenient/`
Each fixture should be a minimal reproduction of the case it tests.
### Coverage
We track test coverage via [Codecov](https://codecov.io). Coverage targets:
- **Project coverage**: 70% (overall codebase)
- **Patch coverage**: 80% (new/modified code in PRs)
To generate coverage locally:
```bash
# Install cargo-llvm-cov (one-time)
cargo install cargo-llvm-cov
# Generate coverage report (text summary)
just coverage
# Generate and open HTML report
just coverage-html
# Generate LCOV format (for tooling)
just coverage-lcov
```
Coverage reports are automatically generated in CI and uploaded to Codecov.
---
## Development Workflow
### Adding a Feature
1. Check if there's a task/issue for it
2. Read relevant spec in `spec/format.md`
3. Write failing tests first
4. Implement the feature
5. Ensure `cargo test` passes
6. Run `cargo clippy` and fix warnings
7. Submit PR
### Modifying the Spec
If you need to change `spec/format.md`:
1. Discuss the change first (open an issue)
2. Update the spec
3. Update affected code
4. Update/add fixtures to cover the change
---
## Test Fixtures Reference
### Valid Fixtures (`tests/fixtures/valid/`)
| `minimal_dot.jsonl` | Smallest valid sprite (1x1) |
| `simple_heart.jsonl` | Basic multi-row sprite |
| `named_palette.jsonl` | Palette defined separately, referenced by name |
| `with_size.jsonl` | Explicit size declaration |
| `multiple_sprites.jsonl` | Multiple sprites sharing a palette |
| `color_formats.jsonl` | All supported color formats (#RGB, #RRGGBB, etc.) |
| `animation.jsonl` | Animation with frames and timing |
### Invalid Fixtures (`tests/fixtures/invalid/`)
| `missing_type.jsonl` | Missing required `type` field |
| `missing_name.jsonl` | Missing required `name` field |
| `missing_grid.jsonl` | Missing required `grid` field |
| `missing_palette.jsonl` | Missing required `palette` field |
| `invalid_json.jsonl` | Malformed JSON |
| `unknown_palette_ref.jsonl` | References undefined palette |
| `invalid_color.jsonl` | Color value not a valid hex |
### Lenient Fixtures (`tests/fixtures/lenient/`)
| `row_too_short.jsonl` | Row has fewer tokens than width | Pad with `{_}` |
| `row_too_long.jsonl` | Row has more tokens than width | Truncate |
| `unknown_token.jsonl` | Token not in palette | Render as magenta |
| `duplicate_name.jsonl` | Two sprites with same name | Last wins |
| `extra_chars_in_grid.jsonl` | Characters outside `{...}` | Ignore |
---
## CLI Reference
```bash
# Render sprites to PNG
pxl render input.jsonl # Output: input_{name}.png
pxl render input.jsonl -o output.png # Output: output.png (single) or output_{name}.png
pxl render input.jsonl -o dir/ # Output: dir/{name}.png
pxl render input.jsonl --sprite hero # Render only "hero"
# Strict mode (fail on warnings)
pxl render input.jsonl --strict
# Animation (Phase 2)
pxl render input.jsonl --gif -o anim.gif
pxl render input.jsonl --spritesheet -o sheet.png
# Palettes (Phase 1)
pxl palettes list
pxl palettes show gameboy
```
---
## For AI Agents
If you're an AI agent working on Pixelsrc:
1. **Read the spec first** - `spec/format.md` has all the rules
2. **Check fixtures** - They show expected behavior for edge cases
3. **Lenient by default** - When in doubt, warn and continue
4. **Minimal changes** - Don't over-engineer; simple solutions preferred
5. **Test your changes** - Add fixtures for new cases
The codebase is designed to be straightforward. Most tasks are isolated to single files.
---
## Creating Releases
Releases are automated via GitHub Actions. To create a new release:
### 1. Update Version
Update the version in `Cargo.toml`:
```toml
[package]
version = "0.2.0" # Bump appropriately
```
### 2. Commit and Tag
```bash
git add Cargo.toml
git commit -m "Bump version to v0.2.0"
git tag v0.2.0
git push origin main --tags
```
### 3. What Happens
The release workflow automatically:
- Builds binaries for 6 platforms:
- Linux (x86_64, aarch64)
- macOS (x86_64, aarch64)
- Windows (x86_64, aarch64)
- Generates SHA256 checksums
- Creates a GitHub Release with all assets
### 4. Verify
After pushing the tag:
1. Check [Actions](../../actions) tab for workflow progress
2. Once complete, verify the [Releases](../../releases) page has all artifacts
3. Download and test a binary on your platform
### Release Assets
Each release includes:
- `pxl-v{version}-x86_64-unknown-linux-gnu.tar.gz`
- `pxl-v{version}-aarch64-unknown-linux-gnu.tar.gz`
- `pxl-v{version}-x86_64-apple-darwin.tar.gz`
- `pxl-v{version}-aarch64-apple-darwin.tar.gz`
- `pxl-v{version}-x86_64-pc-windows-msvc.zip`
- `pxl-v{version}-aarch64-pc-windows-msvc.zip`
- `SHA256SUMS.txt`
---
## Questions?
- Check existing issues
- Read VISION.md for design philosophy
- Open an issue for clarification