> opentype-js
Parse and manipulate OpenType/TrueType fonts with opentype.js — read font metadata, access glyph outlines, measure text, generate font subsets, and render text to SVG paths. Use when tasks involve custom text rendering, font analysis, glyph extraction, or building font tools.
curl "https://skillshub.wtf/TerminalSkills/skills/opentype-js?format=md"opentype.js
Read and write OpenType fonts. Access every glyph, measure text, convert to SVG paths.
Setup
# Install opentype.js for font parsing and manipulation.
npm install opentype.js
Loading a Font
// src/fonts/load.ts — Load a font from file or URL and read metadata.
import opentype from "opentype.js";
import fs from "fs";
// From file (Node.js)
const buffer = fs.readFileSync("./fonts/Inter-Regular.otf");
const font = opentype.parse(buffer.buffer);
console.log(font.names.fontFamily); // "Inter"
console.log(font.names.designer); // designer name
console.log(font.unitsPerEm); // 2048
console.log(font.numGlyphs); // total glyph count
Measuring Text
// src/fonts/measure.ts — Calculate text width and bounding box at a given size.
// Useful for layout engines and canvas text positioning.
import opentype from "opentype.js";
export function measureText(font: opentype.Font, text: string, fontSize: number) {
const path = font.getPath(text, 0, 0, fontSize);
const bb = path.getBoundingBox();
const advance = font.getAdvanceWidth(text, fontSize);
return {
width: advance,
height: bb.y2 - bb.y1,
boundingBox: { x1: bb.x1, y1: bb.y1, x2: bb.x2, y2: bb.y2 },
};
}
Rendering Text to SVG
// src/fonts/to-svg.ts — Convert a text string to an SVG path element.
// This produces resolution-independent text that doesn't require the font file.
import opentype from "opentype.js";
export function textToSvg(
font: opentype.Font,
text: string,
fontSize: number,
x: number,
y: number
): string {
const path = font.getPath(text, x, y, fontSize);
const pathData = path.toPathData(2); // precision
const bb = path.getBoundingBox();
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${bb.x1} ${bb.y1} ${bb.x2 - bb.x1} ${bb.y2 - bb.y1}">
<path d="${pathData}" fill="currentColor"/>
</svg>`;
}
Accessing Individual Glyphs
// src/fonts/glyphs.ts — Extract glyph outlines and metadata for specific characters.
import opentype from "opentype.js";
export function getGlyphInfo(font: opentype.Font, char: string) {
const glyph = font.charToGlyph(char);
const path = glyph.getPath(0, 0, 72);
return {
name: glyph.name,
unicode: glyph.unicode,
advanceWidth: glyph.advanceWidth,
pathData: path.toPathData(2),
commands: path.commands,
};
}
// List all glyphs in a font
export function listGlyphs(font: opentype.Font) {
const glyphs: { index: number; name: string; unicode: number | undefined }[] = [];
for (let i = 0; i < font.numGlyphs; i++) {
const g = font.glyphs.get(i);
glyphs.push({ index: i, name: g.name, unicode: g.unicode });
}
return glyphs;
}
Font Subsetting
// src/fonts/subset.ts — Create a subset font containing only the glyphs needed
// for a specific string. Reduces font file size for web embedding.
import opentype from "opentype.js";
import fs from "fs";
export function subsetFont(font: opentype.Font, chars: string, outputPath: string) {
const glyphs = [font.glyphs.get(0)]; // always include .notdef
const seen = new Set<number>();
for (const char of chars) {
const glyph = font.charToGlyph(char);
if (glyph.index !== 0 && !seen.has(glyph.index)) {
glyphs.push(glyph);
seen.add(glyph.index);
}
}
const subset = new opentype.Font({
familyName: font.names.fontFamily?.en || "Subset",
styleName: font.names.fontSubfamily?.en || "Regular",
unitsPerEm: font.unitsPerEm,
ascender: font.ascender,
descender: font.descender,
glyphs,
});
const buffer = Buffer.from(subset.download() as any);
fs.writeFileSync(outputPath, buffer);
}
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> xero-accounting
Integrate with the Xero accounting API to sync invoices, expenses, bank transactions, and contacts — and generate financial reports like P&L and balance sheet. Use when: connecting apps to Xero, automating bookkeeping workflows, syncing accounting data, or pulling financial reports programmatically.
> windsurf-rules
Configure Windsurf AI coding assistant with .windsurfrules and workspace rules. Use when: customizing Windsurf for a project, setting AI coding standards, creating team-shared Windsurf configurations, or tuning Cascade AI behavior.