An open API service indexing awesome lists of open source software.

https://github.com/Spectrewolf8/isometric-contributions-embeds

Generate beautiful 3D isometric visualizations of GitHub contribution graphs. Available as both a CLI tool and a fast, cached API.
https://github.com/Spectrewolf8/isometric-contributions-embeds

3d-contribution-graph contributions contributions-graph isometric-contributions isometric-graphics visualizations

Last synced: 3 months ago
JSON representation

Generate beautiful 3D isometric visualizations of GitHub contribution graphs. Available as both a CLI tool and a fast, cached API.

Awesome Lists containing this project

README

          

# logo Isometric Contributions

Generate beautiful 3D isometric visualizations of GitHub contribution graphs. Available as both a CLI tool and a fast, cached API server.

## Examples



GitHub Theme

GitHub Theme


Light Theme

Light Theme


Dark Theme

Dark Theme




Neon Theme

Neon Theme


Ocean Theme

Ocean Theme


Minimal Theme

Minimal Theme




Without Stats

Without Stats


Without Credit

Without Credit


Default Theme

One Year




365-Day Rolling Window

365-Day Rolling Window (Default)



## Features

- โšก **Fast API** with intelligent caching and revalidation
- ๐ŸŽจ **6 Built-in Themes**: GitHub, Dark, Light, Neon, Minimal, Ocean
- ๐Ÿ“Š **Statistics Overlay**: Contributions, streaks, averages
- ๐Ÿ–ผ๏ธ **Customizable**: Dimensions, year selection, credits, themes
- ๐Ÿš€ **Minimal**: Lightweight with no framework overhead
- ๐Ÿ’พ **Smart Caching**: Efficient daily caching with instant updates
- ๐Ÿ“… **365-Day Rolling Window**: Default view showing last 365 days of activity

## Installation

```bash
npm install
```

## Quick Start

### CLI Usage

Generate an isometric contribution graph:

```bash
npm run generate -- [year] [output] [options]
```

**Examples:**

```bash
# Basic usage
npm run generate -- spectrewolf8

# Specific year with stats
npm run generate -- spectrewolf8 2025 graph.png --stats --credit

# Custom dimensions
npm run generate -- spectrewolf8 2025 graph.png --width 1920 --height 1080
```

**CLI Options:**

- `--stats` - Include statistics overlay
- `--credit` - Show username in bottom right
- `--width ` - Canvas width (default: 1000)
- `--height ` - Canvas height (default: 600)

### API Server

Start the API server for web integration:

```bash
npm run server
```

Or with auto-reload during development:

```bash
npm run dev
```

Server runs on port 3000 (configurable via `PORT` environment variable).

## API Documentation

### Endpoint

```
GET /api/graph
```

### Query Parameters

| Parameter | Type | Required | Default | Description |
| ---------- | ------------- | -------- | ----------------- | ------------------------------------------------------------------------------- |
| `username` | string | โœ… Yes | - | GitHub username |
| `year`/`y` | number/string | No | `none` (365 days) | Year to fetch (e.g., `2025`), or `none` for 365-day rolling window ending today |
| `theme` | string | No | `github` | Visual theme: `github`, `dark`, `light`, `neon`, `minimal`, `ocean` |
| `width` | number | No | `1000` | Image width in pixels |
| `height` | number | No | `600` | Image height in pixels |
| `stats` | boolean | No | `false` | Include statistics overlay |
| `credit` | boolean | No | `false` | Show username credit |

### API Examples

**Basic Graph:**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8
```

**With Statistics:**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&stats=true
```

**365-Day Rolling Window (Default):**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8
```

**Specific Year:**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&year=2025
```

**With Theme:**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&theme=dark&stats=true
```

**With Credit:**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&credit=true
```

**Full Customization:**

```
https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&year=2025&width=1200&height=700&stats=true&credit=true&theme=neon
```

> **Note:** Use `http://localhost:3000` for local testing.

### Caching

The API implements intelligent daily caching:

- **Cache Duration**: 1 hour with revalidation (ensures freshness)
- **Cache Strategy**: One generation per username+params per day
- **Cache Headers**: Check `X-Cache` header (`HIT` or `MISS`)
- **Benefits**: Instant responses for repeated requests with fresh updates

**Cache Response Headers:**

```
Content-Type: image/png
Content-Length:
Cache-Control: public, max-age=3600, must-revalidate
X-Cache: HIT | MISS
```

### Additional Endpoints

**Documentation:**

```
GET /
GET /docs
```

**Health Check:**

```
GET /health
```

## Programmatic Usage

### Fetch Contributions

```javascript
import {
fetchContributions,
parseContributionsData,
} from "./src/api-client.js";

const data = await fetchContributions("username", 2025);
const days = parseContributionsData(data);
```

### Render Image

```javascript
import { renderIsometricChart, exportToPNG, setTheme } from "./src/renderer.js";
import { DARK_THEME } from "./src/theme-config.js";
import { writeFileSync } from "fs";

// Set theme (optional)
setTheme(DARK_THEME);

// Render
const canvas = renderIsometricChart(days, {
width: 1000,
height: 600,
username: "spectrewolf8", // optional credit
});

// Export
const buffer = await exportToPNG(canvas);
writeFileSync("output.png", buffer);
```

### With Statistics

```javascript
import { renderWithStats } from "./src/renderer.js";

const canvas = renderWithStats(days, {
width: 1000,
height: 600,
});
```

### Available Themes

```javascript
import {
GITHUB_THEME,
DARK_THEME,
LIGHT_THEME,
NEON_THEME,
MINIMAL_THEME,
OCEAN_THEME,
} from "./src/theme-config.js";
import { setTheme } from "./src/renderer.js";

// Apply theme before rendering
setTheme(NEON_THEME);
```

## Embedding in README

### Markdown

```markdown
![GitHub Contributions](https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&stats=true)
```

**With theme:**

```markdown
![GitHub Contributions](https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8&theme=dark&stats=true)
```

### HTML

```html
GitHub Contributions
```

## Scripts

| Command | Description |
| --------------------------- | --------------------------------- |
| `npm run generate` | Generate graph via CLI |
| `npm run server` | Start API server |
| `npm run dev` | Start server with auto-reload |
| `npm run test:api` | Test API endpoints |
| `npm run cleanup` | Manually run cache cleanup |
| `npm run cleanup:scheduler` | Start automatic cleanup scheduler |

## Output

Generates PNG images with:

- **Resolution**: Customizable (default 1000x600)
- **Format**: PNG with transparency
- **Size**: ~20-30 KB (varies with dimensions)

### Statistics Displayed

- Total contributions
- Best day (max contributions)
- Average per day
- Longest streak
- Current streak

## Cache Management

The project includes automatic cache cleanup to remove old files from Supabase Storage.

### Setup

1. **Add environment variables to `.env`:**

```env
SUPABASE_ANON_KEY=your-anon-key
CACHE_RETENTION_DAYS=1
CLEANUP_SCHEDULE=0 3 * * * # Daily at 3 AM
RUN_ON_STARTUP=true
TZ=UTC
```

2. **Add DELETE policy to Supabase (one-time setup):**

Run this in your Supabase SQL Editor:

```sql
CREATE POLICY "Anon delete access"
ON storage.objects
FOR DELETE
TO anon
USING (bucket_id = 'isometric-cache');

GRANT DELETE ON storage.objects TO anon;
```

3. **Start the scheduler:**
```bash
npm run cleanup:scheduler
```

The scheduler runs automatically in Docker/production (see [Dockerfile](Dockerfile)).

### Manual Cleanup

Run cleanup on-demand:

```bash
npm run cleanup
```

### Cron Schedule Examples

- `0 3 * * *` - Daily at 3 AM
- `0 */6 * * *` - Every 6 hours
- `0 */12 * * *` - Every 12 hours
- `*/30 * * * *` - Every 30 minutes
- `0 0 * * 0` - Weekly on Sunday at midnight

### How It Works

The cleanup script:

1. Lists all files in the Supabase Storage bucket
2. Checks each file against retention criteria:
- Files with `created_at` older than retention period
- Files in date folders (e.g., `username/2026-02-01/`) older than retention
- `.emptyFolderPlaceholder` files
3. Deletes matching files using Supabase Storage API
4. Logs results with counts and examples

### Production Deployment

**Docker/Render/Railway:**

The Dockerfile automatically starts both processes:

```dockerfile
CMD ["sh", "-c", "node server.js & node cleanup-scheduler.js & wait"]
```

Just add the environment variables to your hosting platform.

## Troubleshooting

### Cache Cleanup Issues

**No files deleted:**

- Check `CACHE_RETENTION_DAYS` - files must be older than this
- Verify DELETE policy is set up in Supabase (see setup step 2)
- Check file dates in Supabase dashboard

**Permission errors:**

- Ensure DELETE policy exists for anon role on storage.objects
- Run the setup SQL in Supabase SQL Editor (see Cache Management section)
- Verify bucket name matches `SUPABASE_BUCKET_NAME`

**Scheduler not running:**

- Verify cron expression is valid
- Check timezone setting (`TZ` environment variable)
- Ensure process stays running (use PM2 or Docker)
- Check logs: `pm2 logs cache-cleanup` (if using PM2)

**Manual testing:**

```bash
# Test cleanup manually
npm run cleanup

# With different retention
CACHE_RETENTION_DAYS=7 npm run cleanup
```

**Check cleanup logs:**

The cleanup script outputs logs:

```
๐Ÿงน Cleaning cache (retention: 1 day(s))
๐Ÿ“… Deleting folders older than 2026-02-02
โœ… No old folders to delete

โœจ Cleanup completed
```

## Acknowledgements

This project builds upon the excellent work of:

- **Core Renderer**: Based on [isometric-contributions](https://github.com/jasonlong/isometric-contributions) by Jason Long - the foundational isometric rendering logic was taken and modified for this implementation
- **Contributions API**: Uses the [GitHub Contributions API](https://github.com/grubersjoe/github-contributions-api) by Joe Gruber - an unofficial but reliable API for fetching GitHub contribution data

## Contributing

Feel free to open issues or submit PRs for improvements!

## License

This project is licensed under the [MIT License](http://opensource.org/licenses/MIT).