{"id":43438910,"url":"https://github.com/spectrewolf8/isometric-contributions-embeds","last_synced_at":"2026-02-08T02:01:15.364Z","repository":{"id":335936258,"uuid":"1147236234","full_name":"Spectrewolf8/isometric-contributions-embeds","owner":"Spectrewolf8","description":"Generate beautiful 3D isometric visualizations of GitHub contribution graphs. Available as both a CLI tool and a fast, cached API.","archived":false,"fork":false,"pushed_at":"2026-02-03T16:10:10.000Z","size":3104,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-07T09:56:34.433Z","etag":null,"topics":["3d-contribution-graph","contributions","contributions-graph","isometric-contributions","isometric-graphics","visualizations"],"latest_commit_sha":null,"homepage":"https://isometric-contributions-spectrewolf8.onrender.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Spectrewolf8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-01T12:34:39.000Z","updated_at":"2026-02-07T05:30:34.000Z","dependencies_parsed_at":"2026-02-03T22:00:39.016Z","dependency_job_id":null,"html_url":"https://github.com/Spectrewolf8/isometric-contributions-embeds","commit_stats":null,"previous_names":["spectrewolf8/isometric-contributions-embeds"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Spectrewolf8/isometric-contributions-embeds","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Spectrewolf8%2Fisometric-contributions-embeds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Spectrewolf8%2Fisometric-contributions-embeds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Spectrewolf8%2Fisometric-contributions-embeds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Spectrewolf8%2Fisometric-contributions-embeds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Spectrewolf8","download_url":"https://codeload.github.com/Spectrewolf8/isometric-contributions-embeds/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Spectrewolf8%2Fisometric-contributions-embeds/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29217757,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T00:10:47.190Z","status":"online","status_checked_at":"2026-02-08T02:00:07.642Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d-contribution-graph","contributions","contributions-graph","isometric-contributions","isometric-graphics","visualizations"],"created_at":"2026-02-02T21:29:22.584Z","updated_at":"2026-02-08T02:01:15.325Z","avatar_url":"https://github.com/Spectrewolf8.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"media/assets/icon-128.png\" alt=\"logo\" width=\"40\" height=\"40\" style=\"vertical-align: middle;\"\u003e Isometric Contributions\n\nGenerate beautiful 3D isometric visualizations of GitHub contribution graphs. Available as both a CLI tool and a fast, cached API server.\n\n## Examples\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output.png\" width=\"300\" alt=\"Default Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eDefault\u003c/b\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-github.png\" width=\"300\" alt=\"GitHub Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eGitHub Theme\u003c/b\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-dark.png\" width=\"300\" alt=\"Dark Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eDark Theme\u003c/b\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-neon.png\" width=\"300\" alt=\"Neon Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eNeon Theme\u003c/b\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-ocean.png\" width=\"300\" alt=\"Ocean Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eOcean Theme\u003c/b\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-minimal.png\" width=\"300\" alt=\"Minimal Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eMinimal Theme\u003c/b\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-not-stats.png\" width=\"300\" alt=\"Without Stats\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eWithout Stats\u003c/b\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-no-credit.png\" width=\"300\" alt=\"With Credit\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eWithout Credit\u003c/b\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg src=\"media/examples/output-light.png\" width=\"300\" alt=\"Light Theme\"/\u003e\u003cbr/\u003e\n      \u003cb\u003eLight Theme\u003c/b\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Features\n\n- ⚡ **Fast API** with intelligent caching and revalidation\n- 🎨 **6 Built-in Themes**: GitHub, Dark, Light, Neon, Minimal, Ocean\n- 📊 **Statistics Overlay**: Contributions, streaks, averages\n- 🖼️ **Customizable**: Dimensions, year selection, credits, themes\n- 🚀 **Minimal**: Lightweight with no framework overhead\n- 💾 **Smart Caching**: Efficient daily caching with instant updates\n- 🎯 **Single Year Focus**: Clean graphs for one year at a time\n- 🐳 **Docker Ready**: Easy deployment on Render, Railway, or any platform\n\n## Installation\n\n```bash\nnpm install\n```\n\n## Quick Start\n\n### CLI Usage\n\nGenerate an isometric contribution graph:\n\n```bash\nnpm run generate -- \u003cusername\u003e [year] [output] [options]\n```\n\n**Examples:**\n\n```bash\n# Basic usage\nnpm run generate -- spectrewolf8\n\n# Specific year with stats\nnpm run generate -- spectrewolf8 2025 graph.png --stats --credit\n\n# Custom dimensions\nnpm run generate -- spectrewolf8 2025 graph.png --width 1920 --height 1080\n```\n\n**CLI Options:**\n\n- `--stats` - Include statistics overlay\n- `--credit` - Show username in bottom right\n- `--width \u003cpx\u003e` - Canvas width (default: 1000)\n- `--height \u003cpx\u003e` - Canvas height (default: 600)\n\n### API Server\n\nStart the API server for web integration:\n\n```bash\nnpm run server\n```\n\nOr with auto-reload during development:\n\n```bash\nnpm run dev\n```\n\nServer runs on port 3000 (configurable via `PORT` environment variable).\n\n## API Documentation\n\n### Endpoint\n\n```\nGET /api/graph\n```\n\n### Query Parameters\n\n| Parameter  | Type    | Required | Default      | Description                                                         |\n| ---------- | ------- | -------- | ------------ | ------------------------------------------------------------------- |\n| `username` | string  | ✅ Yes   | -            | GitHub username                                                     |\n| `year`/`y` | number  | No       | current year | Year to fetch contributions for (supports aliases)                  |\n| `theme`    | string  | No       | `github`     | Visual theme: `github`, `dark`, `light`, `neon`, `minimal`, `ocean` |\n| `width`    | number  | No       | `1000`       | Image width in pixels                                               |\n| `height`   | number  | No       | `600`        | Image height in pixels                                              |\n| `stats`    | boolean | No       | `false`      | Include statistics overlay                                          |\n| `credit`   | boolean | No       | `false`      | Show username credit                                                |\n\n### API Examples\n\n**Basic Graph:**\n\n```\nhttps://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\n```\n\n**With Statistics:**\n\n```\nhttps://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026stats=true\n```\n\n**Specific Year:**\n\n```\nhttps://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026year=2025\n```\n\n**With Theme:**\n\n```\nhttps://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026theme=dark\u0026stats=true\n```\n\n**With Credit:**\n\n```\nhttps://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026credit=true\n```\n\n**Full Customization:**\n\n```\nhttps://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026year=2025\u0026width=1200\u0026height=700\u0026stats=true\u0026credit=true\u0026theme=neon\n```\n\n\u003e **Note:** Replace `your-app.onrender.com` with your actual deployment URL. Use `http://localhost:3000` for local testing.\n\n### Caching\n\nThe API implements intelligent daily caching:\n\n- **Cache Duration**: 1 hour with revalidation (ensures freshness)\n- **Cache Strategy**: One generation per username+params per day\n- **Cache Headers**: Check `X-Cache` header (`HIT` or `MISS`)\n- **Benefits**: Instant responses for repeated requests with fresh updates\n\n**Cache Response Headers:**\n\n```\nContent-Type: image/png\nContent-Length: \u003cbytes\u003e\nCache-Control: public, max-age=3600, must-revalidate\nX-Cache: HIT | MISS\n```\n\n### Additional Endpoints\n\n**Documentation:**\n\n```\nGET /\nGET /docs\n```\n\n**Health Check:**\n\n```\nGET /health\n```\n\n## Programmatic Usage\n\n### Fetch Contributions\n\n```javascript\nimport {\n  fetchContributions,\n  parseContributionsData,\n} from \"./src/api-client.js\";\n\nconst data = await fetchContributions(\"username\", 2025);\nconst days = parseContributionsData(data);\n```\n\n### Render Image\n\n```javascript\nimport { renderIsometricChart, exportToPNG, setTheme } from \"./src/renderer.js\";\nimport { DARK_THEME } from \"./src/theme-config.js\";\nimport { writeFileSync } from \"fs\";\n\n// Set theme (optional)\nsetTheme(DARK_THEME);\n\n// Render\nconst canvas = renderIsometricChart(days, {\n  width: 1000,\n  height: 600,\n  username: \"spectrewolf8\", // optional credit\n});\n\n// Export\nconst buffer = await exportToPNG(canvas);\nwriteFileSync(\"output.png\", buffer);\n```\n\n### With Statistics\n\n```javascript\nimport { renderWithStats } from \"./src/renderer.js\";\n\nconst canvas = renderWithStats(days, {\n  width: 1000,\n  height: 600,\n});\n```\n\n### Available Themes\n\n```javascript\nimport {\n  GITHUB_THEME,\n  DARK_THEME,\n  LIGHT_THEME,\n  NEON_THEME,\n  MINIMAL_THEME,\n  OCEAN_THEME,\n} from \"./src/theme-config.js\";\nimport { setTheme } from \"./src/renderer.js\";\n\n// Apply theme before rendering\nsetTheme(NEON_THEME);\n```\n\n## Deployment\n\n### Deploy on Render (Recommended)\n\nThis project is optimized for Render deployment with Docker support.\n\n**Quick Deploy:**\n\n1. Push to GitHub\n2. Create new Web Service on [Render](https://render.com)\n3. Connect your repo and select **Docker** environment\n4. Add environment variables:\n\n- `SUPABASE_URL`\n- `SUPABASE_ANON_KEY`\n- `SUPABASE_BUCKET_NAME`\n\n5. Deploy!\n\n**Why Docker?**\nThe `canvas` package requires system libraries (Cairo, Pango) that are automatically installed via the Dockerfile.\n\n### Minimal Deployment (Docker CLI)\n\n```bash\n# Build image\ndocker build -t isometric-contributions .\n\n# Run container with required env vars\ndocker run -p 3000:3000 \\\n  -e SUPABASE_URL=your-url \\\n  -e SUPABASE_ANON_KEY=your-anon-key \\\n  -e SUPABASE_BUCKET_NAME=isometric-cache \\\n  isometric-contributions\n```\n\n### Other Platforms\n\nThe Docker setup works on any platform supporting containers (Railway, Fly.io, Cloud Run, ECS, Azure Container Apps).\n\n## Embedding in README\n\n### Markdown\n\n```markdown\n![GitHub Contributions](https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026stats=true)\n```\n\n**With theme:**\n\n```markdown\n![GitHub Contributions](https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026theme=dark\u0026stats=true)\n```\n\n### HTML\n\n```html\n\u003cimg\n  src=\"https://isometric-contributions-spectrewolf8.onrender.com/api/graph?username=spectrewolf8\u0026theme=neon\u0026stats=true\"\n  alt=\"GitHub Contributions\"\n/\u003e\n```\n\n## Scripts\n\n| Command                     | Description                       |\n| --------------------------- | --------------------------------- |\n| `npm run generate`          | Generate graph via CLI            |\n| `npm run server`            | Start API server                  |\n| `npm run dev`               | Start server with auto-reload     |\n| `npm run test:api`          | Test API endpoints                |\n| `npm run cleanup`           | Manually run cache cleanup        |\n| `npm run cleanup:scheduler` | Start automatic cleanup scheduler |\n\n## Output\n\nGenerates PNG images with:\n\n- **Resolution**: Customizable (default 1000x600)\n- **Format**: PNG with transparency\n- **Size**: ~20-30 KB (varies with dimensions)\n\n### Statistics Displayed\n\n- Total contributions\n- Best day (max contributions)\n- Average per day\n- Longest streak\n- Current streak\n\n## Cache Management\n\nThe project includes automatic cache cleanup to remove old files from Supabase Storage.\n\n### Setup\n\n1. **Add environment variables to `.env`:**\n\n   ```env\n   SUPABASE_ANON_KEY=your-anon-key\n   CACHE_RETENTION_DAYS=1\n   CLEANUP_SCHEDULE=0 3 * * *  # Daily at 3 AM\n   RUN_ON_STARTUP=true\n   TZ=UTC\n   ```\n\n2. **Add DELETE policy to Supabase (one-time setup):**\n\n   Run this in your Supabase SQL Editor:\n\n   ```sql\n   CREATE POLICY \"Anon delete access\"\n     ON storage.objects\n     FOR DELETE\n     TO anon\n     USING (bucket_id = 'isometric-cache');\n\n   GRANT DELETE ON storage.objects TO anon;\n   ```\n\n3. **Start the scheduler:**\n   ```bash\n   npm run cleanup:scheduler\n   ```\n\nThe scheduler runs automatically in Docker/production (see [Dockerfile](Dockerfile)).\n\n### Manual Cleanup\n\nRun cleanup on-demand:\n\n```bash\nnpm run cleanup\n```\n\n### Cron Schedule Examples\n\n- `0 3 * * *` - Daily at 3 AM\n- `0 */6 * * *` - Every 6 hours\n- `0 */12 * * *` - Every 12 hours\n- `*/30 * * * *` - Every 30 minutes\n- `0 0 * * 0` - Weekly on Sunday at midnight\n\n### How It Works\n\nThe cleanup script:\n\n1. Lists all files in the Supabase Storage bucket\n2. Checks each file against retention criteria:\n   - Files with `created_at` older than retention period\n   - Files in date folders (e.g., `username/2026-02-01/`) older than retention\n   - `.emptyFolderPlaceholder` files\n3. Deletes matching files using Supabase Storage API\n4. Logs results with counts and examples\n\n### Production Deployment\n\n**With PM2 (process manager):**\n\n```bash\n# Start server\npm2 start server.js --name api\n\n# Start cleanup scheduler\npm2 start cleanup-scheduler.js --name cache-cleanup\n\n# Save configuration\npm2 save\n\n# Setup startup script\npm2 startup\n```\n\n**Docker/Render/Railway:**\n\nThe Dockerfile automatically starts both processes:\n\n```dockerfile\nCMD [\"sh\", \"-c\", \"node server.js \u0026 node cleanup-scheduler.js \u0026 wait\"]\n```\n\nJust add the environment variables to your hosting platform.\n\n## Troubleshooting\n\n### Cache Cleanup Issues\n\n**No files deleted:**\n\n- Check `CACHE_RETENTION_DAYS` - files must be older than this\n- Verify DELETE policy is set up in Supabase (see setup step 2)\n- Check file dates in Supabase dashboard\n\n**Permission errors:**\n\n- Ensure DELETE policy exists for anon role on storage.objects\n- Run the setup SQL in Supabase SQL Editor (see Cache Management section)\n- Verify bucket name matches `SUPABASE_BUCKET_NAME`\n\n**Scheduler not running:**\n\n- Verify cron expression is valid\n- Check timezone setting (`TZ` environment variable)\n- Ensure process stays running (use PM2 or Docker)\n- Check logs: `pm2 logs cache-cleanup` (if using PM2)\n\n**Manual testing:**\n\n```bash\n# Test cleanup manually\nnpm run cleanup\n\n# With different retention\nCACHE_RETENTION_DAYS=7 npm run cleanup\n```\n\n**Check cleanup logs:**\n\nThe cleanup script outputs detailed logs:\n\n```\n🧹 Starting cache cleanup...\n📅 Retention: 1 day(s)\n📦 Bucket: isometric-cache\n🔪 Cutoff date: 2026-02-01\n📊 Total files: 27\n🎯 Files to delete: 5\n✅ Successfully deleted 5 file(s)\n   🗑️  spectrewolf8/2026-02-01/abc123.png\n   ...\n```\n\n## Acknowledgements\n\nThis project builds upon the excellent work of:\n\n- **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\n- **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\n\n## Contributing\n\nFeel free to open issues or submit PRs for improvements!\n\n## License\n\nThis project is licensed under the [MIT License](http://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspectrewolf8%2Fisometric-contributions-embeds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspectrewolf8%2Fisometric-contributions-embeds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspectrewolf8%2Fisometric-contributions-embeds/lists"}