{"_id":"@deathnaitsa/nishi-canvas","_rev":"2-c2865939ccb67439d48c8150741132f7","name":"@deathnaitsa/nishi-canvas","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@deathnaitsa/nishi-canvas","version":"1.0.0","keywords":["canvas","image","welcome-card","level-card","rank-card","profile-card","leaderboard","speech-bubble","cross-platform","discord","whatsapp","bot"],"author":{"name":"DeathNaitsa"},"license":"MIT","_id":"@deathnaitsa/nishi-canvas@1.0.0","maintainers":[{"name":"deathnaitsa","email":"sebloidl12@gmail.com"}],"homepage":"https://github.com/deathnaitsa/nishi-canvas#readme","bugs":{"url":"https://github.com/deathnaitsa/nishi-canvas/issues"},"dist":{"shasum":"3dffba05001905ee34ae495e19f61e23c576864f","tarball":"https://registry.npmjs.org/@deathnaitsa/nishi-canvas/-/nishi-canvas-1.0.0.tgz","fileCount":35,"integrity":"sha512-5nPWHzLtvEAydx3LBsB7Hum+xUvcVY9n4AhGYpvj5b9bzIwKZZf8Ab6t59YPAgQVI5g0axUBVRd5UJnuQwPHHQ==","signatures":[{"sig":"MEYCIQDuHrzihgB6bNyb7jUNDQ/aGFHyJ2jqkCxYBusJhiU7BwIhAL9VXyWlGHuhj3mewBVq9tvOiiie6SfMq+vPxdgHWd4w","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":808180},"main":"./dist/index.cjs","type":"module","module":"./dist/index.js","exports":{".":{"import":"./dist/index.js","require":"./dist/index.cjs"},"./core":{"import":"./dist/core/engine.js","require":"./dist/core/engine.cjs"},"./themes":{"import":"./dist/themes/index.js","require":"./dist/themes/index.cjs"},"./generators/level":{"import":"./dist/generators/level.js","require":"./dist/generators/level.cjs"},"./generators/bubble":{"import":"./dist/generators/bubble.js","require":"./dist/generators/bubble.cjs"},"./generators/profile":{"import":"./dist/generators/profile.js","require":"./dist/generators/profile.cjs"},"./generators/welcome":{"import":"./dist/generators/welcome.js","require":"./dist/generators/welcome.cjs"},"./generators/leaderboard":{"import":"./dist/generators/leaderboard.js","require":"./dist/generators/leaderboard.cjs"}},"scripts":{"build":"node build.js","prepublishOnly":"npm run build"},"_npmUser":{"name":"deathnaitsa","email":"sebloidl12@gmail.com"},"repository":{"url":"git+https://github.com/deathnaitsa/nishi-canvas.git","type":"git"},"_npmVersion":"10.8.2","description":"Cross-platform Canvas Adapter with built-in image generators — runs anywhere without node-gyp headaches.","directories":{},"_nodeVersion":"20.19.3","dependencies":{"@napi-rs/canvas":">=0.1.0"},"_hasShrinkwrap":false,"devDependencies":{"javascript-obfuscator":"^4.2.2"},"peerDependencies":{"canvas":">=2.0.0","skia-canvas":">=0.9.0"},"peerDependenciesMeta":{"canvas":{"optional":true},"skia-canvas":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nishi-canvas_1.0.0_1772747364218_0.9432946359569097","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@deathnaitsa/nishi-canvas","version":"1.0.1","description":"Cross-platform Canvas Adapter with built-in image generators — runs anywhere without node-gyp headaches.","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","exports":{".":{"import":"./dist/index.js","require":"./dist/index.cjs"},"./generators/welcome":{"import":"./dist/generators/welcome.js","require":"./dist/generators/welcome.cjs"},"./generators/level":{"import":"./dist/generators/level.js","require":"./dist/generators/level.cjs"},"./generators/profile":{"import":"./dist/generators/profile.js","require":"./dist/generators/profile.cjs"},"./generators/bubble":{"import":"./dist/generators/bubble.js","require":"./dist/generators/bubble.cjs"},"./generators/leaderboard":{"import":"./dist/generators/leaderboard.js","require":"./dist/generators/leaderboard.cjs"},"./themes":{"import":"./dist/themes/index.js","require":"./dist/themes/index.cjs"},"./core":{"import":"./dist/core/engine.js","require":"./dist/core/engine.cjs"}},"scripts":{"build":"node build.js","prepublishOnly":"npm run build"},"author":{"name":"DeathNaitsa"},"license":"MIT","keywords":["canvas","image","welcome-card","level-card","rank-card","profile-card","leaderboard","speech-bubble","cross-platform","discord","whatsapp","bot"],"repository":{"type":"git","url":"git+https://github.com/deathnaitsa/nishi-canvas.git"},"bugs":{"url":"https://github.com/deathnaitsa/nishi-canvas/issues"},"homepage":"https://github.com/deathnaitsa/nishi-canvas#readme","dependencies":{"@napi-rs/canvas":">=0.1.0"},"peerDependencies":{"skia-canvas":">=0.9.0","canvas":">=2.0.0"},"peerDependenciesMeta":{"skia-canvas":{"optional":true},"canvas":{"optional":true}},"devDependencies":{"javascript-obfuscator":"^4.2.2"},"_id":"@deathnaitsa/nishi-canvas@1.0.1","_nodeVersion":"20.19.3","_npmVersion":"10.8.2","dist":{"integrity":"sha512-uKEY6TCUUSBJ10CJivqpAK1HpG7h7X7JtVnesnVFHxfpabRTag9HrLwcazkIK//RKTev67ilziMR7X6BHo3QJg==","shasum":"287868966dc84ff67a8a3a910c46ff4c3160572e","tarball":"https://registry.npmjs.org/@deathnaitsa/nishi-canvas/-/nishi-canvas-1.0.1.tgz","fileCount":35,"unpackedSize":814972,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIB7OA2VdJLuaoENwbB99lgFEO8cffgfc67Hg59j3flh8AiEAyNdzRC6QaXP9D4ggzaWxD+7tJ6XXbLeTaIBfx6lB5ZM="}]},"_npmUser":{"name":"deathnaitsa","email":"sebloidl12@gmail.com"},"directories":{},"maintainers":[{"name":"deathnaitsa","email":"sebloidl12@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nishi-canvas_1.0.1_1772747737003_0.008796661587047172"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-05T21:49:24.152Z","modified":"2026-03-05T21:55:37.344Z","1.0.0":"2026-03-05T21:49:24.368Z","1.0.1":"2026-03-05T21:55:37.227Z"},"bugs":{"url":"https://github.com/deathnaitsa/nishi-canvas/issues"},"author":{"name":"DeathNaitsa"},"license":"MIT","homepage":"https://github.com/deathnaitsa/nishi-canvas#readme","keywords":["canvas","image","welcome-card","level-card","rank-card","profile-card","leaderboard","speech-bubble","cross-platform","discord","whatsapp","bot"],"repository":{"type":"git","url":"git+https://github.com/deathnaitsa/nishi-canvas.git"},"description":"Cross-platform Canvas Adapter with built-in image generators — runs anywhere without node-gyp headaches.","maintainers":[{"name":"deathnaitsa","email":"sebloidl12@gmail.com"}],"readme":"# @deathnaitsa/nishi-canvas\n\n**Cross-platform Canvas Adapter + Image Generator Kit**\n\n[![npm version](https://img.shields.io/npm/v/@deathnaitsa/nishi-canvas?color=5865F2;&style=flat-square;&logo=npm)](https://www.npmjs.com/package/@deathnaitsa/nishi-canvas)\n[![license](https://img.shields.io/npm/l/@deathnaitsa/nishi-canvas?color=57f287;&style=flat-square)](./LICENSE)\n\nRuns on Windows, Linux, macOS, WSL, Termux and Docker — zero node-gyp, zero config.  \nDrop-in replacement for `@napi-rs/canvas` with extra generators and utilities built-in.\n\n---\n\n## Installation\n\n```bash\nnpm install @deathnaitsa/nishi-canvas\n```\n\n`@napi-rs/canvas` ships as a bundled dependency with **pre-built binaries** for every platform — no compiling, no build tools required.\n\n**Want a different engine?** Just install it alongside — the adapter picks it up automatically:\n\n```bash\nnpm install skia-canvas   # higher quality Skia renderer\nnpm install canvas        # classic node-canvas (needs build tools)\n```\n\nEngine priority: `@napi-rs/canvas` → `skia-canvas` → `canvas`\n\n---\n\n## Quick Start\n\n```js\nimport Canvas from '@deathnaitsa/nishi-canvas';\n\nconst canvas = await Canvas.createCanvas(700, 250);\nconst ctx    = canvas.getContext('2d');\n\n// Extend ctx with extra utility methods\nCanvas.extendContext(ctx, canvas);\n\nctx.fillStyle = '#5865F2';\nctx.fillRoundRect(10, 10, 680, 230, 16);  // built-in polyfill\nctx.setFont(32, 'sans-serif', 'bold');    // size, family, weight in one call\nctx.fillStyle = '#ffffff';\nctx.textAlign = 'center';\nctx.textBaseline = 'middle';\nctx.fillText('Hello!', 350, 125);\n\n// Export as PNG Buffer\nconst png = await Canvas.toPNG(canvas);\n```\n\n---\n\n## Generators\n\nOne function call returns a PNG Buffer — no setup, no boilerplate.\n\n### Welcome Card\n\n```js\nimport { generateWelcome } from '@deathnaitsa/nishi-canvas';\n\nconst png = await generateWelcome({\n  avatar:      'https://cdn.discordapp.com/avatars/...',\n  username:    'Seblo',\n  serverName:  'Nishi Server',\n  memberCount: 1337,\n  theme:       'dark',        // 'dark' | 'light' | 'neon' | 'midnight'\n  accentColor: '#5865F2',     // optional override\n  welcomeText: 'WELCOME',     // optional header label\n  background:  'https://...', // image URL, hex color, or ['#color1','#color2'] gradient\n});\n```\n\n### Level / Rank Card\n\n```js\nimport { generateLevel } from '@deathnaitsa/nishi-canvas';\n\nconst png = await generateLevel({\n  avatar:   'https://...',\n  username: 'Seblo',\n  level:    42,\n  xp:       1500,\n  maxXp:    3000,\n  rank:     5,        // optional rank badge\n  theme:    'midnight',\n});\n```\n\n### Profile Card\n\n```js\nimport { generateProfile } from '@deathnaitsa/nishi-canvas';\n\nconst png = await generateProfile({\n  avatar:   'https://...',\n  banner:   'https://...',  // or '#hex' color\n  username: 'Seblo',\n  tag:      '#0001',\n  bio:      'Building cool stuff.',\n  stats:    { Level: 42, XP: '15.2k', Rank: '#5', Messages: 2847 },\n  badges:   ['Admin', 'Premium', 'Early Bird'],\n  theme:    'neon',\n});\n```\n\n### Speech Bubble\n\n```js\nimport { generateBubble } from '@deathnaitsa/nishi-canvas';\n\nconst png = await generateBubble({\n  text:    'Yo, was geht?',\n  avatar:  'https://...',  // optional avatar next to bubble\n  tailDir: 'left',         // 'left' | 'right' | 'top' | 'bottom'\n  theme:   'dark',\n});\n```\n\n### Leaderboard\n\n```js\nimport { generateLeaderboard } from '@deathnaitsa/nishi-canvas';\n\nconst png = await generateLeaderboard({\n  title: 'Top Players',\n  entries: [\n    { username: 'Seblo', value: 52000, label: 'XP', avatar: 'https://...' },\n    { username: 'Anna',  value: 41500, label: 'XP' },\n    { username: 'Max',   value: 37200, label: 'XP' },\n  ],\n  theme:      'dark',\n  maxEntries: 10,\n  width:      500,\n});\n```\n\n---\n\n## Themes\n\n| Name | Description |\n|---|---|\n| `dark` | Dark navy (default) |\n| `light` | Clean white |\n| `neon` | Black + neon green |\n| `midnight` | Deep purple |\n\n```js\nimport { registerTheme } from '@deathnaitsa/nishi-canvas';\n\n// Register a custom theme (missing keys fall back to dark)\nregisterTheme('sakura', {\n  accent:     '#ff69b4',\n  background: '#fff0f5',\n  text:       '#2c2f33',\n});\n\nconst png = await generateWelcome({ username: 'Test', theme: 'sakura' });\n\n// Or pass a plain object directly — no registration needed\nconst png2 = await generateLevel({ username: 'Test', theme: { accent: '#ff0000' } });\n```\n\n---\n\n## Extended Context API\n\nCall `Canvas.extendContext(ctx, canvas)` once to get these extra methods:\n\n| Method | Description |\n|---|---|\n| `ctx.fillRoundRect(x, y, w, h, r)` | Fill rounded rectangle |\n| `ctx.strokeRoundRect(x, y, w, h, r)` | Stroke rounded rectangle |\n| `ctx.circle(x, y, r, fill?, stroke?)` | Draw full circle |\n| `ctx.avatarCircle(img, cx, cy, r)` | Image clipped to circle |\n| `ctx.roundedImage(img, x, y, w, h, r)` | Image clipped to rounded rect |\n| `ctx.setFont(size, family, weight, style)` | Set font in one call |\n| `ctx.centeredText(text, x, y, boundWidth)` | Horizontally centered text |\n| `ctx.multilineText(text, x, y, maxW, lineH)` | Word-wrapped text |\n| `ctx.truncateText(text, maxWidth)` | Truncate with `…` |\n| `ctx.progressBar(x, y, w, h, progress, fill, bg)` | Progress bar |\n| `ctx.linearGradient(stops, x1, y1, x2, y2)` | Linear gradient from array |\n| `ctx.shadow(color, blur, offsetX, offsetY)` | Set shadow in one call |\n| `ctx.clearShadow()` | Remove all shadows |\n| `ctx.with(fn)` | `save()` → fn → `restore()` |\n| `ctx.clear()` | Clear entire canvas |\n\n---\n\n## Color Utilities\n\n```js\nimport { alpha, darken, lighten, mix, contrastColor } from '@deathnaitsa/nishi-canvas';\n\nalpha('#5865F2', 0.5)          // → 'rgba(88, 101, 242, 0.5)'\ndarken('#5865F2', 20)          // → darker hex\nlighten('#5865F2', 20)         // → lighter hex\nmix('#ff0000', '#0000ff', 0.5) // → mixed color\ncontrastColor('#5865F2')       // → '#ffffff' or '#000000' for readable contrast\n```\n\n---\n\n## Image Loading\n\nHandles any source type automatically:\n\n```js\nimport { loadImageFromAny, tryLoadImage } from '@deathnaitsa/nishi-canvas';\n\nconst img  = await loadImageFromAny('https://example.com/avatar.png'); // URL\nconst img2 = await loadImageFromAny('./local/image.png');              // local path\nconst img3 = await loadImageFromAny(someBuffer);                       // Buffer\nconst img4 = await loadImageFromAny('data:image/png;base64,...');      // Base64\n\n// Returns null on failure instead of throwing\nconst img5 = await tryLoadImage(maybeInvalidUrl);\n```\n\n---\n\n## Font Management\n\n```js\nimport { loadBuiltinFonts, registerFontFile, loadFontsFromDir } from '@deathnaitsa/nishi-canvas';\n\n// Auto-load all fonts from the fonts/ directory\nawait loadBuiltinFonts();\n\n// Register a single font manually\nawait registerFontFile('./fonts/Roboto-Bold.ttf', 'Roboto', { weight: 'bold' });\n\n// Load all fonts from a directory\nawait loadFontsFromDir('./my-fonts/');\n```\n\n---\n\n## Project Structure\n\n```\n@deathnaitsa/nishi-canvas\n├── dist/        ← Obfuscated build (ESM + CJS)\n│   ├── index.js\n│   ├── index.cjs\n│   ├── core/\n│   ├── generators/\n│   ├── themes/\n│   └── utils/\n└── fonts/       ← Drop .ttf/.otf files here\n```\n\n---\n\n## License\n\nMIT © [DeathNaitsa](https://github.com/deathnaitsa)\n","readmeFilename":"README.md"}