canva-pptx 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.
Files changed (87) hide show
  1. package/README.md +1147 -0
  2. package/package.json +63 -0
  3. package/src/AdvancedComponents/accordionList.js +39 -0
  4. package/src/AdvancedComponents/calendarGrid.js +50 -0
  5. package/src/AdvancedComponents/certificateFrame.js +35 -0
  6. package/src/AdvancedComponents/deviceMockup.js +59 -0
  7. package/src/AdvancedComponents/featureGrid.js +70 -0
  8. package/src/AdvancedComponents/funnelDiagram.js +49 -0
  9. package/src/AdvancedComponents/ganttChart.js +35 -0
  10. package/src/AdvancedComponents/invoiceTable.js +32 -0
  11. package/src/AdvancedComponents/matrixGrid.js +43 -0
  12. package/src/AdvancedComponents/mindMap.js +43 -0
  13. package/src/AdvancedComponents/orgChart.js +76 -0
  14. package/src/AdvancedComponents/personaCard.js +44 -0
  15. package/src/AdvancedComponents/processCycle.js +47 -0
  16. package/src/AdvancedComponents/pyramidHierarchy.js +38 -0
  17. package/src/AdvancedComponents/saasFeatureBlock.js +38 -0
  18. package/src/AdvancedComponents/swotMatrix.js +55 -0
  19. package/src/AdvancedComponents/teamMemberProfile.js +75 -0
  20. package/src/AdvancedComponents/trafficLight.js +35 -0
  21. package/src/AdvancedComponents/vennDiagram.js +35 -0
  22. package/src/AdvancedComponents/winLossChart.js +43 -0
  23. package/src/components/StatMetric.js +43 -0
  24. package/src/components/alertBox.js +46 -0
  25. package/src/components/avatarGroup.js +56 -0
  26. package/src/components/badge.js +40 -0
  27. package/src/components/breadcrumbNav.js +31 -0
  28. package/src/components/browserWindow.js +86 -0
  29. package/src/components/brushStroke.js +23 -0
  30. package/src/components/callToAction.js +27 -0
  31. package/src/components/card.js +64 -0
  32. package/src/components/chart.js +19 -0
  33. package/src/components/codeBlock.js +40 -0
  34. package/src/components/codeDiff.js +51 -0
  35. package/src/components/comparisonTable.js +43 -0
  36. package/src/components/cornerAccent.js +32 -0
  37. package/src/components/dotPattern.js +30 -0
  38. package/src/components/geometricConfetti.js +34 -0
  39. package/src/components/gradientMesh.js +32 -0
  40. package/src/components/iconList.js +43 -0
  41. package/src/components/image.js +11 -0
  42. package/src/components/kanbanColumn.js +38 -0
  43. package/src/components/link.js +23 -0
  44. package/src/components/organicBlob.js +45 -0
  45. package/src/components/pricingColumn.js +53 -0
  46. package/src/components/progressBar.js +55 -0
  47. package/src/components/ratingStars.js +25 -0
  48. package/src/components/shape.js +12 -0
  49. package/src/components/slide.js +5 -0
  50. package/src/components/socialBar.js +59 -0
  51. package/src/components/squiggleLine.js +26 -0
  52. package/src/components/stepProcess.js +39 -0
  53. package/src/components/table.js +23 -0
  54. package/src/components/tagCloud.js +39 -0
  55. package/src/components/testimonialCard.js +54 -0
  56. package/src/components/text.js +14 -0
  57. package/src/components/theme.js +7 -0
  58. package/src/components/timeline.js +73 -0
  59. package/src/components/waveDecoration.js +35 -0
  60. package/src/core/PPTManager.js +17 -0
  61. package/src/index.js +225 -0
  62. package/src/layout/bento.js +47 -0
  63. package/src/layout/checkerboard.js +36 -0
  64. package/src/layout/filmStrip.js +29 -0
  65. package/src/layout/gallery.js +50 -0
  66. package/src/layout/grid.js +37 -0
  67. package/src/layout/hero.js +30 -0
  68. package/src/layout/magazine.js +39 -0
  69. package/src/layout/radial.js +34 -0
  70. package/src/layout/sidebar.js +26 -0
  71. package/src/layout/splitScreen.js +36 -0
  72. package/src/layout/zPattern.js +29 -0
  73. package/src/system/animation.js +36 -0
  74. package/src/system/contrastChecker.js +35 -0
  75. package/src/system/dataAdapter.js +36 -0
  76. package/src/system/layoutDebugger.js +40 -0
  77. package/src/system/markdownEngine.js +45 -0
  78. package/src/system/masterOverlay.js +50 -0
  79. package/src/system/sectionDivider.js +41 -0
  80. package/src/system/smartIcon.js +33 -0
  81. package/src/system/smartText.js +44 -0
  82. package/src/system/speakerNotes.js +12 -0
  83. package/src/system/syntaxHighlighter.js +71 -0
  84. package/src/system/themeGenerator.js +25 -0
  85. package/src/system/tocGenerator.js +68 -0
  86. package/src/system/watermark.js +26 -0
  87. package/src/themes/index.js +93 -0
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "canva-pptx",
3
+ "version": "1.0.0",
4
+ "description": "A professional, component-based PowerPoint (PPTX) generator for Node.js. Create complex, Canva-style slide decks, business reports, and dashboards programmatically with smart layouts and themes.",
5
+ "main": "src/index.js",
6
+ "files": [
7
+ "src/**/*",
8
+ "README.md",
9
+ "LICENSE"
10
+ ],
11
+ "scripts": {
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "pptx",
16
+ "powerpoint",
17
+ "presentation",
18
+ "slides",
19
+ "deck",
20
+ "generator",
21
+ "builder",
22
+ "creator",
23
+ "automation",
24
+ "report-generation",
25
+ "reporting",
26
+ "pptxgenjs",
27
+ "office",
28
+ "microsoft",
29
+ "ms-office",
30
+ "document-generation",
31
+ "export-to-pptx",
32
+ "node-pptx",
33
+ "layout-engine",
34
+ "composable",
35
+ "components",
36
+ "design-system",
37
+ "programmatic-design",
38
+ "canvas",
39
+ "dashboard",
40
+ "charts",
41
+ "business-intelligence",
42
+ "nodejs",
43
+ "javascript",
44
+ "slide-maker"
45
+ ],
46
+ "author": "Fairoz Ahmed",
47
+ "license": "ISC",
48
+ "type": "commonjs",
49
+ "dependencies": {
50
+ "pptxgenjs": "^3.12.0"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/fairoz-539/canva-pptx.git"
55
+ },
56
+ "bugs": {
57
+ "url": "https://github.com/fairoz-539/canva-pptx/issues"
58
+ },
59
+ "homepage": "https://github.com/fairoz-539/canva-pptx#readme",
60
+ "publishConfig": {
61
+ "access": "public"
62
+ }
63
+ }
@@ -0,0 +1,39 @@
1
+ function addAccordionList(slide, items = [], options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 6,
4
+ headerColor = "007AFF",
5
+ bodyColor = "F5F5F5"
6
+ } = options;
7
+
8
+ let currentY = y;
9
+
10
+ items.forEach((item) => {
11
+ // Header
12
+ slide.addShape("rect", {
13
+ x, y: currentY, w, h: 0.5,
14
+ fill: headerColor
15
+ });
16
+ slide.addText(`+ ${item.title}`, {
17
+ x: x + 0.2, y: currentY, w: w - 0.4, h: 0.5,
18
+ color: "FFFFFF", bold: true, valign: "middle", fontSize: 12
19
+ });
20
+
21
+ currentY += 0.5;
22
+
23
+ // Body (Expanded)
24
+ const bodyH = 0.8; // Fixed height for simplicity
25
+ slide.addShape("rect", {
26
+ x, y: currentY, w, h: bodyH,
27
+ fill: bodyColor,
28
+ line: { color: "DDDDDD" }
29
+ });
30
+ slide.addText(item.content, {
31
+ x: x + 0.2, y: currentY, w: w - 0.4, h: bodyH,
32
+ color: "333333", valign: "top", fontSize: 11
33
+ });
34
+
35
+ currentY += bodyH + 0.1; // Gap
36
+ });
37
+ }
38
+
39
+ module.exports = { addAccordionList };
@@ -0,0 +1,50 @@
1
+ function addCalendarGrid(slide, monthName, events = [], options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 5, h = 4,
4
+ headerColor = "D32F2F"
5
+ } = options;
6
+
7
+ const cols = 7;
8
+ const rows = 6; // Header + 5 weeks
9
+ const cellW = w / cols;
10
+ const cellH = (h - 0.5) / 5; // 0.5 for header
11
+
12
+ // Header
13
+ slide.addShape("rect", { x, y, w, h: 0.5, fill: headerColor });
14
+ slide.addText(monthName, { x, y, w, h: 0.5, color: "FFFFFF", bold: true, align: "center" });
15
+
16
+ // Grid
17
+ let dayCount = 1;
18
+ for (let r = 0; r < 5; r++) {
19
+ for (let c = 0; c < 7; c++) {
20
+ if (dayCount > 31) break; // Simple logic
21
+
22
+ const curX = x + c * cellW;
23
+ const curY = y + 0.5 + r * cellH;
24
+
25
+ // Check for event
26
+ const event = events.find(e => e.day === dayCount);
27
+ const bg = event ? event.color || "FFF3E0" : "FFFFFF";
28
+
29
+ slide.addShape("rect", {
30
+ x: curX, y: curY, w: cellW, h: cellH,
31
+ fill: bg, line: { color: "CCCCCC" }
32
+ });
33
+
34
+ slide.addText(String(dayCount), {
35
+ x: curX + 0.05, y: curY + 0.05, w: 0.3, h: 0.3,
36
+ fontSize: 9, color: "666666"
37
+ });
38
+
39
+ if (event) {
40
+ slide.addText(event.title, {
41
+ x: curX, y: curY + 0.2, w: cellW, h: cellH - 0.2,
42
+ fontSize: 8, align: "center", valign: "middle", bold: true
43
+ });
44
+ }
45
+ dayCount++;
46
+ }
47
+ }
48
+ }
49
+
50
+ module.exports = { addCalendarGrid };
@@ -0,0 +1,35 @@
1
+ function addCertificateFrame(slide, recipient, title = "Certificate of Appreciation", options = {}) {
2
+ const { x = 0.5, y = 0.5, w = 9, h = 4.63 } = options;
3
+
4
+ // Outer Border (Gold)
5
+ slide.addShape("rect", {
6
+ x, y, w, h,
7
+ line: { color: "C5A059", width: 4 },
8
+ fill: { color: undefined }
9
+ });
10
+
11
+ // Inner Border (Thin)
12
+ slide.addShape("rect", {
13
+ x: x + 0.2, y: y + 0.2, w: w - 0.4, h: h - 0.4,
14
+ line: { color: "C5A059", width: 1 },
15
+ fill: { color: undefined }
16
+ });
17
+
18
+ // Content
19
+ slide.addText(title, {
20
+ x, y: y + 1, w, h: 1,
21
+ align: "center", fontFace: "Georgia", fontSize: 32, bold: true, color: "333333"
22
+ });
23
+
24
+ slide.addText("Presented to", {
25
+ x, y: y + 2, w, h: 0.5,
26
+ align: "center", fontSize: 14, color: "666666"
27
+ });
28
+
29
+ slide.addText(recipient, {
30
+ x, y: y + 2.5, w, h: 1,
31
+ align: "center", fontFace: "Arial", fontSize: 40, bold: true, color: "C5A059"
32
+ });
33
+ }
34
+
35
+ module.exports = { addCertificateFrame };
@@ -0,0 +1,59 @@
1
+ function addDeviceMockup(slide, imageUrl, options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 6, h = 4,
4
+ type = "laptop" // or 'tablet'
5
+ } = options;
6
+
7
+ const frameColor = "333333";
8
+
9
+ if (type === "laptop") {
10
+ // Screen Frame
11
+ slide.addShape("roundRect", {
12
+ x, y, w, h: h * 0.85,
13
+ fill: frameColor,
14
+ rounding: 0.05
15
+ });
16
+
17
+ // Screen Image Area
18
+ slide.addShape("rect", {
19
+ x: x + 0.2, y: y + 0.2, w: w - 0.4, h: h * 0.85 - 0.4,
20
+ fill: "000000" // Black bg behind image
21
+ });
22
+
23
+ if (imageUrl) {
24
+ slide.addImage({
25
+ path: imageUrl,
26
+ x: x + 0.2, y: y + 0.2, w: w - 0.4, h: h * 0.85 - 0.4,
27
+ sizing: { type: "contain", w: w - 0.4, h: h * 0.85 - 0.4 }
28
+ });
29
+ }
30
+
31
+ // Base/Keyboard area
32
+ slide.addShape("trapezoid", {
33
+ x: x - 0.4, y: y + h * 0.85, w: w + 0.8, h: h * 0.15,
34
+ fill: "555555",
35
+ flipV: true // Invert trapezoid for base look
36
+ });
37
+ } else {
38
+ // Tablet Mode (Simple Round Rect)
39
+ slide.addShape("roundRect", {
40
+ x, y, w, h,
41
+ fill: frameColor,
42
+ rounding: 0.1
43
+ });
44
+ // Screen
45
+ slide.addShape("rect", {
46
+ x: x + 0.3, y: y + 0.3, w: w - 0.6, h: h - 0.6,
47
+ fill: "000000"
48
+ });
49
+ if (imageUrl) {
50
+ slide.addImage({
51
+ path: imageUrl,
52
+ x: x + 0.3, y: y + 0.3, w: w - 0.6, h: h - 0.6,
53
+ sizing: { type: "cover", w: w - 0.6, h: h - 0.6 }
54
+ });
55
+ }
56
+ }
57
+ }
58
+
59
+ module.exports = { addDeviceMockup };
@@ -0,0 +1,70 @@
1
+ function addFeatureGrid(slide, features = [], options = {}) {
2
+ const {
3
+ x = 1,
4
+ y = 1,
5
+ w = 8,
6
+ h = 4,
7
+ cols = 3,
8
+ gap = 0.3,
9
+ iconColor = "007AFF"
10
+ } = options;
11
+
12
+ if (features.length === 0) return;
13
+
14
+ // Calculate cell dimensions
15
+ const rows = Math.ceil(features.length / cols);
16
+ const cellW = (w - (cols - 1) * gap) / cols;
17
+ const cellH = (h - (rows - 1) * gap) / rows;
18
+
19
+ features.forEach((item, index) => {
20
+ const colIndex = index % cols;
21
+ const rowIndex = Math.floor(index / cols);
22
+
23
+ const curX = x + colIndex * (cellW + gap);
24
+ const curY = y + rowIndex * (cellH + gap);
25
+
26
+ // FIX: Use object for transparency instead of 8-digit hex
27
+ // transparency: 80 means 80% transparent (only 20% visible, similar to hex '33')
28
+ slide.addShape("oval", {
29
+ x: curX,
30
+ y: curY,
31
+ w: 0.5,
32
+ h: 0.5,
33
+ fill: { color: iconColor, transparency: 80 },
34
+ line: { color: undefined }
35
+ });
36
+
37
+ // If user provides an icon char (like '★'), use it, otherwise use first letter
38
+ const iconChar = item.icon || item.title[0] || "★";
39
+ slide.addText(iconChar, {
40
+ x: curX, y: curY, w: 0.5, h: 0.5,
41
+ color: iconColor, fontSize: 14, align: "center", valign: "middle", bold: true
42
+ });
43
+
44
+ // Title
45
+ slide.addText(item.title, {
46
+ x: curX + 0.6,
47
+ y: curY,
48
+ w: cellW - 0.6,
49
+ h: 0.3,
50
+ bold: true,
51
+ fontSize: 12,
52
+ color: "333333"
53
+ });
54
+
55
+ // Description
56
+ if (item.desc) {
57
+ slide.addText(item.desc, {
58
+ x: curX + 0.6,
59
+ y: curY + 0.3,
60
+ w: cellW - 0.6,
61
+ h: cellH - 0.3,
62
+ fontSize: 10,
63
+ color: "666666",
64
+ valign: "top"
65
+ });
66
+ }
67
+ });
68
+ }
69
+
70
+ module.exports = { addFeatureGrid };
@@ -0,0 +1,49 @@
1
+ function addFunnelDiagram(slide, stages = [], options = {}) {
2
+ const {
3
+ x = 2, y = 1, w = 6, h = 4,
4
+ colors = ["003f5c", "58508d", "bc5090", "ff6361", "ffa600"]
5
+ } = options;
6
+
7
+ const count = stages.length;
8
+ const layerH = h / count;
9
+
10
+ stages.forEach((stage, i) => {
11
+ const curY = y + i * layerH;
12
+ const color = colors[i % colors.length];
13
+
14
+ // Calculate width reduction for funnel shape
15
+ // Top is widest (w), Bottom is narrowest (e.g. w/2)
16
+ // Interpolate width based on index
17
+ const topW = w - (i * (w * 0.5)) / count;
18
+ const bottomW = w - ((i + 1) * (w * 0.5)) / count;
19
+
20
+ // We approximate the visual by centering a rectangle or trapezoid.
21
+ // pptxgenjs trapezoid shape usually handles scaling well.
22
+ // For simplicity here, we use a centered trapezoid.
23
+
24
+ slide.addShape("trapezoid", {
25
+ x: x + (w - topW)/2, // Centering approximation
26
+ y: curY,
27
+ w: topW,
28
+ h: layerH * 0.9, // slight gap
29
+ fill: color,
30
+ // Note: "adj" property in pptxgenjs controls trapezoid slant,
31
+ // but hard to calculate perfectly dynamically without trial.
32
+ });
33
+
34
+ slide.addText(stage.label, {
35
+ x: x, y: curY, w: w, h: layerH * 0.9,
36
+ align: "center", valign: "middle", color: "FFFFFF", bold: true
37
+ });
38
+
39
+ // Value (e.g. conversion rate)
40
+ if (stage.value) {
41
+ slide.addText(stage.value, {
42
+ x: x + w + 0.2, y: curY, w: 1.5, h: layerH * 0.9,
43
+ valign: "middle", fontSize: 11, color: "666666"
44
+ });
45
+ }
46
+ });
47
+ }
48
+
49
+ module.exports = { addFunnelDiagram };
@@ -0,0 +1,35 @@
1
+ function addGanttChart(slide, tasks = [], options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 8, h = 4,
4
+ barColor = "007AFF"
5
+ } = options;
6
+
7
+ // Header (Timeline ticks - simplified to Month 1, Month 2...)
8
+ slide.addShape("line", { x: x + 2, y: y + 0.4, w: w - 2, h: 0, line: { color: "CCCCCC" } });
9
+
10
+ // Task Rows
11
+ const rowH = (h - 0.5) / (tasks.length || 1);
12
+
13
+ tasks.forEach((task, i) => {
14
+ const curY = y + 0.5 + i * rowH;
15
+
16
+ // Label
17
+ slide.addText(task.name, {
18
+ x: x, y: curY, w: 1.8, h: rowH * 0.6,
19
+ fontSize: 10, bold: true, valign: "middle"
20
+ });
21
+
22
+ // Bar
23
+ // Assuming start/end are normalized 0.0 to 1.0 relative to timeline width
24
+ const startX = x + 2 + (task.start * (w - 2));
25
+ const barW = (task.end - task.start) * (w - 2);
26
+
27
+ slide.addShape("rect", {
28
+ x: startX, y: curY + 0.1, w: barW, h: rowH * 0.4,
29
+ fill: task.color || barColor,
30
+ rounding: 0.1
31
+ });
32
+ });
33
+ }
34
+
35
+ module.exports = { addGanttChart };
@@ -0,0 +1,32 @@
1
+ function addInvoiceTable(slide, items = [], options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 8,
4
+ currency = "$"
5
+ } = options;
6
+
7
+ // Header
8
+ slide.addShape("rect", { x, y, w, h: 0.5, fill: "333333" });
9
+ slide.addText("Description", { x: x + 0.2, y, w: w/2, h: 0.5, color: "FFFFFF", valign: "middle" });
10
+ slide.addText("Amount", { x: x + w - 2, y, w: 2, h: 0.5, color: "FFFFFF", valign: "middle", align: "right" });
11
+
12
+ let curY = y + 0.5;
13
+ let total = 0;
14
+
15
+ items.forEach((item, i) => {
16
+ const bg = i % 2 === 0 ? "F9F9F9" : "FFFFFF";
17
+ slide.addShape("rect", { x, y: curY, w, h: 0.4, fill: bg });
18
+
19
+ slide.addText(item.desc, { x: x + 0.2, y: curY, w: w/2, h: 0.4, valign: "middle", fontSize: 11 });
20
+ slide.addText(`${currency}${item.amount}`, { x: x + w - 2, y: curY, w: 2, h: 0.4, valign: "middle", align: "right", fontSize: 11 });
21
+
22
+ total += item.amount;
23
+ curY += 0.4;
24
+ });
25
+
26
+ // Total Row
27
+ slide.addShape("line", { x, y: curY, w, h: 0, line: { color: "000000" } });
28
+ slide.addText("TOTAL", { x: x + w - 4, y: curY + 0.1, w: 2, h: 0.5, bold: true, align: "right" });
29
+ slide.addText(`${currency}${total}`, { x: x + w - 2, y: curY + 0.1, w: 2, h: 0.5, bold: true, align: "right", fontSize: 14 });
30
+ }
31
+
32
+ module.exports = { addInvoiceTable };
@@ -0,0 +1,43 @@
1
+ function addMatrixGrid(slide, quadrants = [], options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 5, h = 5,
4
+ xAxis = "Effort", yAxis = "Impact"
5
+ } = options;
6
+
7
+ const halfW = w / 2;
8
+ const halfH = h / 2;
9
+
10
+ // Backgrounds
11
+ const colors = ["E3F2FD", "E8F5E9", "FFF3E0", "FFEBEE"]; // TL, TR, BL, BR
12
+ const pos = [
13
+ { ox: 0, oy: 0 }, { ox: halfW, oy: 0 },
14
+ { ox: 0, oy: halfH }, { ox: halfW, oy: halfH }
15
+ ];
16
+
17
+ pos.forEach((p, i) => {
18
+ slide.addShape("rect", {
19
+ x: x + p.ox, y: y + p.oy, w: halfW, h: halfH,
20
+ fill: colors[i]
21
+ });
22
+ if (quadrants[i]) {
23
+ slide.addText(quadrants[i], {
24
+ x: x + p.ox, y: y + p.oy, w: halfW, h: halfH,
25
+ align: "center", valign: "middle", bold: true, color: "555555"
26
+ });
27
+ }
28
+ });
29
+
30
+ // Axis Labels
31
+ // Y-Axis
32
+ slide.addText(yAxis, {
33
+ x: x - 0.6, y: y, w: 0.5, h: h,
34
+ rotate: 270, align: "center", bold: true
35
+ });
36
+ // X-Axis
37
+ slide.addText(xAxis, {
38
+ x: x, y: y + h + 0.1, w: w, h: 0.5,
39
+ align: "center", bold: true
40
+ });
41
+ }
42
+
43
+ module.exports = { addMatrixGrid };
@@ -0,0 +1,43 @@
1
+ function addMindMap(slide, centerText, branches = [], options = {}) {
2
+ const { x = 4, y = 2.5, w = 6, h = 4 } = options;
3
+
4
+ // Center Node
5
+ slide.addShape("oval", {
6
+ x: x, y: y, w: 1.5, h: 1.0,
7
+ fill: "FFFFFF", line: { color: "000000", width: 2 }
8
+ });
9
+ slide.addText(centerText, {
10
+ x: x, y: y, w: 1.5, h: 1.0,
11
+ align: "center", valign: "middle", bold: true
12
+ });
13
+
14
+ // Branches
15
+ // Very simple radial distribution
16
+ const angleStep = (2 * Math.PI) / branches.length;
17
+ const radius = 2.5;
18
+
19
+ branches.forEach((branch, i) => {
20
+ const angle = i * angleStep;
21
+ const nodeX = x + 0.75 + Math.cos(angle) * radius; // 0.75 is half width correction
22
+ const nodeY = y + 0.5 + Math.sin(angle) * radius;
23
+
24
+ // Line
25
+ slide.addShape("line", {
26
+ x: x + 0.75, y: y + 0.5,
27
+ w: (nodeX - (x + 0.75)), h: (nodeY - (y + 0.5)),
28
+ line: { color: "666666" }
29
+ });
30
+
31
+ // Branch Node
32
+ slide.addShape("roundRect", {
33
+ x: nodeX - 0.75, y: nodeY - 0.3, w: 1.5, h: 0.6,
34
+ fill: "F0F0F0", line: { color: "999999" }
35
+ });
36
+ slide.addText(branch, {
37
+ x: nodeX - 0.75, y: nodeY - 0.3, w: 1.5, h: 0.6,
38
+ align: "center", valign: "middle", fontSize: 10
39
+ });
40
+ });
41
+ }
42
+
43
+ module.exports = { addMindMap };
@@ -0,0 +1,76 @@
1
+ function addOrgChart(slide, rootData, options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 8, h = 4,
4
+ nodeW = 1.5, nodeH = 0.6,
5
+ gapX = 0.2, gapY = 0.8,
6
+ color = "007AFF"
7
+ } = options;
8
+
9
+ // Simple recursive renderer for 2 levels (Root -> Children)
10
+ // A full tree algorithm is complex; this covers the most common use case (CEO -> Reports)
11
+
12
+ // 1. Draw Root
13
+ const rootX = x + (w - nodeW) / 2;
14
+ const rootY = y;
15
+
16
+ slide.addShape("rect", {
17
+ x: rootX, y: rootY, w: nodeW, h: nodeH,
18
+ fill: color, line: { color: "FFFFFF" }
19
+ });
20
+ slide.addText(rootData.name, {
21
+ x: rootX, y: rootY, w: nodeW, h: nodeH,
22
+ color: "FFFFFF", bold: true, align: "center", fontSize: 11
23
+ });
24
+ if (rootData.role) {
25
+ slide.addText(rootData.role, {
26
+ x: rootX, y: rootY + 0.35, w: nodeW, h: 0.25,
27
+ color: "E0E0E0", align: "center", fontSize: 9
28
+ });
29
+ }
30
+
31
+ // 2. Draw Children
32
+ if (rootData.children && rootData.children.length > 0) {
33
+ const count = rootData.children.length;
34
+ // Calculate total width of children row
35
+ const totalChildrenW = count * nodeW + (count - 1) * gapX;
36
+ let startX = x + (w - totalChildrenW) / 2;
37
+ const childY = rootY + nodeH + gapY;
38
+
39
+ // Draw Connector Lines
40
+ // Vertical from Root
41
+ slide.addShape("line", {
42
+ x: rootX + nodeW/2, y: rootY + nodeH,
43
+ w: 0, h: gapY / 2,
44
+ line: { color: "333333", width: 1 }
45
+ });
46
+ // Horizontal Bar
47
+ slide.addShape("line", {
48
+ x: startX + nodeW/2, y: rootY + nodeH + gapY/2,
49
+ w: totalChildrenW - nodeW, h: 0,
50
+ line: { color: "333333", width: 1 }
51
+ });
52
+
53
+ rootData.children.forEach((child, i) => {
54
+ const curX = startX + i * (nodeW + gapX);
55
+
56
+ // Vertical to Child
57
+ slide.addShape("line", {
58
+ x: curX + nodeW/2, y: rootY + nodeH + gapY/2,
59
+ w: 0, h: gapY / 2,
60
+ line: { color: "333333", width: 1 }
61
+ });
62
+
63
+ // Child Box
64
+ slide.addShape("rect", {
65
+ x: curX, y: childY, w: nodeW, h: nodeH,
66
+ fill: "FFFFFF", line: { color: color }
67
+ });
68
+ slide.addText(child.name, {
69
+ x: curX, y: childY, w: nodeW, h: nodeH,
70
+ color: "333333", bold: true, align: "center", fontSize: 10
71
+ });
72
+ });
73
+ }
74
+ }
75
+
76
+ module.exports = { addOrgChart };
@@ -0,0 +1,44 @@
1
+ function addPersonaCard(slide, persona, options = {}) {
2
+ const {
3
+ x = 1, y = 1, w = 4, h = 5,
4
+ accent = "9C27B0"
5
+ } = options;
6
+
7
+ // Background
8
+ slide.addShape("rect", { x, y, w, h, fill: "F9F9F9", line: { color: "DDDDDD" } });
9
+
10
+ // Header Color
11
+ slide.addShape("rect", { x, y, w, h: 0.15, fill: accent });
12
+
13
+ // Photo Placeholder
14
+ slide.addShape("oval", { x: x + 0.3, y: y + 0.4, w: 1, h: 1, fill: "CCCCCC" });
15
+
16
+ // Name & Role
17
+ slide.addText(persona.name, {
18
+ x: x + 1.5, y: y + 0.4, w: w - 1.6, h: 0.5,
19
+ fontSize: 16, bold: true, color: "333333"
20
+ });
21
+ slide.addText(persona.role, {
22
+ x: x + 1.5, y: y + 0.8, w: w - 1.6, h: 0.4,
23
+ fontSize: 12, color: accent
24
+ });
25
+
26
+ // Quote
27
+ slide.addText(`"${persona.quote}"`, {
28
+ x: x + 0.3, y: y + 1.6, w: w - 0.6, h: 0.6,
29
+ italic: true, fontSize: 11, color: "666666"
30
+ });
31
+
32
+ // Sections
33
+ const drawSection = (title, items, sY) => {
34
+ slide.addText(title, { x: x + 0.3, y: sY, w: w - 0.6, h: 0.3, bold: true, fontSize: 10 });
35
+ items.forEach((item, i) => {
36
+ slide.addText(`• ${item}`, { x: x + 0.3, y: sY + 0.3 + (i*0.25), w: w - 0.6, h: 0.25, fontSize: 9 });
37
+ });
38
+ };
39
+
40
+ if (persona.goals) drawSection("GOALS", persona.goals, y + 2.4);
41
+ if (persona.frustrations) drawSection("FRUSTRATIONS", persona.frustrations, y + 3.8);
42
+ }
43
+
44
+ module.exports = { addPersonaCard };
@@ -0,0 +1,47 @@
1
+ function addProcessCycle(slide, steps = [], options = {}) {
2
+ const {
3
+ x = 3, y = 3, radius = 2,
4
+ color = "007AFF"
5
+ } = options;
6
+
7
+ if (steps.length === 0) return;
8
+
9
+ const angleStep = (2 * Math.PI) / steps.length;
10
+
11
+ steps.forEach((step, index) => {
12
+ // Start from top ( -PI/2 )
13
+ const angle = index * angleStep - Math.PI / 2;
14
+
15
+ // Position for the circle center
16
+ const cx = x + radius * Math.cos(angle);
17
+ const cy = y + radius * Math.sin(angle);
18
+
19
+ // Circle Node
20
+ const nodeSize = 1.2;
21
+ slide.addShape("oval", {
22
+ x: cx - nodeSize/2,
23
+ y: cy - nodeSize/2,
24
+ w: nodeSize,
25
+ h: nodeSize,
26
+ fill: "FFFFFF",
27
+ line: { color: color, width: 3 }
28
+ });
29
+
30
+ // Step Number
31
+ slide.addText(String(index + 1), {
32
+ x: cx - nodeSize/2, y: cy - nodeSize/2, w: nodeSize, h: 0.4,
33
+ align: "center", valign: "bottom", fontSize: 14, bold: true, color: color
34
+ });
35
+
36
+ // Step Title
37
+ slide.addText(step, {
38
+ x: cx - nodeSize/2 + 0.1, y: cy, w: nodeSize - 0.2, h: 0.5,
39
+ align: "center", valign: "top", fontSize: 10
40
+ });
41
+
42
+ // (Optional) Simple Arrow/Line pointing to next could be added here
43
+ // using trigonometry for start/end points, but pure shapes are cleaner.
44
+ });
45
+ }
46
+
47
+ module.exports = { addProcessCycle };