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

@techspokes/ocr-box-geometry-descriptor

v1.2.0

Published

Transform OCR bounding boxes into LLM-friendly geometry descriptors

Readme

@techspokes/ocr-box-geometry-descriptor

Transform OCR bounding boxes into LLM-friendly geometry descriptors.

A TypeScript npm package that converts normalized bounding boxes (as produced by OCR engines) into rich, structured geometry descriptors. Pure math, zero runtime dependencies, works in Node.js, Cloudflare Workers, Deno, Bun, or any V8/ESM-compatible runtime.

Installation

npm install @techspokes/ocr-box-geometry-descriptor

Quick Start

import { describeBox } from '@techspokes/ocr-box-geometry-descriptor';

const descriptor = describeBox(
  { left: 0.58, top: 0.92, right: 0.93, bottom: 0.97 },
  { pageNumber: 1, totalPages: 11 },
);

console.log(descriptor.box_bands.primary_cell); // "bottom:center"
console.log(descriptor.box_size.width_percent);  // 35

Batch Processing (OCR Chunks)

Process an array of OCR chunks in one call. The grounding.page field is 0-based (as OCR engines emit); it is converted to 1-based internally.

import { describeBoxes } from '@techspokes/ocr-box-geometry-descriptor';

const descriptors = describeBoxes(ocrChunks, totalPages, { preset: 'portrait' });

If any chunk has invalid data, describeBoxes throws immediately (fail-fast). Wrap individual calls in try/catch if you need per-element tolerance.

Presets

Three built-in presets define the vertical/horizontal band boundaries for different page orientations:

| Preset | Vertical boundaries | Horizontal boundaries | |--------|--------------------|-----------------------| | portrait (default) | [0.05, 0.15, 0.82, 0.93] | [0.12, 0.88] | | landscape | [0.08, 0.18, 0.78, 0.90] | [0.08, 0.92] | | square | [0.08, 0.18, 0.82, 0.92] | [0.10, 0.90] |

Vertical boundaries produce 5 bands: top, upper, middle, lower, bottom. Horizontal boundaries produce 3 bands: left, center, right.

Inspect a preset:

import { getPreset } from '@techspokes/ocr-box-geometry-descriptor';

const bands = getPreset('portrait');
console.log(bands.vertical);   // [0.05, 0.15, 0.82, 0.93]
console.log(bands.horizontal); // [0.12, 0.88]

Custom Bands

Override the preset with explicit band boundaries:

describeBox(box, page, {
  bands: {
    vertical: [0.10, 0.20, 0.75, 0.90],
    horizontal: [0.15, 0.85],
  },
});

Resolution order: explicit bands > named preset > default ('portrait').

Output Schema

A GeometryDescriptor has this structure (all values are percentages rounded to 2 decimal places):

{
  "descriptor_version": "1.0",
  "box_in_document": {
    "page_number": 1,
    "total_pages": 11,
    "page_position_percent": 9.09,
    "is_first_page": true,
    "is_last_page": false
  },
  "box_edges": {
    "left_from_page_left": 58.36,
    "right_from_page_left": 92.84,
    "top_from_page_top": 92.15,
    "bottom_from_page_top": 96.95
  },
  "box_center": {
    "horizontal_from_page_left": 75.6,
    "vertical_from_page_top": 94.55
  },
  "box_size": {
    "width_percent": 34.48,
    "height_percent": 4.8,
    "area_percent": 1.66
  },
  "box_distance_to_page_edges": {
    "to_left": 58.36,
    "to_right": 7.16,
    "to_top": 92.15,
    "to_bottom": 3.05
  },
  "box_shape": {
    "aspect_ratio": 7.18,
    "is_wider_than_tall": true
  },
  "box_bands": {
    "primary_cell": "bottom:center",
    "start_cell": "lower:center",
    "end_cell": "bottom:right",
    "vertical_band": "bottom",
    "horizontal_band": "center",
    "spans_rows": true,
    "spans_columns": true,
    "row_span_count": 2,
    "column_span_count": 2,
    "overlap_cell": "bottom:center",
    "overlap_percent": 70.74,
    "all_cells": ["lower:center", "lower:right", "bottom:center", "bottom:right"]
  }
}

Coordinate Origin

By default, input coordinates use a top-left origin (standard for most OCR engines). For bottom-left origin systems (e.g., PDF coordinate space), pass origin: 'bottom-left':

describeBox(box, page, { origin: 'bottom-left' });

Warning Callback

Out-of-range values (< 0 or > 1) are clamped automatically. To capture clamping events, pass an onWarn callback:

describeBox(box, page, {
  onWarn: (msg) => console.warn(msg),
});

The callback is fire-and-forget. If it throws, the error propagates to the caller.

Percentage-Space Caveat

All size values (width_percent, height_percent, area_percent) and aspect_ratio are computed in percentage space (0-100), not physical space. The aspect_ratio is the ratio of width percent to height percent, which equals the physical aspect ratio only for square pages.

Workers Compatibility

This package is pure JavaScript with zero dependencies and no Node.js APIs. It works out of the box in Cloudflare Workers, Deno, Bun, or any V8-compatible runtime.

License

MIT