diff --git a/docs/scripts/generateOgImages.js b/docs/scripts/generateOgImages.js
index 42752c5..d64dd63 100644
--- a/docs/scripts/generateOgImages.js
+++ b/docs/scripts/generateOgImages.js
@@ -1,6 +1,7 @@
import fs from "fs";
import path from "path";
import { createContentLoader } from "vitepress";
+import sharp from "sharp";
// Colors
const COLORS = {
@@ -24,13 +25,67 @@ const FONT_FACE = {
SECONDARY: "Roboto",
};
-// Image paths
+// Image paths relative to project root
const IMAGES = {
- BACKGROUND: "../open-graph-background.png",
- LOGO: "../logo.png",
+ BACKGROUND: path.resolve(process.cwd(), "docs/public/images/open-graph-background.png"),
+ LOGO: path.resolve(process.cwd(), "docs/public/images/logo.png"),
};
-function buildOgImage({ title, summary, pageUrl }) {
+// Function to convert image to base64
+async function imageToBase64(imagePath) {
+ try {
+ const imageBuffer = await fs.promises.readFile(imagePath);
+ return `data:image/png;base64,${imageBuffer.toString('base64')}`;
+ } catch (error) {
+ console.error(`Error loading image ${imagePath}:`, error);
+ return null;
+ }
+}
+
+// Text wrapping function
+function wrapText(text, maxWidth, fontSize) {
+ const avgCharWidth = fontSize * 0.6;
+ const charsPerLine = Math.floor(maxWidth / avgCharWidth);
+ const words = text.split(' ');
+ const lines = [];
+ let currentLine = words[0];
+
+ for (let i = 1; i < words.length; i++) {
+ if (currentLine.length + words[i].length + 1 <= charsPerLine) {
+ currentLine += ' ' + words[i];
+ } else {
+ lines.push(currentLine);
+ currentLine = words[i];
+ }
+ }
+ lines.push(currentLine);
+
+ return lines;
+}
+
+async function buildOgImage({ title, summary, pageUrl }) {
+ // Load images as base64
+ const backgroundBase64 = await imageToBase64(IMAGES.BACKGROUND);
+ const logoBase64 = await imageToBase64(IMAGES.LOGO);
+
+ if (!backgroundBase64 || !logoBase64) {
+ throw new Error('Failed to load required images');
+ }
+
+ // Calculate wrapped text
+ const titleLines = wrapText(title, 1000, parseInt(FONT_SIZE.TITLE));
+ const summaryLines = wrapText(summary, 1100, parseInt(FONT_SIZE.SUMMARY));
+
+ // Generate title tspans with 1.5 line height
+ const titleTspans = titleLines.map((line, index) =>
+ `${line}`
+ ).join('');
+
+ // Generate summary tspans with 1.5 line height
+ const summaryTspans = summaryLines.map((line, index) =>
+ `${line}`
+ ).join('');
+
return `