fuelcard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/15.png ADDED
Binary file
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Fuelcard 🔥
2
+
3
+ ![Fuelcard Banner](./assets/banner.png)
4
+
5
+ > **The Most Advanced Discord Music Card Generator**
6
+ >
7
+ > By **Ramkrishna** & **ZayDocs**
8
+
9
+ ---
10
+
11
+ ## 🚀 Features
12
+
13
+ - 🎨 **4 Premium Themes** - Fuelex, Classic, Neon, Flame
14
+ - 🦊 **Unique Mascot** - Cyber-fox branding with golden flames
15
+ - ⚡ **High Performance** - Native canvas bindings (@napi-rs/canvas)
16
+ - 🎵 **Universal Compatibility** - Works with DisTube, Riffy, Shoukaku, Erela.js
17
+ - 📦 **Simple API** - Async functions with clean options
18
+
19
+ ---
20
+
21
+ ## 📦 Installation
22
+
23
+ ```bash
24
+ npm install fuelcard
25
+ ```
26
+
27
+ ---
28
+
29
+ ## 🎨 Themes
30
+
31
+ | Theme | Description |
32
+ |-------|-------------|
33
+ | **Fuelex** | Main theme with large mascot on the right |
34
+ | **Classic** | Dark background with orange accents |
35
+ | **Neon** | Glowing cyan/magenta cyberpunk effects |
36
+ | **Flame** | Fire gradient with corner mascot |
37
+
38
+ ---
39
+
40
+ ## 💻 Quick Start
41
+
42
+ ```javascript
43
+ import { Fuelex, Classic, Neon, Flame } from 'fuelcard';
44
+
45
+ // Generate a Fuelex card (recommended)
46
+ const card = await Fuelex({
47
+ thumbnail: 'https://...album-art.jpg',
48
+ trackName: 'Blinding Lights',
49
+ artistName: 'The Weeknd',
50
+ progress: 52,
51
+ startTime: '1:45',
52
+ endTime: '3:22'
53
+ });
54
+
55
+ // Use with Discord.js
56
+ import { AttachmentBuilder } from 'discord.js';
57
+ const attachment = new AttachmentBuilder(card, { name: 'now-playing.png' });
58
+ await channel.send({ files: [attachment] });
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 🎵 Integration Examples
64
+
65
+ ### DisTube
66
+ ```javascript
67
+ client.distube.on('playSong', async (queue, song) => {
68
+ const card = await Fuelex({
69
+ thumbnail: song.thumbnail,
70
+ trackName: song.name,
71
+ artistName: song.uploader?.name || 'Unknown',
72
+ progress: 0,
73
+ startTime: '0:00',
74
+ endTime: song.formattedDuration
75
+ });
76
+
77
+ queue.textChannel.send({
78
+ files: [new AttachmentBuilder(card, { name: 'now-playing.png' })]
79
+ });
80
+ });
81
+ ```
82
+
83
+ ### Riffy / Lavalink
84
+ ```javascript
85
+ client.riffy.on('trackStart', async (player, track) => {
86
+ const card = await Fuelex({
87
+ thumbnail: track.thumbnail,
88
+ trackName: track.title,
89
+ artistName: track.author,
90
+ progress: 0,
91
+ startTime: '0:00',
92
+ endTime: formatTime(track.length)
93
+ });
94
+
95
+ channel.send({
96
+ files: [new AttachmentBuilder(card, { name: 'now-playing.png' })]
97
+ });
98
+ });
99
+ ```
100
+
101
+ ---
102
+
103
+ ## ⚙️ Theme Options
104
+
105
+ ### Fuelex Options
106
+ ```javascript
107
+ await Fuelex({
108
+ thumbnail: string | Buffer, // Album art (required)
109
+ trackName: string, // Song title
110
+ artistName: string, // Artist name
111
+ progress: number, // 0-100
112
+ startTime: string, // e.g., '1:45'
113
+ endTime: string, // e.g., '3:22'
114
+ backgroundColor: string, // Hex color (default: '#1a1a2e')
115
+ accentColor: string // Hex color (default: '#ff6b00')
116
+ });
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 📄 License
122
+
123
+ **Private & Proprietary** - © 2026 Ramkrishna & ZayDocs
124
+
125
+ This package is closed-source. Unauthorized distribution is prohibited.
@@ -0,0 +1,76 @@
1
+ <svg width="900" height="280" viewBox="0 0 900 280" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <!-- Gold gradient -->
4
+ <linearGradient id="goldGradient" x1="0%" y1="0%" x2="100%" y2="100%">
5
+ <stop offset="0%" style="stop-color:#FFD700"/>
6
+ <stop offset="50%" style="stop-color:#FFA500"/>
7
+ <stop offset="100%" style="stop-color:#FF6B00"/>
8
+ </linearGradient>
9
+
10
+ <!-- Text glow filter -->
11
+ <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
12
+ <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
13
+ <feMerge>
14
+ <feMergeNode in="coloredBlur"/>
15
+ <feMergeNode in="SourceGraphic"/>
16
+ </feMerge>
17
+ </filter>
18
+
19
+ <!-- Border glow -->
20
+ <filter id="borderGlow" x="-10%" y="-10%" width="120%" height="120%">
21
+ <feGaussianBlur stdDeviation="4" result="blur"/>
22
+ <feMerge>
23
+ <feMergeNode in="blur"/>
24
+ <feMergeNode in="SourceGraphic"/>
25
+ </feMerge>
26
+ </filter>
27
+ </defs>
28
+
29
+ <!-- Background -->
30
+ <rect width="900" height="280" rx="20" fill="#0a0a0a"/>
31
+
32
+ <!-- Subtle gradient overlay -->
33
+ <rect width="900" height="280" rx="20" fill="url(#goldGradient)" opacity="0.05"/>
34
+
35
+ <!-- Gold border -->
36
+ <rect x="3" y="3" width="894" height="274" rx="18" stroke="url(#goldGradient)" stroke-width="3" fill="none" filter="url(#borderGlow)"/>
37
+
38
+ <!-- Inner subtle border -->
39
+ <rect x="8" y="8" width="884" height="264" rx="15" stroke="#FFD700" stroke-width="1" fill="none" opacity="0.3"/>
40
+
41
+ <!-- FUELCARD Text -->
42
+ <text x="50" y="150" font-family="Arial, sans-serif" font-size="90" font-weight="bold" fill="url(#goldGradient)" filter="url(#glow)">
43
+ FUELCARD
44
+ </text>
45
+
46
+ <!-- Subtitle -->
47
+ <text x="55" y="200" font-family="Arial, sans-serif" font-size="24" fill="#888888">
48
+ The Most Advanced Music Card Generator
49
+ </text>
50
+
51
+ <!-- Version badge -->
52
+ <rect x="50" y="220" width="60" height="24" rx="12" fill="url(#goldGradient)" opacity="0.8"/>
53
+ <text x="80" y="237" font-family="Arial, sans-serif" font-size="12" fill="#0a0a0a" text-anchor="middle" font-weight="bold">v1.0.0</text>
54
+
55
+ <!-- Authors -->
56
+ <text x="130" y="237" font-family="Arial, sans-serif" font-size="14" fill="#666666">
57
+ By Ramkrishna &amp; ZayDocs
58
+ </text>
59
+
60
+ <!-- Decorative flame elements -->
61
+ <circle cx="520" cy="140" r="3" fill="#FF6B00" opacity="0.6">
62
+ <animate attributeName="opacity" values="0.6;1;0.6" dur="2s" repeatCount="indefinite"/>
63
+ </circle>
64
+ <circle cx="540" cy="130" r="2" fill="#FFD700" opacity="0.5">
65
+ <animate attributeName="opacity" values="0.5;1;0.5" dur="1.5s" repeatCount="indefinite"/>
66
+ </circle>
67
+ <circle cx="530" cy="155" r="2.5" fill="#FFA500" opacity="0.7">
68
+ <animate attributeName="opacity" values="0.7;1;0.7" dur="1.8s" repeatCount="indefinite"/>
69
+ </circle>
70
+
71
+ <!-- Fire emoji placeholder for animation -->
72
+ <text x="560" y="180" font-size="40" opacity="0.15">🔥</text>
73
+
74
+ <!-- Mascot area indicator (actual mascot will be embedded) -->
75
+ <rect x="620" y="20" width="260" height="240" rx="15" fill="none" stroke="#FFD700" stroke-width="1" opacity="0.2" stroke-dasharray="5,5"/>
76
+ </svg>
Binary file
Binary file
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Generate banner with mascot for README
3
+ */
4
+
5
+ import { createCanvas, loadImage } from '@napi-rs/canvas';
6
+ import { cropImage } from 'cropify';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import { fileURLToPath } from 'url';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+
14
+ async function generateBanner() {
15
+ console.log('╔═══════════════════════════════════════════════════════════════╗');
16
+ console.log('║ FUELCARD BANNER GENERATOR ║');
17
+ console.log('╚═══════════════════════════════════════════════════════════════╝');
18
+ console.log();
19
+
20
+ const width = 900;
21
+ const height = 280;
22
+
23
+ const canvas = createCanvas(width, height);
24
+ const ctx = canvas.getContext('2d');
25
+
26
+ // Background
27
+ ctx.fillStyle = '#0a0a0a';
28
+ ctx.beginPath();
29
+ ctx.roundRect(0, 0, width, height, 20);
30
+ ctx.fill();
31
+
32
+ // Gold gradient border
33
+ const borderGradient = ctx.createLinearGradient(0, 0, width, height);
34
+ borderGradient.addColorStop(0, '#FFD700');
35
+ borderGradient.addColorStop(0.5, '#FFA500');
36
+ borderGradient.addColorStop(1, '#FF6B00');
37
+
38
+ // Outer glow effect
39
+ ctx.shadowColor = '#FFD700';
40
+ ctx.shadowBlur = 20;
41
+ ctx.strokeStyle = borderGradient;
42
+ ctx.lineWidth = 4;
43
+ ctx.beginPath();
44
+ ctx.roundRect(3, 3, width - 6, height - 6, 18);
45
+ ctx.stroke();
46
+ ctx.shadowBlur = 0;
47
+
48
+ // Inner subtle border
49
+ ctx.strokeStyle = 'rgba(255, 215, 0, 0.3)';
50
+ ctx.lineWidth = 1;
51
+ ctx.beginPath();
52
+ ctx.roundRect(10, 10, width - 20, height - 20, 15);
53
+ ctx.stroke();
54
+
55
+ // FUELCARD text with glow
56
+ ctx.shadowColor = '#FFD700';
57
+ ctx.shadowBlur = 15;
58
+ ctx.font = 'bold 85px Arial';
59
+
60
+ // Create gradient for text
61
+ const textGradient = ctx.createLinearGradient(50, 80, 500, 160);
62
+ textGradient.addColorStop(0, '#FFD700');
63
+ textGradient.addColorStop(0.5, '#FFA500');
64
+ textGradient.addColorStop(1, '#FF6B00');
65
+
66
+ ctx.fillStyle = textGradient;
67
+ ctx.fillText('FUELCARD', 50, 145);
68
+ ctx.shadowBlur = 0;
69
+
70
+ // Subtitle
71
+ ctx.fillStyle = '#888888';
72
+ ctx.font = '22px Arial';
73
+ ctx.fillText('The Most Advanced Music Card Generator', 55, 195);
74
+
75
+ // Version badge
76
+ ctx.fillStyle = '#FF6B00';
77
+ ctx.beginPath();
78
+ ctx.roundRect(50, 215, 65, 26, 13);
79
+ ctx.fill();
80
+
81
+ ctx.fillStyle = '#0a0a0a';
82
+ ctx.font = 'bold 13px Arial';
83
+ ctx.textAlign = 'center';
84
+ ctx.fillText('v1.0.0', 82, 233);
85
+ ctx.textAlign = 'left';
86
+
87
+ // Authors
88
+ ctx.fillStyle = '#666666';
89
+ ctx.font = '15px Arial';
90
+ ctx.fillText('By Ramkrishna & ZayDocs', 130, 233);
91
+
92
+ // Load and draw mascot
93
+ try {
94
+ const mascotPath = path.join(__dirname, 'assets', 'mascot.png');
95
+ const mascotImage = await loadImage(mascotPath);
96
+
97
+ // Draw mascot large on the right
98
+ const mascotSize = 250;
99
+ const mascotX = width - mascotSize - 30;
100
+ const mascotY = (height - mascotSize) / 2 + 10;
101
+
102
+ ctx.drawImage(mascotImage, mascotX, mascotY, mascotSize, mascotSize);
103
+
104
+ console.log('✓ Mascot loaded and drawn');
105
+ } catch (e) {
106
+ console.log('✗ Mascot not found:', e.message);
107
+ }
108
+
109
+ // Add some flame particles
110
+ const particles = [
111
+ { x: 530, y: 130, r: 4, color: '#FF6B00' },
112
+ { x: 550, y: 120, r: 3, color: '#FFD700' },
113
+ { x: 540, y: 145, r: 3.5, color: '#FFA500' },
114
+ { x: 560, y: 135, r: 2.5, color: '#FF6B00' },
115
+ { x: 545, y: 155, r: 3, color: '#FFD700' },
116
+ ];
117
+
118
+ particles.forEach(p => {
119
+ ctx.beginPath();
120
+ ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
121
+ ctx.fillStyle = p.color;
122
+ ctx.globalAlpha = 0.7;
123
+ ctx.fill();
124
+ });
125
+ ctx.globalAlpha = 1;
126
+
127
+ // Save banner
128
+ const outputPath = path.join(__dirname, 'assets', 'banner.png');
129
+
130
+ // Crop with rounded corners
131
+ const finalImage = await cropImage({
132
+ imagePath: canvas.toBuffer('image/png'),
133
+ width: width,
134
+ height: height,
135
+ borderRadius: 25
136
+ });
137
+
138
+ fs.writeFileSync(outputPath, finalImage);
139
+ console.log('✓ Banner saved:', outputPath);
140
+
141
+ console.log();
142
+ console.log('═══════════════════════════════════════════════════════════════');
143
+ }
144
+
145
+ generateBanner().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "fuelcard",
3
+ "version": "1.0.0",
4
+ "description": "The most advanced Discord music card generator - stunning visual cards for your music bot",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "scripts": {
8
+ "test": "node test.js"
9
+ },
10
+ "keywords": [
11
+ "discord",
12
+ "music",
13
+ "card",
14
+ "musicard",
15
+ "lavalink",
16
+ "riffy",
17
+ "distube",
18
+ "canvas",
19
+ "image",
20
+ "generator"
21
+ ],
22
+ "author": "Ramkrishna & ZayDocs",
23
+ "license": "UNLICENSED",
24
+ "engines": {
25
+ "node": ">=18.0.0"
26
+ },
27
+ "dependencies": {
28
+ "@napi-rs/canvas": "^0.1.83",
29
+ "cropify": "^2.0.1"
30
+ }
31
+ }
package/src/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ╔═══════════════════════════════════════════════════════════════╗
3
+ * ║ FUELCARD ║
4
+ * ║ The Most Advanced Discord Music Card Generator ║
5
+ * ║ ║
6
+ * ║ By Ramkrishna & ZayDocs ║
7
+ * ╚═══════════════════════════════════════════════════════════════╝
8
+ *
9
+ * @module fuelcard
10
+ * @private
11
+ */
12
+
13
+ // Main themes (like reference cards with mascot)
14
+ export { Fuego } from './themes/Fuego.js'; // Orange/Gold
15
+ export { Aqua } from './themes/Aqua.js'; // Blue/Cyan
16
+ export { Rosa } from './themes/Rosa.js'; // Pink/Magenta
17
+ export { Oscuro } from './themes/Oscuro.js'; // Dark with accent
18
+
19
+ // Premium themes
20
+ export { Flame } from './themes/Flame.js'; // Fire gradient
21
+ export { Fuelex } from './themes/Fuelex.js'; // Wide with mascot
22
+
23
+ // Version info
24
+ export const version = '1.0.0';
25
+ export const authors = ['Ramkrishna', 'ZayDocs'];
@@ -0,0 +1,156 @@
1
+ /**
2
+ * ╔═══════════════════════════════════════════════════════════════╗
3
+ * ║ FUELCARD - Aqua Theme ║
4
+ * ║ Blue/Cyan theme with mascot (like reference cards) ║
5
+ * ╚═══════════════════════════════════════════════════════════════╝
6
+ */
7
+
8
+ import { createCanvas, loadImage } from '@napi-rs/canvas';
9
+ import { cropImage } from 'cropify';
10
+ import path from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ const MASCOT_PATH = path.join(__dirname, '../../assets/mascot.png');
17
+
18
+ /**
19
+ * Generate an Aqua-styled music card (blue/cyan like reference)
20
+ */
21
+ export const Aqua = async ({
22
+ thumbnail,
23
+ trackName = 'Unknown Track',
24
+ artistName = 'Unknown Artist',
25
+ progress = 0,
26
+ startTime = '0:00',
27
+ endTime = '0:00'
28
+ }) => {
29
+ const width = 600;
30
+ const height = 170;
31
+
32
+ if (trackName.length > 22) trackName = trackName.substring(0, 19) + '...';
33
+ if (artistName.length > 28) artistName = artistName.substring(0, 25) + '...';
34
+
35
+ const safeProgress = Math.min(Math.max(progress, 0), 100);
36
+
37
+ const canvas = createCanvas(width, height);
38
+ const ctx = canvas.getContext('2d');
39
+
40
+ // Blue/Cyan gradient background
41
+ const bgGradient = ctx.createLinearGradient(0, 0, width, height);
42
+ bgGradient.addColorStop(0, '#3498db');
43
+ bgGradient.addColorStop(1, '#2980b9');
44
+
45
+ ctx.fillStyle = bgGradient;
46
+ ctx.beginPath();
47
+ ctx.roundRect(0, 0, width, height, 15);
48
+ ctx.fill();
49
+
50
+ // Subtle overlay
51
+ const overlay = ctx.createLinearGradient(0, 0, width, 0);
52
+ overlay.addColorStop(0, 'rgba(0,0,0,0.05)');
53
+ overlay.addColorStop(0.6, 'rgba(0,0,0,0)');
54
+ overlay.addColorStop(1, 'rgba(0,0,0,0.15)');
55
+ ctx.fillStyle = overlay;
56
+ ctx.beginPath();
57
+ ctx.roundRect(0, 0, width, height, 15);
58
+ ctx.fill();
59
+
60
+ // Thumbnail
61
+ const thumbSize = 100;
62
+ const thumbX = 20;
63
+ const thumbY = (height - thumbSize) / 2;
64
+
65
+ try {
66
+ const thumbBuffer = await cropImage({
67
+ imagePath: thumbnail,
68
+ width: thumbSize,
69
+ height: thumbSize,
70
+ borderRadius: 12
71
+ });
72
+ const thumbImage = await loadImage(thumbBuffer);
73
+
74
+ ctx.shadowColor = 'rgba(0,0,0,0.3)';
75
+ ctx.shadowBlur = 10;
76
+ ctx.shadowOffsetX = 3;
77
+ ctx.shadowOffsetY = 3;
78
+ ctx.drawImage(thumbImage, thumbX, thumbY, thumbSize, thumbSize);
79
+ ctx.shadowBlur = 0;
80
+ ctx.shadowOffsetX = 0;
81
+ ctx.shadowOffsetY = 0;
82
+ } catch (e) {
83
+ ctx.fillStyle = 'rgba(0,0,0,0.3)';
84
+ ctx.beginPath();
85
+ ctx.roundRect(thumbX, thumbY, thumbSize, thumbSize, 12);
86
+ ctx.fill();
87
+
88
+ ctx.fillStyle = '#ffffff';
89
+ ctx.font = 'bold 40px Arial';
90
+ ctx.textAlign = 'center';
91
+ ctx.textBaseline = 'middle';
92
+ ctx.fillText('♪', thumbX + thumbSize / 2, thumbY + thumbSize / 2);
93
+ }
94
+
95
+ // Text
96
+ const textX = thumbX + thumbSize + 20;
97
+ ctx.textAlign = 'left';
98
+ ctx.textBaseline = 'top';
99
+
100
+ ctx.fillStyle = '#ffffff';
101
+ ctx.font = 'bold 22px Arial';
102
+ ctx.fillText(trackName, textX, 25);
103
+
104
+ ctx.fillStyle = 'rgba(255,255,255,0.7)';
105
+ ctx.font = '16px Arial';
106
+ ctx.fillText(artistName, textX, 55);
107
+
108
+ // Progress bar
109
+ const progressX = textX;
110
+ const progressY = 95;
111
+ const progressWidth = 200;
112
+ const progressHeight = 8;
113
+ const actualProgress = (safeProgress / 100) * progressWidth;
114
+
115
+ ctx.fillStyle = 'rgba(0,0,0,0.2)';
116
+ ctx.beginPath();
117
+ ctx.roundRect(progressX, progressY, progressWidth, progressHeight, 4);
118
+ ctx.fill();
119
+
120
+ if (safeProgress > 0) {
121
+ ctx.fillStyle = '#ffffff';
122
+ ctx.beginPath();
123
+ ctx.roundRect(progressX, progressY, actualProgress, progressHeight, 4);
124
+ ctx.fill();
125
+ }
126
+
127
+ // Timestamps
128
+ ctx.fillStyle = 'rgba(255,255,255,0.6)';
129
+ ctx.font = '12px Arial';
130
+ ctx.textAlign = 'left';
131
+ ctx.fillText(startTime, progressX, progressY + 14);
132
+ ctx.textAlign = 'right';
133
+ ctx.fillText(endTime, progressX + progressWidth, progressY + 14);
134
+
135
+ // Mascot
136
+ try {
137
+ const mascotImage = await loadImage(MASCOT_PATH);
138
+ const mascotHeight = 190;
139
+ const mascotWidth = 190;
140
+ const mascotX = width - mascotWidth + 40;
141
+ const mascotY = height - mascotHeight + 15;
142
+
143
+ ctx.drawImage(mascotImage, mascotX, mascotY, mascotWidth, mascotHeight);
144
+ } catch (e) { }
145
+
146
+ const finalImage = await cropImage({
147
+ imagePath: canvas.toBuffer('image/png'),
148
+ width: width,
149
+ height: height,
150
+ borderRadius: 20
151
+ });
152
+
153
+ return finalImage;
154
+ };
155
+
156
+ export default Aqua;