
Research
/Security News
Critical Vulnerability in NestJS Devtools: Localhost RCE via Sandbox Escape
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
pptx-builder-js
Advanced tools
A TypeScript library for building PowerPoint (.pptx) files with template support and chart embedding
A powerful TypeScript library for creating PowerPoint (.pptx) presentations programmatically. Build professional presentations with charts, tables, shapes, images, and rich text formatting without relying on existing PPTX libraries.
# Using pnpm (recommended)
pnpm add pptx-builder-js
# Using npm
npm install pptx-builder-js
# Using yarn
yarn add pptx-builder-js
import { PowerPointBuilder, THEME_COLORS, TableRow } from "pptx-builder-js";
// Create a new presentation
const pptx = new PowerPointBuilder({
title: "My Presentation",
author: "John Doe",
subject: "Demo Presentation",
});
// Add a slide
const slide = pptx.addSlide("Welcome Slide");
// Add text
slide.addText(
"Hello, World!",
{ x: 100, y: 100 },
{ width: 400, height: 50 },
{ fontSize: 24, bold: true, color: "#0066CC" }
);
// Add a chart
const chartData = {
categories: ["Q1", "Q2", "Q3", "Q4"],
series: [
{
name: "Sales",
values: [100, 150, 200, 175],
color: THEME_COLORS.ACCENT_1,
},
],
title: "Quarterly Sales",
};
slide.addChart(
"column",
{ x: 50, y: 200 },
{ width: 500, height: 300 },
chartData
);
// Add a table
slide.addTable(
[
{
cells: [
{ content: "Product" },
{ content: "Sales" },
{ content: "Growth" },
],
style: {
fill: THEME_COLORS.ACCENT_1,
font: { bold: true, color: THEME_COLORS.LIGHT_1 },
borders: {
all: {
show: true,
color: "#333",
width: 2,
style: "solid",
},
},
},
},
{
cells: [
{ content: "Product A" },
{ content: "$100K" },
{
content: "+15%",
style: { font: { color: "#22C55E", bold: true } },
},
],
},
],
{ x: 50, y: 350 },
{ width: 400, height: 100 }
);
// Save the presentation
await pptx.saveToFile("my-presentation.pptx");
import { TableRow } from "pptx-builder-js";
const tableData: TableRow[] = [
{
// Header row
cells: [
{ content: "Name" },
{ content: "Position" },
{ content: "Salary" },
],
style: {
fill: "#4F46E5",
font: { bold: true, color: "#FFFFFF" },
textAlign: "center",
},
},
{
// Data row
cells: [
{ content: "John Doe" },
{ content: "Engineer" },
{ content: "$75,000" },
],
},
];
slide.addTable(tableData, { x: 50, y: 100 }, { width: 500, height: 150 });
// Set borders for all edges at once
const simpleTable: TableRow[] = [
{
cells: [
{
content: "All Red Borders",
style: {
borders: {
all: {
show: true,
color: "#FF0000",
width: 3,
style: "solid",
},
},
},
},
],
},
];
// Mix 'all' with individual edge overrides
const mixedBorders: TableRow[] = [
{
cells: [
{
content: "Blue base, Red top",
style: {
borders: {
all: {
show: true,
color: "#0000FF",
width: 1,
style: "solid",
},
top: {
show: true,
color: "#FF0000",
width: 4,
style: "solid",
},
},
},
},
],
},
];
// No borders (clean modern look)
const noBorders: TableRow[] = [
{
cells: [
{
content: "Clean look",
style: {
borders: { all: { show: false } },
},
},
],
},
];
const advancedTable: TableRow[] = [
{
cells: [{ content: "Product" }, { content: "Q1 Sales" }],
style: {
// Row-level styling
fill: "#F3F4F6",
font: { bold: true },
borders: {
all: { show: true, color: "#6B7280", width: 1, style: "solid" },
},
},
},
{
cells: [
{ content: "Widget A" },
{
content: "$25,000",
style: {
// Cell-level styling (highest priority)
fill: "#DCFCE7",
font: { color: "#22C55E", bold: true },
borders: {
all: {
show: true,
color: "#22C55E",
width: 2,
style: "solid",
},
},
},
},
],
},
];
slide.addTable(
advancedTable,
{ x: 50, y: 100 },
{ width: 400, height: 100 },
{
// Table-level styling (lowest priority)
style: {
globalBorders: {
all: { show: true, color: "#E5E7EB", width: 1, style: "solid" },
},
padding: { top: 10, bottom: 10, left: 12, right: 12 },
font: { family: "Arial", size: 11 },
},
}
);
slide.addTable(
tableData,
{ x: 50, y: 100 },
{ width: 600, height: 200 },
{
columns: [
{
style: {
fill: "#F3F4F6",
textAlign: "left",
font: { bold: true },
},
}, // Name column
{ style: { fill: "#EFF6FF", textAlign: "center" } }, // Position column
{
style: {
fill: "#ECFDF5",
textAlign: "right",
font: { family: "Courier New" },
},
}, // Salary column
],
style: {
globalBorders: {
all: { show: true, color: "#D1D5DB", width: 1, style: "solid" },
},
},
}
);
The table styling system follows a clear priority hierarchy:
import { ChartData, THEME_COLORS } from "pptx-builder-js";
const chartData: ChartData = {
categories: ["Q1", "Q2", "Q3", "Q4"],
series: [
{
name: "Revenue",
values: [25000, 32000, 28000, 35000],
color: THEME_COLORS.ACCENT_1,
},
{
name: "Expenses",
values: [18000, 22000, 20000, 25000],
color: THEME_COLORS.ACCENT_2,
},
],
title: "Quarterly Performance",
xAxisTitle: "Quarter",
yAxisTitle: "Amount ($)",
};
slide.addChart(
"column",
{ x: 50, y: 120 },
{ width: 650, height: 400 },
chartData
);
const styledChart: ChartData = {
categories: ["Product A", "Product B", "Product C"],
series: [
{
name: "Sales",
values: [1500000, 1200000, 1800000],
color: THEME_COLORS.ACCENT_1,
},
],
title: "Product Sales Analysis",
xAxisTitle: "Products",
yAxisTitle: "Sales ($)",
style: {
// Chart title styling
title: {
font: { family: "Calibri", size: 18, bold: true },
color: THEME_COLORS.DARK_1,
},
// X-axis comprehensive styling
xAxis: {
title: {
font: { family: "Calibri", size: 12, bold: true },
color: THEME_COLORS.DARK_1,
},
labels: {
font: { family: "Calibri", size: 10 },
color: THEME_COLORS.DARK_2,
rotation: -45, // Rotate labels
},
line: { show: true, color: THEME_COLORS.DARK_2, width: 1 },
tickMarks: {
major: { show: true, type: "out" },
minor: { show: false },
},
},
// Y-axis with number formatting and scaling
yAxis: {
title: {
font: { family: "Calibri", size: 12, bold: true },
color: THEME_COLORS.DARK_1,
},
labels: {
font: { family: "Calibri", size: 10 },
color: THEME_COLORS.DARK_2,
numberFormat: {
type: "currency",
currencySymbol: "$",
useThousandsSeparator: true,
decimalPlaces: 0,
},
},
scale: {
min: 0,
max: 2000000,
majorUnit: 500000,
},
tickMarks: {
major: { show: true, type: "out" },
minor: { show: true, type: "in" },
},
},
// Grid lines
gridLines: {
major: {
show: true,
color: Colors.variants.lighter80(THEME_COLORS.DARK_2),
width: 0.5,
style: "solid",
},
minor: {
show: false,
},
},
// Legend styling
legend: {
show: true,
position: "top",
font: { family: "Calibri", size: 10 },
color: THEME_COLORS.DARK_1,
},
// Data labels
dataLabels: {
show: true,
position: "outsideEnd",
font: { family: "Calibri", size: 9, bold: true },
color: THEME_COLORS.DARK_1,
numberFormat: {
type: "custom",
customFormat: '#,##0,"K"', // Thousands with K suffix
},
},
// Chart and plot area styling
chartArea: {
fill: THEME_COLORS.LIGHT_1,
border: { color: THEME_COLORS.DARK_2, width: 1, style: "solid" },
},
plotArea: {
fill: "#FFFFFF",
border: { color: THEME_COLORS.LIGHT_2, width: 0.5, style: "solid" },
},
},
};
// Currency formatting
numberFormat: {
type: "currency",
currencySymbol: "$",
useThousandsSeparator: true,
decimalPlaces: 2,
}
// Result: $1,234.56
// Percentage formatting
numberFormat: {
type: "percentage",
decimalPlaces: 1,
}
// Result: 15.3%
// Custom formatting
numberFormat: {
type: "custom",
customFormat: "#,##0.0,,\"M\"", // Millions with M suffix
}
// Result: 1.2M
// Scientific notation
numberFormat: {
type: "scientific",
decimalPlaces: 2,
}
// Result: 1.23E+06
import { Colors, COLOR_PALETTES, HEX_COLORS } from "pptx-builder-js";
// Individual column colors
const chartWithCustomColors: ChartData = {
categories: ["Q1", "Q2", "Q3", "Q4"],
series: [
{
name: "Sales",
values: [30000, 45000, 35000, 50000],
pointColors: [
"#FF0000", // Q1 - Red
THEME_COLORS.ACCENT_2, // Q2 - Theme color
Colors.rgb(0, 255, 0), // Q3 - Green (RGB)
Colors.lighter(THEME_COLORS.ACCENT_1, 0.4), // Q4 - Light accent
],
},
],
title: "Sales by Quarter",
};
// Using color palettes
const paletteChart: ChartData = {
categories: ["A", "B", "C", "D", "E", "F"],
series: [
{
name: "Revenue",
values: [120, 98, 150, 87, 134, 92],
pointColors: COLOR_PALETTES.BUSINESS, // Professional colors
},
],
title: "Product Revenue",
};
slide.addText(
"Styled Text Example",
{ x: 50, y: 100 },
{ width: 400, height: 50 },
{
fontSize: 24,
bold: true,
italic: false,
underline: true,
color: "#0066FF", // Blue hex color
fontFamily: "Arial",
textAlign: "center",
verticalAlign: "middle",
}
);
import {
Colors,
THEME_COLORS,
HEX_COLORS,
COLOR_PALETTES,
} from "pptx-builder-js";
// RGB Colors (Color objects) - using rgb() function
Colors.rgb(255, 0, 0); // Red: "#FF0000"
Colors.rgb(0, 0, 255); // Blue: "#0000FF"
Colors.rgb(0, 255, 0); // Green: "#00FF00"
Colors.rgb(255, 128, 0); // Custom RGB: "#FF8000"
// Hex Colors
("#FF0000"); // Direct hex string
HEX_COLORS.RED; // "#FF0000"
HEX_COLORS.BLUE; // "#0000FF"
// Theme Colors with Variants
THEME_COLORS.ACCENT_1; // Primary theme color
THEME_COLORS.ACCENT_2; // Secondary theme color
THEME_COLORS.DARK_1; // Dark theme color
THEME_COLORS.LIGHT_1; // Light theme color
// Color Variants
Colors.lighter(THEME_COLORS.ACCENT_1, 0.4); // 40% lighter
Colors.darker(THEME_COLORS.ACCENT_1, 0.3); // 30% darker
Colors.theme("accent2", 0.5); // Accent2 with 50% tint
// RGB to Hex conversion
const orangeColor = Colors.rgb(255, 165, 0); // Returns "#FFA500"
// Theme color creation
const lightAccent = Colors.theme("accent1", 0.6); // 60% lighter
const darkAccent = Colors.theme("accent1", -0.4); // 40% darker
// Quick theme helpers
const lightAccent2 = Colors.accent1(0.5); // Accent1 50% lighter
const darkAccent3 = Colors.accent2(-0.3); // Accent2 30% darker
// Professional business colors
COLOR_PALETTES.BUSINESS; // [accent1, accent2, accent3, ...]
// Bright, eye-catching colors
COLOR_PALETTES.VIBRANT; // ["#FF6B6B", "#4ECDC4", "#45B7D1", ...]
// Soft, muted colors
COLOR_PALETTES.PASTEL; // ["#FFB3BA", "#BAFFC9", "#BAE1FF", ...]
// Grayscale variations
COLOR_PALETTES.MONOCHROME; // ["#2C3E50", "#34495E", "#7F8C8D", ...]
// Natural earth tones
COLOR_PALETTES.EARTH; // ["#8B4513", "#A0522D", "#CD853F", ...]
// Primary accent colors
THEME_COLORS.ACCENT_1 through THEME_COLORS.ACCENT_6
// Text and background colors
THEME_COLORS.DARK_1, THEME_COLORS.DARK_2 // Dark colors
THEME_COLORS.LIGHT_1, THEME_COLORS.LIGHT_2 // Light colors
THEME_COLORS.BACKGROUND_1, THEME_COLORS.BACKGROUND_2 // Backgrounds
THEME_COLORS.TEXT_1, THEME_COLORS.TEXT_2 // Text colors
// Link colors
THEME_COLORS.HYPERLINK, THEME_COLORS.FOLLOWED_HYPERLINK
// Rectangle
slide.addShape(
"rectangle",
{ x: 100, y: 100 },
{ width: 200, height: 100 },
{
fill: "#ADD8E6", // Light blue
borderColor: "#0000FF", // Blue
borderWidth: 2,
}
);
// Circle
slide.addShape(
"circle",
{ x: 350, y: 100 },
{ width: 100, height: 100 },
{
fill: "#90EE90", // Light green
borderColor: "#00FF00", // Green
borderWidth: 3,
}
);
// Line
slide.addLine(
{ x: 50, y: 250 },
{ x: 450, y: 250 },
{
color: "#FF0000", // Red
width: 4,
style: "dash",
}
);
// Add image from file
slide.addImageFromFile(
"./path/to/image.png",
{ x: 100, y: 100 },
{ width: 300, height: 200 }
);
// Add image from buffer
const imageBuffer = fs.readFileSync("./image.jpg");
slide.addImageFromBuffer(
imageBuffer,
"jpg",
{ x: 100, y: 100 },
{ width: 300, height: 200 }
);
// Load and modify existing template
const pptx = await PowerPointBuilder.fromTemplate("template.pptx");
const slide = pptx.addSlide("New Slide");
// Add content to the slide...
await pptx.saveToFile("modified-presentation.pptx");
const pptx = new PowerPointBuilder({
title: "Annual Report 2024",
author: "Finance Team",
subject: "Financial Performance",
company: "Acme Corporation",
description: "Comprehensive financial analysis for 2024",
category: "Business",
keywords: ["finance", "annual", "report", "2024"],
created: new Date(),
modified: new Date(),
});
// Slide 1: Title slide
const titleSlide = pptx.addSlide("Annual Report 2024");
titleSlide.addText(
"Annual Report 2024",
{ x: 50, y: 100 },
{ width: 800, height: 100 },
{ fontSize: 36, bold: true, textAlign: "center" }
);
// Slide 2: Sales overview
const salesSlide = pptx.addSlide("Sales Overview");
salesSlide.addChart(/* chart configuration */);
// Slide 3: Financial summary
const financialSlide = pptx.addSlide("Financial Summary");
financialSlide.addTable(/* table configuration */);
PowerPoint uses a coordinate system measured in points (1/72 inch):
// Position element 50 points from left, 100 points from top
{ x: 50, y: 100 }
// Size element 400 points wide, 200 points tall
{ width: 400, height: 200 }
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with coverage
pnpm test:coverage
# Run specific test file
pnpm test chart-builder.test.ts
class PowerPointBuilder {
constructor(metadata?: PresentationMetadata);
addSlide(title: string): Slide;
static fromTemplate(templatePath: string): Promise<PowerPointBuilder>;
saveToFile(filePath: string): Promise<void>;
saveToBuffer(): Promise<Buffer>;
}
class Slide {
addText(
text: string,
position: Position,
dimensions: Dimensions,
style?: TextStyle
): void;
addChart(
type: ChartType,
data: ChartData[],
position: Position,
dimensions: Dimensions,
options?: ChartOptions
): void;
addTable(
rows: TableRow[],
position: Position,
dimensions: Dimensions,
options?: TableOptions
): void;
addShape(
type: ShapeType,
position: Position,
dimensions: Dimensions,
style?: ShapeStyle
): void;
addLine(start: Position, end: Position, style?: LineStyle): void;
addImageFromFile(
filePath: string,
position: Position,
dimensions: Dimensions
): void;
addImageFromBuffer(
buffer: Buffer,
format: string,
position: Position,
dimensions: Dimensions
): void;
}
interface Position {
x: number;
y: number;
}
interface Dimensions {
width: number;
height: number;
}
interface TableRow {
cells: TableCell[];
style?: TableRowStyle;
}
interface TableCell {
content: string;
colspan?: number;
rowspan?: number;
style?: TableCellStyle;
font?: FontStyle;
}
interface TableCellStyle {
fill?: ChartColor;
borders?: TableCellBorders;
textAlign?: "left" | "center" | "right" | "justify";
verticalAlign?: "top" | "middle" | "bottom";
padding?: TableCellPadding;
font?: FontStyle;
}
interface TableCellBorders {
// Individual edge control
top?: TableBorder;
bottom?: TableBorder;
left?: TableBorder;
right?: TableBorder;
// Simplified API: apply to all edges at once
all?: TableBorder;
}
interface TableBorder {
show?: boolean;
color?: ChartColor;
width?: number;
style?: "solid" | "dash" | "dot" | "dashDot" | "double";
}
# Clone the repository
git clone https://github.com/your-username/pptx-builder-js.git
cd pptx-builder-js
# Install dependencies
pnpm install
# Build the project
pnpm build
# Run tests
pnpm test
# Run the demo
pnpm demo
git checkout -b feature/amazing-feature
)git commit -m 'Add some amazing feature'
)git push origin feature/amazing-feature
)Please read our Contributing Guidelines for more details.
This project is licensed under the MIT License - see the LICENSE file for details.
Check out the /demo
folder for comprehensive examples:
# Run the advanced table demo
npx ts-node demo/advanced-table-demo.ts
# Run the main demo with charts
npx ts-node demo/demo.ts
# Run the simple test
npx ts-node demo/simple-test.ts
# Run the business presentation demo
npx ts-node demo/mavens.ts
borders: { all: {...} }
Before (verbose):
borders: {
top: { show: true, color: '#FF0000', width: 3 },
bottom: { show: true, color: '#FF0000', width: 3 },
left: { show: true, color: '#FF0000', width: 3 },
right: { show: true, color: '#FF0000', width: 3 }
}
Now (simplified):
borders: {
all: { show: true, color: '#FF0000', width: 3 }
}
Made with โค๏ธ by the pptx-builder-js team
FAQs
A TypeScript library for building PowerPoint (.pptx) files with template support and chart embedding
The npm package pptx-builder-js receives a total of 13 weekly downloads. As such, pptx-builder-js popularity was classified as not popular.
We found that pptx-builder-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.ย It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
Product
Customize license detection with Socketโs new license overlays: gain control, reduce noise, and handle edge cases with precision.
Product
Socket now supports Rust and Cargo, offering package search for all users and experimental SBOM generation for enterprise projects.