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

pretext-image-engine

v0.1.0

Published

A configurable image-aware text layout engine built on Pretext.

Readme

pretext-image-engine

A standalone, image-aware text layout engine built on @chenglou/pretext.

The engine takes:

  • a full base image
  • a same-canvas overlay image whose opaque pixels should stay in front
  • structured scene JSON for text, regions, colors, highlight, fallback, and debug behavior

It then tries to place text inside the transparent openings without covering the subject. If the opening gets too tight and preserveFullText is enabled, it falls back below the image so nothing disappears.

Why This Exists

This repo is intentionally isolated from any website implementation. It focuses on one thing:

image input plus overlay-mask parsing plus pretext text layout

The goal is a reusable engine for editorial-image compositions, not a site-specific component.

Features

  • Base-image plus overlay-mask composition
  • Row-by-row transparent-slot parsing from the overlay alpha
  • pretext-powered manual line layout
  • Region-aware layout for multi-opening overlays
  • Automatic dark/light text selection from sampled image luminance
  • Optional highlight pills or blocks for better legibility
  • Long-opening column splitting
  • Resize-aware fallback when full text should be preserved
  • Debug overlays for slots and regions
  • Package-friendly API plus demo app

Install

npm install pretext-image-engine

Local Development

npm install
npm run dev

Other commands:

npm run typecheck
npm test
npm run build:lib
npm run build:demo
npm run build
npm run preview

Basic Usage

import { createPretextImageEngine, type ImageEngineSceneConfig } from 'pretext-image-engine'

const scene: ImageEngineSceneConfig = {
  meta: {
    name: 'Demo scene',
    alt: 'A photo with an editorial opening.'
  },
  assets: {
    baseSrc: '/scenes/demo/base.png',
    overlaySrc: '/scenes/demo/overlay.png'
  },
  blocks: [
    { style: 'heading', text: 'Editorial image layout.' },
    { style: 'body', text: 'The overlay keeps the subject in front while the text flows into the transparent region.' }
  ]
}

const mount = document.getElementById('engine')

if (!mount) {
  throw new Error('Missing mount node')
}

const engine = createPretextImageEngine(mount, scene)
await engine.ready

Scene Config

The demo uses src/demo/sample-scene.json as a full reference scene.

There is also a schema file at schemas/scene.schema.json.

Main sections:

  • meta: scene identity and accessibility text
  • assets: base image, overlay image, alpha threshold, fit mode
  • stage: aspect ratio, minimum height, background, frame styling
  • layout: padding, min slot width, font downscaling, fallback trigger width
  • resize: whether to preserve full text and what fallback mode to use
  • colors: fixed or automatic text color, highlight behavior, shadows, selection colors
  • columnSplit: how long transparent strips can become multiple columns
  • interaction: whether text is selectable
  • debug: slot and region visualization
  • regions: named placement zones for multi-opening masks
  • styles: reusable typography presets for eyebrow, heading, lede, body, caption, or custom styles
  • blocks: the actual text content and per-block overrides

Multi-Opening Overlays

If your overlay has several transparent openings, there are two modes:

  • Automatic mode: blocks are laid out wherever the transparent slots fit best.
  • Region-aware mode: define named regions and assign blocks to them.

Example:

{
  "regions": {
    "sky": {
      "xStart": 0.58,
      "xEnd": 0.98,
      "yStart": 0.04,
      "yEnd": 0.42,
      "anchorX": 0.78
    },
    "water": {
      "xStart": 0.04,
      "xEnd": 0.72,
      "yStart": 0.5,
      "yEnd": 0.96,
      "anchorX": 0.22
    }
  },
  "blocks": [
    { "style": "heading", "region": "sky", "text": "Bridge into haze." },
    { "style": "body", "region": "water", "text": "Longer body copy..." }
  ]
}

Contrast and Highlight

The engine can sample the image under each line and switch automatically between light and dark text.

Highlights can be:

  • disabled
  • fixed-color pills or blocks
  • automatic pills/blocks that flip tone depending on the sampled background

That means you can keep text readable on haze, water, shadow, or mixed backgrounds without hard-coding one color for the whole image.

Long Empty Regions

If an opening becomes a long strip, columnSplit can break it into multiple sub-slots on the same band.

Key fields:

  • mode: off, auto, or fixed
  • preferredColumns
  • maxColumns
  • minColumnWidth
  • gap
  • applyToStyles

Resize Behavior

If resize.preserveFullText is true, the engine tries:

  1. masked in-image layout
  2. smaller font scales down to layout.minScale
  3. fallback below the image if the scene still does not fit

If resize.preserveFullText is false, the engine keeps the text in the image and allows clipping instead of falling back.

Demo Assets

The demo ships with a sample scene under:

public/scenes/san-francisco/

The preview app lets you:

  • resize the stage
  • toggle debug overlays
  • toggle text selection
  • edit the scene JSON directly

Package Surface

Exports:

  • createPretextImageEngine()
  • PretextImageEngine
  • TypeScript types for the scene config

Caveats

  • The engine assumes the base image and overlay share the same composition and alignment.
  • Automatic placement can only infer geometry. For art-directed multi-region layouts, define named regions.
  • Very small openings still need either shorter copy or fallback behavior.

License

MIT