From c8b4f81f6b03177825f51d08cd1848f53a633543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E6=B5=B7=20Liang=20Hai?= Date: Wed, 1 Jul 2026 00:16:42 +0200 Subject: [PATCH 1/5] Modernize and simplify the example code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now the API’s documentation is well accessible in editors, this example can be simplified so it looks less scary. --- README.md | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 6c1bda0..aad1bac 100644 --- a/README.md +++ b/README.md @@ -30,35 +30,29 @@ The v1 release introduced several API-breaking changes. See [MIGRATING](MIGRATIN ### TL;DR -```javascript +```js import * as hb from "harfbuzzjs"; -const fontdata = await fetch('myfont.ttf').then(r => r.arrayBuffer()); -const blob = new hb.Blob(fontdata); // Load the font data into Harfbuzz blob -const face = new hb.Face(blob, 0); // Select the first font in the file -const font = new hb.Font(face); // Create a Harfbuzz font object from the face -const buffer = new hb.Buffer(); // Make a buffer to hold some text -buffer.addText('abc'); // Fill it with some stuff -buffer.guessSegmentProperties(); // Set script, language and direction -hb.shape(font, buffer); // Shape the text -const output = buffer.getGlyphInfosAndPositions(); - -// Enumerate the glyphs -var xCursor = 0; -var yCursor = 0; -for (var glyph of output) { - var glyphId = glyph.codepoint; - var xAdvance = glyph.xAdvance; - var yAdvance = glyph.yAdvance; - var xDisplacement = glyph.xOffset; - var yDisplacement = glyph.yOffset; - - var svgPath = font.glyphToPath(glyphId); - // You need to supply this bit - drawAGlyph(svgPath, xCursor + xDisplacement, yCursor + yDisplacement); - - xCursor += xAdvance; - yCursor += yAdvance; +// Load data from a font file: +const response = await fetch("font.ttf"); +const arrayBuffer = await response.arrayBuffer(); + +// Create a HarfBuzz font object from the data: +const blob = new hb.Blob(arrayBuffer); +const face = new hb.Face(blob); +const font = new hb.Font(face); + +// Shape text in a HarfBuzz buffer with the font: +const buffer = new hb.Buffer(); +buffer.addText("abc"); +buffer.guessSegmentProperties(); +hb.shape(font, buffer); + +// Enumerate the resulted glyphs in the buffer: +for (const glyph of buffer.getGlyphInfosAndPositions()) { + const gid = glyph.codepoint; // Glyph ID despite the property name + const { xAdvance, yAdvance, xOffset, yOffset } = glyph; + const svgPath = font.glyphToPath(gid); } ``` From 606e80331172ff899e478c89e342f94e8f9c3ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E6=B5=B7=20Liang=20Hai?= Date: Wed, 1 Jul 2026 00:44:01 +0200 Subject: [PATCH 2/5] Reorganize README Group related sections. Move usage examples to be before the development section. Revise formats. --- README.md | 57 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index aad1bac..2638b25 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ # harfbuzzjs
-

harfbuzzjs Logo

- -[![Build](https://github.com/harfbuzz/harfbuzzjs/actions/workflows/build.yml/badge.svg)](https://github.com/harfbuzz/harfbuzzjs/actions/workflows/build.yml) -[![NPM Version](https://img.shields.io/npm/v/harfbuzzjs)](https://www.npmjs.com/package/harfbuzzjs) +

harfbuzzjs Logo

+ [![Build](https://github.com/harfbuzz/harfbuzzjs/actions/workflows/build.yml/badge.svg)](https://github.com/harfbuzz/harfbuzzjs/actions/workflows/build.yml) + [![NPM Version](https://img.shields.io/npm/v/harfbuzzjs)](https://www.npmjs.com/package/harfbuzzjs)
Providing [HarfBuzz](https://github.com/harfbuzz/harfbuzz) shaping @@ -13,22 +12,19 @@ library for client/server side JavaScript projects. See the demo [here](https://harfbuzz.github.io/harfbuzzjs/demo/). -## Building -1. Install emscripten -2. `make` +## Download -## Testing -1. `make test` +From the repo's [releases](https://github.com/harfbuzz/harfbuzzjs/releases), or npm: -## Download -Download from the [releases tab](https://github.com/harfbuzz/harfbuzzjs/releases). +``` +npm install harfbuzzjs +``` ## Migrating from v0.x -The v1 release introduced several API-breaking changes. See [MIGRATING](MIGRATING.md) for migrating from v0.x. -## Usage +The v1 release introduced several API-breaking changes. See [MIGRATING](MIGRATING.md) for migrating from v0.x. -### TL;DR +## Usage examples ```js import * as hb from "harfbuzzjs"; @@ -56,20 +52,35 @@ for (const glyph of buffer.getGlyphInfosAndPositions()) { } ``` -More examples: +### Alternative browser example + +``` +npx pad.js +``` + +Then open http://127.0.0.1/examples/harfbuzz.example.html. + +### Node.js example + +``` +node examples/harfbuzz.example.node.js +``` + +## Development -### Browser +### Building -1. `npx pad.js` -2. Open `http://127.0.0.1/examples/harfbuzz.example.html` +First install [emscripten](https://emscripten.org), then: -### Node.js +``` +make +``` -1. `node examples/harfbuzz.example.node.js` +### Testing -## [npm](https://www.npmjs.com/package/harfbuzzjs) -Can be added with `npm i harfbuzzjs` or `yarn add harfbuzzjs`, see the examples for -how to use it. +``` +make test +``` ## Need more of the library? From 47bbeceba69fb3466b823579644dccd86215b5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E6=B5=B7=20Liang=20Hai?= Date: Wed, 1 Jul 2026 00:52:35 +0200 Subject: [PATCH 3/5] Simplify examples --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2638b25..3a01a7e 100644 --- a/README.md +++ b/README.md @@ -54,17 +54,15 @@ for (const glyph of buffer.getGlyphInfosAndPositions()) { ### Alternative browser example +See [examples/harfbuzz.example.html](examples/harfbuzz.example.html). To quickly run it in a browser: + ``` -npx pad.js +npx http-server -o /examples/harfbuzz.example.html ``` -Then open http://127.0.0.1/examples/harfbuzz.example.html. - ### Node.js example -``` -node examples/harfbuzz.example.node.js -``` +See [examples/harfbuzz.example.node.js](examples/harfbuzz.example.node.js). ## Development From 9eb408612abb206c8e4b6cd814b344b60b698556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E6=B5=B7=20Liang=20Hai?= Date: Wed, 1 Jul 2026 01:11:21 +0200 Subject: [PATCH 4/5] Simplify the Node.js example Focus on how to load a file. --- examples/harfbuzz.example.node.js | 35 +++++++++++-------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/examples/harfbuzz.example.node.js b/examples/harfbuzz.example.node.js index e78d83c..bd4c860 100644 --- a/examples/harfbuzz.example.node.js +++ b/examples/harfbuzz.example.node.js @@ -1,29 +1,18 @@ import fs from "node:fs"; import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { Blob, Face, Font, Buffer, shape } from "../dist/index.mjs"; +import * as hb from "harfbuzzjs"; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -function example(fontPath, text) { - var blob = new Blob(fs.readFileSync(fontPath)); - var face = new Face(blob, 0); - var font = new Font(face); +const nodeBuffer = fs.readFileSync( + path.join(import.meta.dirname, "../test/fonts/noto/NotoSans-Regular.ttf"), +); - var buffer = new Buffer(); - buffer.addText(text || "abc"); - buffer.guessSegmentProperties(); - shape(font, buffer); +const blob = new hb.Blob(nodeBuffer); +const face = new hb.Face(blob); +const font = new hb.Font(face); - return buffer.getGlyphInfosAndPositions(); -} +const buffer = new hb.Buffer(); +buffer.addText("abc"); +buffer.guessSegmentProperties(); +hb.shape(font, buffer); -console.log( - example(path.resolve(__dirname, "../test/fonts/noto/NotoSans-Regular.ttf")), -); -console.log( - example( - path.resolve(__dirname, "../test/fonts/noto/NotoSansArabic-Variable.ttf"), - "أبجد", - ), -); +console.log(buffer.getGlyphInfosAndPositions()); From bd6a79d7426dd5b732053ab02e9d3751b3bc8d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E6=B5=B7=20Liang=20Hai?= Date: Wed, 1 Jul 2026 01:45:08 +0200 Subject: [PATCH 5/5] Use .getGlyphPositions() in examples .getGlyphInfosAndPositions() is quite cumbersome in practice because of the Partial. --- README.md | 10 +++++++--- examples/harfbuzz.example.node.js | 14 +++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a01a7e..aa9b90c 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,14 @@ buffer.guessSegmentProperties(); hb.shape(font, buffer); // Enumerate the resulted glyphs in the buffer: -for (const glyph of buffer.getGlyphInfosAndPositions()) { +const infos = buffer.getGlyphInfos(); +const positions = buffer.getGlyphPositions(); +for (const [index, glyph] of infos.entries()) { const gid = glyph.codepoint; // Glyph ID despite the property name - const { xAdvance, yAdvance, xOffset, yOffset } = glyph; - const svgPath = font.glyphToPath(gid); + console.log( + font.glyphToPath(gid), // SVG path + positions[index], // xAdvance, yAdvance, xOffset, yOffset + ); } ``` diff --git a/examples/harfbuzz.example.node.js b/examples/harfbuzz.example.node.js index bd4c860..ca06bd8 100644 --- a/examples/harfbuzz.example.node.js +++ b/examples/harfbuzz.example.node.js @@ -2,17 +2,29 @@ import fs from "node:fs"; import path from "node:path"; import * as hb from "harfbuzzjs"; +// Load data from a font file: const nodeBuffer = fs.readFileSync( path.join(import.meta.dirname, "../test/fonts/noto/NotoSans-Regular.ttf"), ); +// Create a HarfBuzz font object from the data: const blob = new hb.Blob(nodeBuffer); const face = new hb.Face(blob); const font = new hb.Font(face); +// Shape text in a HarfBuzz buffer with the font: const buffer = new hb.Buffer(); buffer.addText("abc"); buffer.guessSegmentProperties(); hb.shape(font, buffer); -console.log(buffer.getGlyphInfosAndPositions()); +// Enumerate the resulted glyphs in the buffer: +const infos = buffer.getGlyphInfos(); +const positions = buffer.getGlyphPositions(); +for (const [index, glyph] of infos.entries()) { + const gid = glyph.codepoint; // Glyph ID despite the property name + console.log( + font.glyphToPath(gid), // SVG path + positions[index], // xAdvance, yAdvance, xOffset, yOffset + ); +}