apexify.js 4.6.2 → 4.7.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.
Files changed (129) hide show
  1. package/dist/cjs/ai/ApexModules.d.ts.map +1 -1
  2. package/dist/cjs/ai/ApexModules.js +56 -7
  3. package/dist/cjs/ai/ApexModules.js.map +1 -1
  4. package/dist/cjs/ai/functions/readFiles.js +1 -1
  5. package/dist/cjs/ai/functions/readFiles.js.map +1 -1
  6. package/dist/cjs/ai/modals-chat/electronHub/chatmodels.d.ts.map +1 -1
  7. package/dist/cjs/ai/modals-chat/electronHub/chatmodels.js +2 -1
  8. package/dist/cjs/ai/modals-chat/electronHub/chatmodels.js.map +1 -1
  9. package/dist/cjs/ai/modals-chat/electronHub/speechModels.d.ts.map +1 -1
  10. package/dist/cjs/ai/modals-chat/electronHub/speechModels.js +1 -1
  11. package/dist/cjs/ai/modals-chat/electronHub/speechModels.js.map +1 -1
  12. package/dist/cjs/canvas/ApexPainter.d.ts.map +1 -1
  13. package/dist/cjs/canvas/ApexPainter.js +27 -28
  14. package/dist/cjs/canvas/ApexPainter.js.map +1 -1
  15. package/dist/cjs/canvas/Themes/Level-Up/levelup.d.ts +11 -0
  16. package/dist/cjs/canvas/Themes/Level-Up/levelup.d.ts.map +1 -0
  17. package/dist/cjs/canvas/Themes/Level-Up/levelup.js +163 -0
  18. package/dist/cjs/canvas/Themes/Level-Up/levelup.js.map +1 -0
  19. package/dist/cjs/canvas/utils/Background/bg.d.ts +17 -10
  20. package/dist/cjs/canvas/utils/Background/bg.d.ts.map +1 -1
  21. package/dist/cjs/canvas/utils/Background/bg.js +102 -27
  22. package/dist/cjs/canvas/utils/Background/bg.js.map +1 -1
  23. package/dist/cjs/canvas/utils/Custom/customLines.d.ts.map +1 -1
  24. package/dist/cjs/canvas/utils/Custom/customLines.js +43 -19
  25. package/dist/cjs/canvas/utils/Custom/customLines.js.map +1 -1
  26. package/dist/cjs/canvas/utils/General/general functions.d.ts +6 -1
  27. package/dist/cjs/canvas/utils/General/general functions.d.ts.map +1 -1
  28. package/dist/cjs/canvas/utils/General/general functions.js +19 -20
  29. package/dist/cjs/canvas/utils/General/general functions.js.map +1 -1
  30. package/dist/cjs/canvas/utils/Image/imageProperties.d.ts +3 -9
  31. package/dist/cjs/canvas/utils/Image/imageProperties.d.ts.map +1 -1
  32. package/dist/cjs/canvas/utils/Image/imageProperties.js +220 -214
  33. package/dist/cjs/canvas/utils/Image/imageProperties.js.map +1 -1
  34. package/dist/cjs/canvas/utils/Texts/textProperties.d.ts +12 -14
  35. package/dist/cjs/canvas/utils/Texts/textProperties.d.ts.map +1 -1
  36. package/dist/cjs/canvas/utils/Texts/textProperties.js +100 -91
  37. package/dist/cjs/canvas/utils/Texts/textProperties.js.map +1 -1
  38. package/dist/cjs/canvas/utils/types.d.ts +89 -109
  39. package/dist/cjs/canvas/utils/types.d.ts.map +1 -1
  40. package/dist/cjs/canvas/utils/types.js.map +1 -1
  41. package/dist/cjs/canvas/utils/utils.d.ts +2 -4
  42. package/dist/cjs/canvas/utils/utils.d.ts.map +1 -1
  43. package/dist/cjs/canvas/utils/utils.js +2 -5
  44. package/dist/cjs/canvas/utils/utils.js.map +1 -1
  45. package/dist/cjs/index.d.ts.map +1 -1
  46. package/dist/cjs/index.js +31 -3
  47. package/dist/cjs/index.js.map +1 -1
  48. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  49. package/dist/esm/ai/ApexModules.d.ts.map +1 -1
  50. package/dist/esm/ai/ApexModules.js +56 -7
  51. package/dist/esm/ai/ApexModules.js.map +1 -1
  52. package/dist/esm/ai/functions/readFiles.js +1 -1
  53. package/dist/esm/ai/functions/readFiles.js.map +1 -1
  54. package/dist/esm/ai/modals-chat/electronHub/chatmodels.d.ts.map +1 -1
  55. package/dist/esm/ai/modals-chat/electronHub/chatmodels.js +2 -1
  56. package/dist/esm/ai/modals-chat/electronHub/chatmodels.js.map +1 -1
  57. package/dist/esm/ai/modals-chat/electronHub/speechModels.d.ts.map +1 -1
  58. package/dist/esm/ai/modals-chat/electronHub/speechModels.js +1 -1
  59. package/dist/esm/ai/modals-chat/electronHub/speechModels.js.map +1 -1
  60. package/dist/esm/canvas/ApexPainter.d.ts.map +1 -1
  61. package/dist/esm/canvas/ApexPainter.js +27 -28
  62. package/dist/esm/canvas/ApexPainter.js.map +1 -1
  63. package/dist/esm/canvas/Themes/Level-Up/levelup.d.ts +11 -0
  64. package/dist/esm/canvas/Themes/Level-Up/levelup.d.ts.map +1 -0
  65. package/dist/esm/canvas/Themes/Level-Up/levelup.js +163 -0
  66. package/dist/esm/canvas/Themes/Level-Up/levelup.js.map +1 -0
  67. package/dist/esm/canvas/utils/Background/bg.d.ts +17 -10
  68. package/dist/esm/canvas/utils/Background/bg.d.ts.map +1 -1
  69. package/dist/esm/canvas/utils/Background/bg.js +102 -27
  70. package/dist/esm/canvas/utils/Background/bg.js.map +1 -1
  71. package/dist/esm/canvas/utils/Custom/customLines.d.ts.map +1 -1
  72. package/dist/esm/canvas/utils/Custom/customLines.js +43 -19
  73. package/dist/esm/canvas/utils/Custom/customLines.js.map +1 -1
  74. package/dist/esm/canvas/utils/General/general functions.d.ts +6 -1
  75. package/dist/esm/canvas/utils/General/general functions.d.ts.map +1 -1
  76. package/dist/esm/canvas/utils/General/general functions.js +19 -20
  77. package/dist/esm/canvas/utils/General/general functions.js.map +1 -1
  78. package/dist/esm/canvas/utils/Image/imageProperties.d.ts +3 -9
  79. package/dist/esm/canvas/utils/Image/imageProperties.d.ts.map +1 -1
  80. package/dist/esm/canvas/utils/Image/imageProperties.js +220 -214
  81. package/dist/esm/canvas/utils/Image/imageProperties.js.map +1 -1
  82. package/dist/esm/canvas/utils/Texts/textProperties.d.ts +12 -14
  83. package/dist/esm/canvas/utils/Texts/textProperties.d.ts.map +1 -1
  84. package/dist/esm/canvas/utils/Texts/textProperties.js +100 -91
  85. package/dist/esm/canvas/utils/Texts/textProperties.js.map +1 -1
  86. package/dist/esm/canvas/utils/types.d.ts +89 -109
  87. package/dist/esm/canvas/utils/types.d.ts.map +1 -1
  88. package/dist/esm/canvas/utils/types.js.map +1 -1
  89. package/dist/esm/canvas/utils/utils.d.ts +2 -4
  90. package/dist/esm/canvas/utils/utils.d.ts.map +1 -1
  91. package/dist/esm/canvas/utils/utils.js +2 -5
  92. package/dist/esm/canvas/utils/utils.js.map +1 -1
  93. package/dist/esm/index.d.ts.map +1 -1
  94. package/dist/esm/index.js +31 -3
  95. package/dist/esm/index.js.map +1 -1
  96. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  97. package/lib/ai/ApexModules.ts +83 -11
  98. package/lib/ai/functions/readFiles.ts +1 -1
  99. package/lib/ai/modals-chat/electronHub/chatmodels.ts +4 -2
  100. package/lib/ai/modals-chat/electronHub/speechModels.ts +2 -1
  101. package/lib/canvas/ApexPainter.ts +52 -61
  102. package/lib/canvas/Themes/Level-Up/levelup.ts +183 -0
  103. package/lib/canvas/utils/Background/bg.ts +179 -65
  104. package/lib/canvas/utils/Custom/customLines.ts +53 -20
  105. package/lib/canvas/utils/General/general functions.ts +21 -29
  106. package/lib/canvas/utils/Image/imageProperties.ts +399 -318
  107. package/lib/canvas/utils/Texts/textProperties.ts +213 -162
  108. package/lib/canvas/utils/types.ts +74 -107
  109. package/lib/canvas/utils/utils.ts +2 -5
  110. package/lib/index.ts +38 -10
  111. package/package.json +3 -2
  112. package/dist/cjs/canvas/utils/Background/circular.d.ts +0 -3
  113. package/dist/cjs/canvas/utils/Background/circular.d.ts.map +0 -1
  114. package/dist/cjs/canvas/utils/Background/circular.js +0 -13
  115. package/dist/cjs/canvas/utils/Background/circular.js.map +0 -1
  116. package/dist/cjs/canvas/utils/Background/radius.d.ts +0 -18
  117. package/dist/cjs/canvas/utils/Background/radius.d.ts.map +0 -1
  118. package/dist/cjs/canvas/utils/Background/radius.js +0 -104
  119. package/dist/cjs/canvas/utils/Background/radius.js.map +0 -1
  120. package/dist/esm/canvas/utils/Background/circular.d.ts +0 -3
  121. package/dist/esm/canvas/utils/Background/circular.d.ts.map +0 -1
  122. package/dist/esm/canvas/utils/Background/circular.js +0 -13
  123. package/dist/esm/canvas/utils/Background/circular.js.map +0 -1
  124. package/dist/esm/canvas/utils/Background/radius.d.ts +0 -18
  125. package/dist/esm/canvas/utils/Background/radius.d.ts.map +0 -1
  126. package/dist/esm/canvas/utils/Background/radius.js +0 -104
  127. package/dist/esm/canvas/utils/Background/radius.js.map +0 -1
  128. package/lib/canvas/utils/Background/circular.ts +0 -17
  129. package/lib/canvas/utils/Background/radius.ts +0 -102
@@ -8,6 +8,7 @@ import { electronImagine } from './modals-chat/electronHub/imageModels';
8
8
  import { electronChat } from './modals-chat/electronHub/chatmodels';
9
9
  import { electronSpeech } from './modals-chat/electronHub/speechModels';
10
10
  import { electronVideo } from './modals-chat/electronHub/videoModels';
11
+ import { GoogleGenerativeAI } from"@google/generative-ai";
11
12
 
12
13
 
13
14
  const dbConfig = {
@@ -591,22 +592,26 @@ async function ApexImagine(model: string, prompt: string, options?: ApexImagineO
591
592
  return response;
592
593
  }
593
594
 
594
- async function ApexChat(model: string, prompt: string, { userId, memory, limit, instruction, Api_key }: { userId?: string, memory?: boolean, limit?: number, instruction?: string, Api_key?: string }): Promise<string> {
595
+ async function ApexChat(
596
+ model: string,
597
+ prompt: string,
598
+ { userId, memory, limit, instruction, Api_key }: { userId?: string; memory?: boolean; limit?: number; instruction?: string; Api_key?: string }
599
+ ): Promise<string> {
595
600
  try {
596
-
597
601
  let enhancedPrompt: string = prompt;
598
602
  let historyChat: string = `- This is Previous chat history between you (System) and the user (User). Don't use the history or reply back anything related to it unless being mentioned in user's new prompt\n`;
599
- let commandString: string = ''
600
- if (instruction) {
601
- commandString = `- Given Constant instruction for the System (AI) to abide and to always follow:\n${instruction}\n\n`
602
- }
603
+
604
+ let commandString = instruction ? `- Given Constant instruction for the System (AI) to abide and to always follow:\n${instruction}\n\n` : '';
605
+
603
606
  if (memory && userId) {
604
-
605
607
  const userHistoryResult = (await db.find(`${userId}`, { userId })).results?.history || [];
606
- const historyItems = Array.isArray(userHistoryResult) ? userHistoryResult.slice(-(limit ?? 12)) : [];
608
+ const historyItems = Array.isArray(userHistoryResult) ? userHistoryResult : [];
609
+
610
+ const relevantMessages = await getRelevantHistoryAI(prompt, historyItems, limit ?? 12);
611
+
607
612
 
608
613
  let formattedHistory = '';
609
- historyItems.forEach((item) => {
614
+ relevantMessages.forEach((item) => {
610
615
  formattedHistory += `User: ${item.user}\nSystem: ${item.model}\n\n`;
611
616
  });
612
617
 
@@ -628,7 +633,7 @@ async function ApexChat(model: string, prompt: string, { userId, memory, limit,
628
633
 
629
634
  response = responses.join('');
630
635
  } else {
631
- response = await processChunk(model, enhancedPrompt, {});
636
+ response = await processChunk(model, enhancedPrompt, { ApiKey: Api_key, personality: instruction });
632
637
  }
633
638
 
634
639
  if (memory && userId && model !== 'gemini-pro' && model !== 'gemini-flash') {
@@ -637,11 +642,78 @@ async function ApexChat(model: string, prompt: string, { userId, memory, limit,
637
642
 
638
643
  return response;
639
644
  } catch (error: any) {
640
- console.error(error.message);
645
+ console.error(error.message);
641
646
  return '';
642
647
  }
643
648
  }
644
649
 
650
+ const genAI = new GoogleGenerativeAI('AIzaSyAdlBVg12yjqqGfBqxT5DLGMhP2jysG7Hk');
651
+
652
+ const model = genAI.getGenerativeModel({ model: "text-embedding-004" });
653
+
654
+ async function getRelevantHistoryAI(prompt: string, history: any[], maxResults: number): Promise<any[]> {
655
+
656
+ const trimmedPrompt = prompt.length > 20000 ? prompt.slice(0, 20000) : prompt;
657
+ const promptEmbedding = await generateEmbedding(trimmedPrompt);
658
+
659
+ const threshold = 0.7;
660
+
661
+ const scores = await Promise.all(
662
+ history.map(async (item) => {
663
+ const trimmedUser = item.user.length > 20000 ? item.user.slice(0, 20000) : item.user;
664
+
665
+ const messageEmbedding = await generateEmbedding(trimmedUser);
666
+ const score = cosineSimilarity(promptEmbedding, messageEmbedding);
667
+ return { item, score };
668
+ })
669
+ );
670
+
671
+ const filteredResults = scores.filter(entry => entry.score >= threshold);
672
+ filteredResults.sort((a, b) => b.score - a.score);
673
+
674
+ return filteredResults.slice(0, maxResults).map(entry => entry.item);
675
+ }
676
+
677
+ async function generateEmbedding(text: string): Promise<number[]> {
678
+ let maxRetries = 5;
679
+ let delay = 5000;
680
+ let attempt = 0;
681
+
682
+ while (attempt < maxRetries) {
683
+ try {
684
+
685
+ const response = await model.embedContent(text);
686
+
687
+
688
+ return response.embedding.values;
689
+ } catch (error: any) {
690
+ if (error.response) {
691
+ console.warn(`❌ API Error - Status: ${error.response.status}, Message: ${error.response.statusText}`);
692
+ } else {
693
+ console.error("❌ Network or unknown error:", error.message);
694
+ }
695
+
696
+ if (error.response && error.response.status === 429) {
697
+ console.warn(`⚠️ Rate limited (429). Retrying in ${delay / 1000} seconds...`);
698
+ await new Promise(res => setTimeout(res, delay));
699
+ } else {
700
+ throw error;
701
+ }
702
+ }
703
+
704
+ attempt++;
705
+ }
706
+
707
+ throw new Error("Max retries reached. Failed to get embedding.");
708
+ }
709
+
710
+ function cosineSimilarity(a: number[], b: number[]): number {
711
+ const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
712
+ const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
713
+ const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
714
+ return dotProduct / (magnitudeA * magnitudeB);
715
+ }
716
+
645
717
  async function resetHistory({ id, last }: { id: string; last: number | string }): Promise<boolean> {
646
718
  if (!id) return false;
647
719
 
@@ -15,7 +15,7 @@ export async function readFile(pathOrUrl: string, type?: string): Promise<string
15
15
  case "pdf":
16
16
  return readPdf(buffer);
17
17
  default:
18
- return buffer.toString();
18
+ return buffer.toString("utf-8");
19
19
  }
20
20
  }
21
21
 
@@ -32,14 +32,16 @@ export async function electronChat({
32
32
  if (!modelExists) {
33
33
  throw new Error('Invalid model name please check out Electron hub models for more info.')
34
34
  }
35
-
35
+ console.log(prompt);
36
+
36
37
  const completion = await openai.chat.completions.create({
37
- model: 'mistral-large-latest',
38
+ model: modelName,
38
39
  messages: [
39
40
  {"role": "system", "content": `${instruction}`},
40
41
  {"role": "user", "content": `${prompt}`}
41
42
  ]
42
43
  });
44
+
43
45
 
44
46
  return completion.choices[0]?.message?.content;
45
47
  } catch (e: any) {
@@ -17,9 +17,10 @@ export async function electronSpeech({
17
17
 
18
18
  const validPersonalities = [
19
19
  'will', 'maltida', 'liam', 'jessica', 'george', 'lily', 'sana',
20
- 'Wahab', 'martin', 'darine', 'guillaume', 'leoni', 'kurt', 'leo',
20
+ 'wahab', 'martin', 'darine', 'guillaume', 'leonie', 'kurt', 'leo',
21
21
  'shakuntala', 'maciej', 'aneta', 'gabriela', 'juan'
22
22
  ];
23
+
23
24
  if (personality && !validPersonalities.includes(personality)) {
24
25
  throw new Error(`Invalid personality. Please choose from the following: ${validPersonalities.join(', ')}`);
25
26
  }
@@ -6,13 +6,10 @@ import axios from 'axios';
6
6
  import fs from "fs";
7
7
  import path from "path";
8
8
  import { OutputFormat, CanvasConfig, TextObject, ImageProperties, GIFOptions, GIFResults, CustomOptions, cropOptions,
9
- drawBackgroundGradient, drawBackgroundColor, customBackground, circularBorder, radiusBorder, customLines, applyRotation, applyStroke,
9
+ drawBackgroundGradient, drawBackgroundColor, customBackground, customLines, applyRotation, applyStroke,
10
10
  applyShadow, imageRadius, drawShape, drawText, converter, resizingImg, applyColorFilters, imgEffects,verticalBarChart, pieChart,
11
11
  lineChart, cropInner, cropOuter, bgRemoval, detectColors, removeColor, dataURL, base64, arrayBuffer, blob, url, GradientConfig, Frame,
12
- PatternOptions, ExtractFramesOptions,
13
- applyZoom,
14
- ResizeOptions,
15
- applyPerspective
12
+ PatternOptions, ExtractFramesOptions, backgroundRadius, applyZoom, ResizeOptions, applyPerspective
16
13
  } from "./utils/utils";
17
14
 
18
15
  interface CanvasResults {
@@ -49,7 +46,8 @@ export class ApexPainter {
49
46
  shadow,
50
47
  borderPosition = 'all',
51
48
  opacity = 1,
52
- zoom
49
+ zoom,
50
+ blur
53
51
  } = canvas;
54
52
 
55
53
  const canvasInstance = createCanvas(width, height);
@@ -64,23 +62,20 @@ export class ApexPainter {
64
62
  applyShadow(ctx, shadow, x, y, width, height);
65
63
 
66
64
  ctx.save();
67
- if (typeof borderRadius === 'string') {
68
- circularBorder(ctx, width, height);
69
- } else if (typeof borderRadius === 'number') {
70
- radiusBorder(ctx, x, y, width, height, borderRadius, borderPosition);
65
+ if (borderRadius) {
66
+ backgroundRadius(ctx, x, y, width, height, borderRadius, borderPosition);
71
67
  }
72
68
 
73
- // ctx.translate(x, y);
74
-
75
- // applyZoom(ctx, zoom);
69
+ ctx.translate(x, y);
76
70
 
77
71
  if (customBg) {
78
- await customBackground(ctx, canvas);
72
+ await customBackground(ctx, canvas, zoom, blur);
79
73
  } else if (gradientBg) {
80
- await drawBackgroundGradient(ctx, canvas);
74
+ await drawBackgroundGradient(ctx, canvas, zoom, blur);
81
75
  } else {
82
- await drawBackgroundColor(ctx, canvas);
76
+ await drawBackgroundColor(ctx, canvas, zoom, blur);
83
77
  }
78
+
84
79
  ctx.restore();
85
80
 
86
81
  applyStroke(ctx, stroke, x, y, width, height);
@@ -165,12 +160,12 @@ export class ApexPainter {
165
160
 
166
161
  GlobalFonts.registerFromPath(
167
162
  path.join(process.cwd(), mergedTextOptions.fontPath),
168
- mergedTextOptions.fontName,
163
+ (mergedTextOptions.fontName || 'customFont'),
169
164
  );
170
165
  }
171
166
 
172
167
  const size = { width: existingImage.width, height: existingImage.height };
173
- drawText(ctx, mergedTextOptions, size);
168
+ drawText(ctx, mergedTextOptions);
174
169
  }
175
170
 
176
171
  return canvas.toBuffer("image/png");
@@ -469,87 +464,83 @@ async createGIF(gifFrames: { background: string; duration: number }[], options:
469
464
  }
470
465
  }
471
466
 
472
- private async drawImage(
473
- ctx: SKRSContext2D,
474
- image: ImageProperties
475
- ): Promise<void> {
467
+ private async drawImage(ctx: SKRSContext2D, image: ImageProperties): Promise<void> {
476
468
  const {
477
469
  source,
478
- x,
479
- y,
480
- width,
481
- height,
470
+ x, y, width, height,
482
471
  rotation = 0,
483
472
  borderRadius = 0,
484
- stroke,
485
- shadow,
486
- isFilled,
487
- color,
488
- gradient,
473
+ stroke, shadow,
474
+ isFilled, color, gradient,
489
475
  borderPosition = 'all',
490
476
  opacity,
491
- perspective
477
+ perspective,
478
+ blur = 0,
479
+ zoom,
480
+ filling
492
481
  } = image;
493
482
 
494
- if (
495
- !source ||
496
- typeof x !== 'number' ||
497
- typeof y !== 'number' ||
498
- typeof width !== 'number' ||
499
- typeof height !== 'number'
500
- ) {
483
+ if (perspective) throw new Error("`perspective` Feature is under construction. Please refrain from using it.");
484
+
485
+ if (!source || typeof x !== 'number' || typeof y !== 'number' || typeof width !== 'number' || typeof height !== 'number') {
501
486
  throw new Error('Invalid image properties: source, x, y, width, and height are required.');
502
487
  }
503
-
504
- const shapeNames = ['circle', 'square', 'triangle', 'pentagon', 'hexagon', 'heptagon', 'octagon', 'star', 'kite'];
488
+
489
+ const shapeNames = ['circle', 'square', 'triangle', 'pentagon', 'hexagon', 'heptagon', 'octagon', 'star', 'kite', 'arrow', 'star', 'oval', 'heart', 'diamond', 'trapezoid', 'cloud'];
505
490
  const isShape = shapeNames.includes(source.toLowerCase());
506
-
491
+
507
492
  if (opacity !== undefined) {
508
493
  ctx.globalAlpha = opacity;
509
494
  }
510
-
495
+
511
496
  if (isShape) {
512
- drawShape(ctx, { source, x, y, width, height, rotation, borderRadius, stroke, shadow, isFilled, color, gradient, borderPosition });
497
+ drawShape(ctx, { source, x, y, width, height, rotation, borderRadius, stroke, shadow, isFilled, color, gradient, borderPosition, filling });
513
498
  ctx.globalAlpha = 1.0;
514
499
  return;
515
500
  }
516
-
501
+
517
502
  let loadedImage: Image | undefined;
518
503
  try {
519
504
  if (source.startsWith('http')) {
520
505
  loadedImage = await loadImage(source);
521
506
  } else {
522
- const imagePath = path.join(process.cwd(), source);
507
+ const imagePath = path.resolve(process.cwd(), source);
523
508
  loadedImage = await loadImage(imagePath);
524
509
  }
525
510
  } catch (e: any) {
526
511
  throw new Error(`Error loading image: ${e.message}`);
527
512
  }
528
-
513
+
529
514
  if (!loadedImage) {
530
515
  throw new Error('Invalid image source or failed to load image');
531
516
  }
532
-
517
+
533
518
  ctx.save();
519
+
520
+ const scale = zoom?.scale ?? 1;
521
+ const focusX = zoom?.x ?? 0.5;
522
+ const focusY = zoom?.y ?? 0.5;
523
+
524
+ if (scale !== 1) {
525
+ ctx.translate(focusX, focusY);
526
+ ctx.scale(scale, scale);
527
+ }
528
+
529
+ if (blur > 0) {
530
+ ctx.filter = `blur(${blur}px)`;
531
+ }
532
+
534
533
  applyRotation(ctx, rotation, x, y, width, height);
535
534
  applyShadow(ctx, shadow, x, y, width, height);
536
535
 
537
536
  if (perspective) {
538
- throw new Error('Under construction')
539
- // const offscreen = createCanvas(width, height);
540
- // const offCtx = offscreen.getContext('2d') as SKRSContext2D;
541
- // offCtx.clearRect(0, 0, width, height);
542
-
543
- // await applyPerspective(offCtx, loadedImage, 0, 0, width, height, perspective, 10, 10);
544
-
545
- // imageRadius(ctx, offscreen, x, y, width, height, borderRadius, borderPosition);
537
+ throw new Error('Under construction');
546
538
  }
547
-
539
+
548
540
  imageRadius(ctx, loadedImage, x, y, width, height, borderRadius, borderPosition);
549
-
550
- applyStroke(ctx, stroke, x, y, width, height);
541
+ applyStroke(ctx, stroke, x, y, width, height, undefined, true);
542
+
551
543
  ctx.restore();
552
-
553
544
  ctx.globalAlpha = 1.0;
554
545
  }
555
546
 
@@ -997,7 +988,7 @@ async animate(
997
988
  }
998
989
 
999
990
  if (frame.onDrawCustom) {
1000
- frame.onDrawCustom(ctx as unknown as CanvasRenderingContext2D, canvas);
991
+ frame.onDrawCustom(ctx as unknown as SKRSContext2D, canvas);
1001
992
  }
1002
993
 
1003
994
  if (frame.transformations) {
@@ -0,0 +1,183 @@
1
+ import { ApexPainter, CanvasConfig, ImageProperties, TextObject } from "../../../index";
2
+
3
+ const Image = new ApexPainter();
4
+
5
+ /**
6
+ * Generates a level-up card.
7
+ * @param {string} userPfp - User profile picture URL.
8
+ * @param {string} username - Username.
9
+ * @param {string} [levelUpmsg="Well done user. You had leveled up 🔥🔥"] - Custom level-up message.
10
+ * @param {string} prevLevel - Previous level before leveling up.
11
+ * @param {string} nextLevel - Next level after leveling up.
12
+ * @returns {Promise<Buffer>} - The generated level-up image.
13
+ */
14
+ export async function level_up_1(
15
+ userPfp: string,
16
+ username: string,
17
+ levelUpmsg: string = "Well done user. You had leveled up 🔥🔥",
18
+ prevLevel: string,
19
+ nextLevel: string
20
+ ): Promise<Buffer> {
21
+
22
+ /** Helper function to detect Arabic text */
23
+ const isArabic = (text: string) => /[\u0600-\u06FF]/.test(text);
24
+
25
+ /** Helper function to shuffle an array */
26
+ function shuffleArray<T>(array: T[]): T[] {
27
+ return array.sort(() => Math.random() - 0.5);
28
+ }
29
+
30
+ /** Extracts and returns random colors from the dominant colors */
31
+ function getRandomColors(colors: { color: string }[]): string[] {
32
+ if (colors.length === 0) return ["rgb(0, 255, 247)", "rgb(157, 0, 255)", "rgb(255, 94, 0)"];
33
+ return shuffleArray(colors).slice(0, 5).map(c => `rgb(${c.color})`);
34
+ }
35
+
36
+ // 1. **Canvas Configuration**
37
+ const canvasConfig: CanvasConfig = {
38
+ customBg: './bg.png',
39
+ width: 1599, height: 876,
40
+ zoom: {}
41
+ };
42
+
43
+ const bg = await Image.createCanvas(canvasConfig);
44
+
45
+ // 2. **Extract Dominant Colors for Gradients**
46
+ const dominantColors = await Image.colorAnalysis(userPfp);
47
+ const gradientColors = getRandomColors(dominantColors).map((color, index) => ({
48
+ stop: index / 4, color
49
+ }));
50
+ const shadowGradient = [...gradientColors];
51
+
52
+ // 3. **User Profile Picture Configuration**
53
+ const imgs: ImageProperties[] = [{
54
+ source: userPfp,
55
+ width: 240, height: 240,
56
+ x: 235, y: 235,
57
+ blur: 0.4,
58
+ borderRadius: 'circular',
59
+ stroke: {
60
+ width: 8, position: 5, blur: 0.5,
61
+ borderRadius: 'circular',
62
+ gradient: {
63
+ type: 'linear',
64
+ startX: 200, startY: 200,
65
+ endX: 290, endY: 290,
66
+ colors: gradientColors
67
+ }
68
+ },
69
+ shadow: {
70
+ gradient: {
71
+ type: 'linear',
72
+ startX: 220, startY: 220,
73
+ endX: 270, endY: 270,
74
+ colors: shadowGradient
75
+ },
76
+ opacity: 0.7,
77
+ blur: 25,
78
+ borderRadius: 90,
79
+ offsetX: 0, offsetY: 0,
80
+ }
81
+ }];
82
+
83
+ const img = await Image.createImage(imgs, bg);
84
+
85
+ // 4. **Username Text Handling**
86
+ const maxLength = isArabic(username) ? 12 : 10;
87
+ let displayName = username.length > maxLength
88
+ ? isArabic(username)
89
+ ? '...' + username.slice(-maxLength)
90
+ : username.slice(0, maxLength - 3) + '...'
91
+ : username;
92
+
93
+ let xPos = isArabic(username) ? Math.max(480 - (displayName.length - 4) * 3, 190) - 30 : 300 - Math.min((displayName.length - 3) * 10, 110);
94
+
95
+ // 5. **Message Text Alignment**
96
+ const container = { width: 590, height: 235, x: 810, y: 520 };
97
+ const fontName = isArabic(levelUpmsg) ? 'Segoe UI' : 'Segoe UI Emoji';
98
+ const textX = isArabic(levelUpmsg) ? container.x + 290 : container.x + 285;
99
+
100
+ // 6. **Dynamic Level Positioning Function**
101
+ function getLevelPosition(level: string, isNext: boolean) {
102
+ let x = isNext ? 1320 : 885;
103
+ let y = 455;
104
+ let fontSize = 72;
105
+
106
+ if (level.length === 3) {
107
+ x = isNext ? 1323 : 888;
108
+ y = 455;
109
+ fontSize = 63;
110
+ }
111
+
112
+ return { x, y, fontSize };
113
+ }
114
+
115
+ const prevLevelConfig = getLevelPosition(prevLevel, false);
116
+ const nextLevelConfig = getLevelPosition(nextLevel, true);
117
+
118
+ // 7. **Text Elements Configuration**
119
+ const txts: TextObject[] = [
120
+ {
121
+ text: displayName,
122
+ x: xPos, y: 600,
123
+ fontSize: 54,
124
+ fontName: 'Segoe UI',
125
+ textAlign: isArabic(username) ? 'right' : 'left',
126
+ gradient: {
127
+ type: 'linear',
128
+ startX: 0, startY: 0,
129
+ endX: 0, endY: 50,
130
+ colors: [
131
+ { stop: 0, color: '#ffffff' },
132
+ { stop: 1, color: '#66e6ff' }
133
+ ]
134
+ },
135
+ stroke: { width: 3, color: '#9d00ff' },
136
+ shadow: { color: '#66e6ff', opacity: 0.4, blur: 8, offsetX: 0, offsetY: 0 }
137
+ },
138
+ {
139
+ text: levelUpmsg,
140
+ x: textX, y: container.y + 60,
141
+ fontSize: 34,
142
+ fontName: fontName,
143
+ textAlign: 'center',
144
+ maxWidth: container.width - 30,
145
+ lineHeight: 42,
146
+ maxHeight: container.height - 30,
147
+ gradient: {
148
+ type: 'linear',
149
+ startX: 0, startY: 0,
150
+ endX: 0, endY: 50,
151
+ colors: [
152
+ { stop: 0, color: '#f9ff00' },
153
+ { stop: 1, color: '#ff6a00' }
154
+ ]
155
+ },
156
+ stroke: { width: 2, color: '#ff9d00' },
157
+ shadow: { color: '#ffcc00', opacity: 0.5, blur: 10, offsetX: 0, offsetY: 0 }
158
+ },
159
+ {
160
+ text: prevLevel,
161
+ x: prevLevelConfig.x, y: prevLevelConfig.y,
162
+ fontSize: prevLevelConfig.fontSize,
163
+ fontName: "Bahnschrift",
164
+ textAlign: "center",
165
+ gradient: { type: "linear", startX: 0, startY: 0, endX: 0, endY: 80, colors: [{ stop: 0, color: "#00FFFF" }, { stop: 1, color: "#007BFF" }] },
166
+ stroke: { width: 6, color: "#0033FF" },
167
+ shadow: { color: "#00BFFF", opacity: 0.6, blur: 15, offsetX: 0, offsetY: 0 }
168
+ },
169
+ {
170
+ text: nextLevel,
171
+ x: nextLevelConfig.x, y: nextLevelConfig.y,
172
+ fontSize: nextLevelConfig.fontSize,
173
+ fontName: "Bahnschrift",
174
+ textAlign: "center",
175
+ gradient: { type: "linear", startX: 0, startY: 0, endX: 0, endY: 80, colors: [{ stop: 0, color: "#00FFFF" }, { stop: 1, color: "#007BFF" }] },
176
+ stroke: { width: 6, color: "#0033FF" },
177
+ shadow: { color: "#00BFFF", opacity: 0.6, blur: 15, offsetX: 0, offsetY: 0 }
178
+ }
179
+ ];
180
+
181
+ // 8. **Render Final Image**
182
+ return await Image.createText(txts, img);
183
+ }