npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bekesh

v0.2.0

Published

Browser-first Persian and Arabic kashida justification

Downloads

0

Readme

Bekesh

Bekesh is an opinionated ESM-only browser library that fits a line of Persian or Arabic text set in a naskh-style font to a target width. It inserts U+0640 ARABIC TATWEEL at contextually appropriate elongation points, then returns CSS word spacing for the remaining width.

Bekesh measures the requested font in the browser and verifies its result against DOM layout. Its candidate rules use letter families, positional forms, joined-run length, and explicit naskh prohibitions. If a word has no suitable elongation point, Bekesh leaves that width to word spacing instead of using an arbitrary connection.

Install

pnpm add bekesh

Or: npm install bekesh

Usage

import { justifyWithKashida } from "bekesh";

const sourceText = "توانا بود هر که دانا بود";
const font = '32px "Scheherazade New"';
const lang = "fa";
const result = await justifyWithKashida({
  text: sourceText,
  targetWidth: 420,
  font,
  lang,
});

element.textContent = result.displayText;
element.lang = lang;
element.style.font = font;
element.style.wordSpacing = `${result.wordSpacing}px`;
element.style.direction = "rtl";
element.style.whiteSpace = "pre";

Pass clean source text on every call. displayText contains presentation characters and should not replace the original text in application state. targetWidth is a CSS-pixel content width. Make sure to render with the same language, font, and RTL direction used for measurement! white-space: pre preserves spaces and keeps the text on one line.

An existing bare U+0640 is treated as an author-selected elongation point and receives the highest candidate priority. A tatweel carrying a combining mark remains a mark seat and is not treated as an elongation signal.

justifyWithKashida() waits for the requested font through the CSS Font Loading API. It uses Canvas for candidate search, verifies the fitted text and word spacing in a hidden DOM element, and backs off when the browser's inline layout would exceed the target.

API

function justifyWithKashida(options: JustifyOptions): Promise<JustificationResult>;

JustifyOptions contains:

  • text: clean source text; it is not mutated or normalized
  • targetWidth: desired inline width in CSS pixels
  • font: a valid CSS font shorthand, including the font size
  • lang: optional shaping language, "fa" (default) or "ar"
  • tolerance: optional permitted overshoot in CSS pixels; defaults to zero

The result includes the source and display strings, measured widths, width remaining after tatweels, per-space wordSpacing, inserted tatweel edits, and diagnostic strings. If the clean source text already exceeds the target width, Bekesh returns it unchanged with the source-overflows-target diagnostic.

diagnostics contains values from the exported JustificationDiagnostic type:

  • source-overflows-target: the clean source is already too wide and is returned unchanged
  • no-adjustable-spaces: residual width remains, but the source contains no U+0020 spaces to which word spacing can be applied
  • iteration-safety-limit-reached: the pure solver reached its bounded iteration limit
  • dom-verification-adjusted: DOM verification reduced the Canvas-selected tatweels or word spacing
  • dom-verification-fallback: bounded DOM refitting could not find a verified edited result, so the fitting step fell back to clean source text

The package also exports measureDomText(text, font, lang?) for synchronous DOM measurement, plus the JustifyOptions, JustificationResult, JustificationDiagnostic, and TatweelEdit types. Language defaults to "fa". measureDomText() does not load fonts; wait for the relevant face before calling this function when the font may not be ready:

await document.fonts.load(font, text);
const width = measureDomText(text, font, "ar");

Browser and layout requirements

Bekesh requires a modern browser with ES modules, the DOM, Canvas 2D, document.fonts, and Intl.Segmenter support. It has no runtime dependencies.

Measurement currently models the CSS font shorthand, the selected language, RTL direction, and returned word spacing. Font features, variation settings, letter spacing, transforms, fallback selection, and other shaping inputs are not API options. If those differ between measurement and rendering, the final element can have a different width. Padding and borders are likewise outside targetWidth.

Bekesh fits one line at a time. It does not break paragraphs into lines, shrink overlong source text, or implement calligraphic glyph elongation. Bekesh sets the measurement language to Persian or Arabic and the direction to RTL; the browser handles bidi, shaping, and font fallback. This library's rules are designed for Persian and Arabic text in naskh-style fonts, not as a universal Arabic-script justification model. Candidate choice remains heuristic, so please review it with the fonts and texts that your application supports.

Research and prior art

This repository also maintains the research that informed the implementation:

Research notes prefer primary sources and pin code observations to revisions where possible. U+0640 output is treated as a reversible presentation artifact, not source text.

Development

pnpm install
pnpm check
pnpm test:browser

test:browser is an opt-in integration suite. It expects a system Playwright installation with Chromium, Firefox, and WebKit, and downloads a pinned Scheherazade New font into the operating system's temporary directory. The normal test and check commands do not require Playwright or network access.

One way to provide the system browser tooling is:

volta install playwright
playwright install chromium firefox webkit

If Playwright is installed elsewhere, set BEKESH_PLAYWRIGHT_PATH to its package directory.

License

Bekesh is available under the MIT License. See third-party notices for the provenance and terms of the compact Unicode joining-property data.