PHPackages                             wazum/stipple - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [CLI &amp; Console](/categories/cli)
4. /
5. wazum/stipple

ActiveLibrary[CLI &amp; Console](/categories/cli)

wazum/stipple
=============

Render small SVG icons to monochrome ANSI for terminal UIs (Laravel/Prompts, Symfony Console, plain CLI).

v0.1.0(1mo ago)0637↑205.6%MITPHPPHP ^8.2

Since May 9Pushed 1mo agoCompare

[ Source](https://github.com/wazum/stipple)[ Packagist](https://packagist.org/packages/wazum/stipple)[ Docs](https://github.com/wazum/stipple)[ RSS](/packages/wazum-stipple/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (4)Versions (2)Used By (0)

stipple
=======

[](#stipple)

Render small SVG icons as monochrome ANSI in the terminal — pure PHP, zero system dependencies.

Drop it into any PHP CLI tool that wants real icons next to its menu items. The output is a plain string ending in `\n` per row — works equally well with `echo`, Symfony Console, Laravel/Prompts, or whatever else writes to a TTY. Two pluggable samplers ship: Braille (default) for highest density and half-block as a more universal fallback.

Preview
-------

[](#preview)

The [`actions-brand-github`](https://typo3.github.io/TYPO3.Icons/icons/actions/actions-brand-github.html) icon from [TYPO3.Icons](https://typo3.github.io/TYPO3.Icons/) (MIT-licensed) — source SVG and Braille rendering at heights 4, 6, 8:

[![actions-brand-github source SVG](examples/icons/actions-brand-github.svg)](examples/icons/actions-brand-github.svg)Source SVG (16×16)

```
⠀⢀⣠⣤⣤⣤⣀⠀
⢠⣿⡏⠋⠙⠋⣿⣧
⠸⣿⣇⠀⠀⢀⣿⣿
⠀⠙⠿⡅⠀⣿⠟⠁

```

Braille, `height(4)`

```
⠀⠀⠀⢀⣀⣀⣀⣀⣀⠀⠀⠀
⠀⢀⣴⡿⢿⣿⣿⣿⠿⣷⣄⠀
⠀⣿⣿⠇⠀⠀⠀⠀⠀⢿⣿⡇
⠀⣿⣿⡄⠀⠀⠀⠀⠀⣼⣿⡏
⠀⠹⣿⡿⠶⠀⠀⢰⣾⣿⡿⠁
⠀⠀⠈⠻⠶⠀⠀⠸⠟⠋⠀⠀

```

Braille, `height(6)`

```
⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀
⠀⠀⠀⣤⣶⣿⣿⣿⣿⣿⣿⣷⣦⡄⠀⠀
⠀⢀⣾⣿⡏⠉⠛⠛⠛⠛⠋⠉⣿⣿⣆⠀
⠀⣾⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⡆
⠀⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⡇
⠀⠹⣿⣿⣷⣤⣀⠀⠀⢀⣀⣴⣿⣿⡿⠁
⠀⠀⠙⢿⣮⣙⣋⠀⠀⢸⣿⣿⣿⠟⠁⠀
⠀⠀⠀⠀⠉⠛⠟⠀⠀⠘⠟⠋⠁⠀⠀⠀

```

Braille, `height(8)`

Same icon at `height(8)` rendered with the half-block sampler — coarser, but works in any terminal/font:

```
   ▄▄███████▄▄
  ███▀█▀▀██▀███
 ████       ████
 ████       ████
 ▀███▄     ▄████
  ▀███▀   ████▀
    ▀▀█   ██▀

```

Install
-------

[](#install)

```
composer require wazum/stipple
```

Requires PHP 8.2+ with `ext-gd`, `ext-mbstring`, `ext-dom`, `ext-simplexml`. No system binaries needed — rasterization is handled in pure PHP via [`meyfa/php-svg`](https://github.com/meyfa/php-svg).

Usage
-----

[](#usage)

```
use Wazum\Stipple\Stipple;

// One-shot, defaults: height 8 cells, terminal default fg, Braille sampler.
echo Stipple::render('/path/to/icon.svg');
echo Stipple::renderFromString('');

// Fluent
echo Stipple::make('/path/to/icon.svg')
    ->height(4)                // cells; valid 1..256
    ->color('#00ffff')         // optional, 6-digit hex; null → terminal default fg
    ->accent('#ff8700')        // overrides the fallback in any var(--icon-color-accent, …) call in the SVG
    ->threshold(0.5)           // alpha-weighted luminance cutoff in [0.0, 1.0]
    ->maxRasterDimension(2048) // safety cap on the intermediate raster (default 4096 px)
    ->toString();

// __toString delegates to toString(), so casting works too:
echo (string) Stipple::make('/path/to/icon.svg')->height(4);
```

The output is a plain string ending in `\n` per row, safe to `echo` or pass to Laravel/Prompts' `note()`/`info()`.

Samplers
--------

[](#samplers)

```
use Wazum\Stipple\Sampler\BrailleSampler;
use Wazum\Stipple\Sampler\HalfBlockSampler;

Stipple::make($path)->sampler(new BrailleSampler())->toString();   // default — 2x4 px/cell
Stipple::make($path)->sampler(new HalfBlockSampler())->toString(); // 1x2 px/cell, more universal
```

SamplerDensityGlyphsBest for`BrailleSampler` (default)2×4 px/cell`U+2800`–`U+28FF`Highest fidelity for line-art icons. Needs a Braille-capable monospace font (JetBrains Mono, Cascadia, DejaVu, Iosevka all work).`HalfBlockSampler`1×2 px/cell`▀ ▄ █`Universal — works in any terminal/font including legacy `cmd.exe`.For a 16×16 SVG at `height(4)` the Braille sampler maps 1:1 with the source pixel grid; at `height(8)` it super-samples 2×.

> **Alignment note.** Blank Braille cells emit `U+2800` so adjacent icons stay column-aligned in fonts that render `U+2800` narrower than other Braille glyphs. The half-block sampler emits raw spaces for blank rows — usually fine, but two icons rendered side-by-side may drift by a column on terminals/fonts that treat space and `█` as different widths.

Demo
----

[](#demo)

Two scripts are bundled in this repository. They run only from a checkout — the `bin/`and `examples/` directories are excluded from the Composer dist tarball, so they're not shipped to library consumers.

```
composer install
php bin/demo.php      # height 4/6/8 comparison across two samplers
php bin/icon-row.php  # ten icons rendered side-by-side in a single 4-line row
```

Pluggable rasterizer
--------------------

[](#pluggable-rasterizer)

The default rasterizer wraps `meyfa/php-svg`. You can swap in a different backend later by implementing `RasterizerInterface`:

```
use Wazum\Stipple\Rasterizer\RasterizerInterface;

final class RsvgConvertRasterizer implements RasterizerInterface
{
    public function rasterize(string $svg, int $widthPx, int $heightPx): \GdImage { /* … */ }
}

Stipple::make($path)->rasterizer(new RsvgConvertRasterizer())->toString();
```

Security
--------

[](#security)

The preprocessor hardens SVG input before rasterization:

- DOCTYPE / ENTITY declarations are rejected pre-parse (XXE attack surface).
- ``, ``, and **all ``** elements are rejected after parse — embedded raster is out of scope, and allowing `` would let the rasterizer dependency `file_get_contents()` arbitrary local files.
- libxml is invoked with `LIBXML_NONET` (no network).
- `currentColor` is substituted with a configurable foreground hex; `var(--icon-color-accent, ...)` is resolved DOM-side so the rasterizer never has to deal with CSS custom properties.

Supported SVG features
----------------------

[](#supported-svg-features)

The preprocessor handles common patterns found in icon SVGs from any source:

- `fill="currentColor"` and `stroke="currentColor"` — substituted with `#ffffff` so the rasterizer always renders at full luminance, regardless of the terminal foreground colour.
- `style="fill: currentColor; …"` — same substitution inside inline CSS, with other declarations preserved.
- `var(--icon-color-accent, )` — resolved DOM-side using either the configured `accent()` value or the embedded fallback hex (the rasterizer doesn't resolve CSS custom properties on its own).
- `viewBox` (space- or comma-separated) and root `width`/`height` numeric attributes for aspect-ratio resolution.

Anything not in the above list is passed through to the rasterizer untouched.

Development
-----------

[](#development)

```
composer install
vendor/bin/phpunit
vendor/bin/phpstan analyse src --level=8
```

License
-------

[](#license)

MIT — see [LICENSE](LICENSE). Bundled demo icons (`examples/icons/`) are MIT-licensed by the [TYPO3.Icons](https://github.com/TYPO3/TYPO3.Icons) project — see [THIRD\_PARTY\_NOTICES.md](THIRD_PARTY_NOTICES.md).

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity19

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

31d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/f4ea950f22b43e010ba4f0a6effb0928a6a1d11f64d36cec0d030b757bdfa85e?d=identicon)[wazum](/maintainers/wazum)

---

Top Contributors

[![wazum](https://avatars.githubusercontent.com/u/146727?v=4)](https://github.com/wazum "wazum (1 commits)")

---

Tags

cliterminaliconssvgansirendertuibraillehalf-block

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/wazum-stipple/health.svg)

```
[![Health](https://phpackages.com/badges/wazum-stipple/health.svg)](https://phpackages.com/packages/wazum-stipple)
```

###  Alternatives

[symfony/console

Eases the creation of beautiful and testable command line interfaces

9.8k1.1B13.1k](/packages/symfony-console)[league/climate

PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.

1.9k14.5M291](/packages/league-climate)[php-tui/php-tui

Comprehensive TUI library heavily influenced by Ratatui

596920.8k12](/packages/php-tui-php-tui)[php-school/cli-menu

A command line menu helper in PHP

2.0k1.2M30](/packages/php-school-cli-menu)[clue/term-react

Streaming terminal emulator, built on top of ReactPHP.

10410.7M2](/packages/clue-term-react)[aplus/cli

Aplus Framework CLI Library

2311.7M6](/packages/aplus-cli)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
