Thank you for your interest in contributing to ggterm! This document provides guidelines and instructions for contributing.
- Bun (v1.0+) - for package management and running
- Node.js 18+ (for compatibility testing)
- Git
# Clone the repository
git clone https://github.com/shandley/ggterm.git
cd ggterm
# Install dependencies
bun install
# Run tests
bun test
# Build
bun run buildggterm is a single package with a layered architecture. The grammar primitives (Layer 1) produce a PlotSpec that rendering backends (Layer 2) consume independently.
ggterm/
├── packages/
│ └── core/ # Everything: grammar, renderers, CLI, export
│ └── src/
│ ├── types.ts # PlotSpec and all core interfaces
│ ├── grammar.ts # gg() fluent builder API
│ ├── geoms/ # 66 geometry implementations
│ ├── scales/ # 75 scale implementations
│ ├── stats/ # Statistical transforms
│ ├── coords/ # Coordinate systems
│ ├── facets/ # Faceting (wrap, grid)
│ ├── themes/ # Theme definitions
│ ├── pipeline/ # Terminal rendering backend
│ │ └── pipeline.ts # PlotSpec → Canvas → ANSI string
│ ├── export/ # Vega-Lite backend
│ │ └── vega-lite.ts # PlotSpec → VegaLiteSpec → JSON
│ ├── canvas/ # Abstract canvas buffer
│ ├── history/ # Plot history with provenance
│ ├── cli-plot.ts # CLI tool (npx ggterm-plot)
│ ├── cli.ts # Interactive REPL (npx ggterm)
│ ├── serve.ts # Live viewer server (SSE)
│ ├── init.ts # Skill/project installer
│ └── __tests__/ # All tests (2158)
├── examples/ # AI-forward vignettes
├── docs/ # Technical documentation
└── paper/ # bioRxiv preprint
main- primary branchfeature/*- feature branches (merge tomain)fix/*- bug fix branches
- Fork the repository
- Create a branch from
main:git checkout -b feature/my-feature main
- Make your changes with clear, incremental commits
- Write tests for new functionality
- Update documentation as needed
- Submit a pull request to
main
Follow conventional commits:
type(scope): description
[optional body]
[optional footer]
Types:
feat- new featurefix- bug fixdocs- documentationstyle- formattingrefactor- code restructuringtest- adding testschore- maintenance tasks
Examples:
feat(geoms): add geom_waterfall geometry
fix(pipeline): correct aspect ratio calculation for faceted plots
docs(architecture): update PlotSpec boundary diagram
- Use TypeScript strict mode
- Prefer
interfaceovertypefor object shapes - Export types alongside implementations
- Use descriptive variable names
// Good
interface ScaleOptions {
limits?: [number, number]
breaks?: number[]
}
function createScale(options: ScaleOptions): Scale {
// ...
}
// Avoid
type Opts = { l?: number[], b?: number[] }- 2 space indentation
- Single quotes
- No semicolons
- 100 character line width
# All tests
bun test
# Watch mode
bun test --watch
# Coverage
bun test --coveragePlace tests in __tests__ directories or use .test.ts suffix:
import { describe, it, expect } from 'bun:test'
import { gg, geom_point } from '../src'
describe('gg builder', () => {
it('creates a plot with data', () => {
const data = [{ x: 1, y: 2 }]
const plot = gg(data).aes({ x: 'x', y: 'y' })
expect(plot.data).toEqual(data)
})
it('adds geom layers', () => {
const plot = gg([]).aes({ x: 'x', y: 'y' }).geom(geom_point())
expect(plot.geoms).toHaveLength(1)
})
})For renderer tests, use snapshot testing:
import { expect, it } from 'bun:test'
import { gg, geom_point } from '../src'
it('renders scatter plot correctly', () => {
const plot = gg(data).aes({ x: 'x', y: 'y' }).geom(geom_point())
const output = plot.render({ width: 40, height: 20, colorMode: 'truecolor' })
expect(output).toMatchSnapshot()
})- Create file in
packages/core/src/geoms/ - Implement the geometry interface:
export interface Geom { type: string render(data: DataPoint[], scales: Scales, canvas: Canvas): void }
- Add tests
- Export from
packages/core/src/geoms/index.ts - Update documentation
- Create file in
packages/core/src/scales/ - Implement the scale interface:
export interface Scale { type: 'continuous' | 'discrete' aesthetic: string domain: Domain range: Range map(value: unknown): number | string invert(position: number): unknown }
- Add tests
- Export and document
New backends consume PlotSpec from types.ts and produce output in a target format. There are no separate renderer packages — backends live inside packages/core/src/.
Reference implementations:
- Terminal backend:
pipeline/pipeline.ts—PlotSpec→ Canvas → ANSI string - Vega-Lite backend:
export/vega-lite.ts—PlotSpec→ Vega-Lite JSON
To add a new backend:
- Create a new file (e.g.,
export/svg.ts) - Write a function that takes
PlotSpecand returns your target format - Reuse stat/scale computation from
pipeline.tswhere possible - Add tests and export
- Update
docs/API.mdfor API changes - Update
docs/ARCHITECTURE.mdfor structural changes - Add examples for new features
- Keep
README.mdcurrent
- Title: Use conventional commit format
- Description: Explain what and why
- Tests: Ensure all tests pass
- Review: Address feedback promptly
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Tests added/updated
- [ ] All tests passing
- [ ] Manual testing performed
## Checklist
- [ ] Code follows style guidelines
- [ ] Documentation updated
- [ ] No new warningsReleases follow semantic versioning:
- Major: Breaking changes
- Minor: New features, backwards compatible
- Patch: Bug fixes
Releases are automated via GitHub Actions when tags are pushed:
# Create release
git tag v0.3.10
git push origin v0.3.10- Issues: For bugs and feature requests
- Discussions: For questions and ideas
Be respectful and inclusive. We follow the Contributor Covenant.
By contributing, you agree that your contributions will be licensed under the MIT License.