PHPackages                             sugarcraft/candy-flip - 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. sugarcraft/candy-flip

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

sugarcraft/candy-flip
=====================

ASCII GIF viewer — port of namzug16/gifterm on the SugarCraft stack.

0303PHP

Since Jun 29Pushed 1mo agoCompare

[ Source](https://github.com/sugarcraft/candy-flip)[ Packagist](https://packagist.org/packages/sugarcraft/candy-flip)[ RSS](/packages/sugarcraft-candy-flip/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependenciesVersions (1)Used By (0)

[![candy-flip](.assets/icon.png)](.assets/icon.png)

CandyFlip
=========

[](#candyflip)

[![CI](https://github.com/detain/sugarcraft/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/detain/sugarcraft/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/431b0ab2eec89bc9bcff80760fe8f3f0f4228b3a854ac69560da8928cd7d4e80/68747470733a2f2f636f6465636f762e696f2f67682f64657461696e2f737567617263726166742f6272616e63682f6d61737465722f67726170682f62616467652e7376673f666c61673d63616e64792d666c6970)](https://app.codecov.io/gh/detain/sugarcraft?flags%5B0%5D=candy-flip)[![Packagist Version](https://camo.githubusercontent.com/85e159898b113b5b883bc85597cebbfe8690ef5d8dc387ac09ccdbbadc597d0c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f737567617263726166742f63616e64792d666c69703f6c6162656c3d7061636b6167697374)](https://packagist.org/packages/sugarcraft/candy-flip)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/e78ffc83837c0d12647811a7fd1910c3cbeae04988de94bb4fd5b67e0874696a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d254532253839254135382e312d3838393262662e737667)](https://www.php.net/)

[![demo](.vhs/play.gif)](.vhs/play.gif)

ASCII GIF viewer on the SugarCraft stack — port of [`namzug16/gifterm`](https://github.com/namzug16/gifterm). Decodes a `.gif` on disk via `ext-gd`, downsamples each frame to a configurable cell grid, and renders the animation into the terminal as ANSI-coloured Unicode block-glyphs at a configurable framerate.

```
composer require sugarcraft/candy-flip
candy-flip my-animation.gif         # solid-block preset (default)
candy-flip my-animation.gif density # ASCII luminance ramp
```

Keys
----

[](#keys)

KeyAction`Space`Pause / resume`←`Step back one frame`→`Step forward one frame`d`Toggle solid ↔ density preset`q` / `Esc`QuitImplementation notes
--------------------

[](#implementation-notes)

The decoder uses PHP's built-in `imagecreatefromstring()` for in-memory single-frame extraction — no temporary files are written to disk. It walks the GIF89a byte-stream manually to:

1. Parse the Logical Screen Descriptor and Global Color Table (GCT) from the header.
2. Walk the frame stream, extracting each frame's Graphic Control Extension (GCE) delay, disposal method (0–3), and transparent-color index.
3. Extract per-frame Local Color Table (LCT) when present; fall back to the GCT otherwise.
4. Reassemble a minimal single-frame GIF payload in memory and pass it to `imagecreatefromstring()`.
5. Area-average downsample the resulting `GdImage` to the requested cell grid, skipping transparent pixels in the average.

GIF parsing is hand-rolled to avoid loading the entire animation into a `GdImage` at once; each frame is decoded independently so memory usage stays bounded regardless of input size.

Architecture
------------

[](#architecture)

FileRole`Decoder`Reads the GIF, extracts per-frame GCE delay + disposal + transparency + local color table, hands each frame to GD via `imagecreatefromstring()`, area-average downsamples to a cell grid, returns a list of {@see Frame}.`Frame`Pure value — 2-D RGB grid in cell coordinates with per-frame `$delay` (centiseconds), `$disposal` method (0–3), and `$transparent` flag.`Downsampler`Image downsampler with two modes: `NEAREST` (center-pixel sample) and `AREA_AVERAGE` (area-weighted RGB average — higher quality, default).`Dither\FloydSteinberg`Floyd-Steinberg error-diffusion dithering against a fixed palette. Source image is not modified; returns a new `GdImage`.`Renderer`ANSI emitter. Two presets: `solid` (24-bit `█` blocks) or `density` (luminance ramp). `withAdaptiveSize()` queries the TTY via `SizeIoctl` so the output never overflows the viewport; `withConstraints()` accepts explicit row/col limits for testing.`Cache/FrameCache`WeakMap-backed memoization cache keyed by `Frame` object identity. Identical frames skip the rendering step on re-playback, and entries are dropped automatically when the `Frame` is garbage-collected.`Player`SugarCraft Model — index + paused + preset state. `Cmd::tick(...)` schedules frame advance using per-frame delays.`TickMsg`Frame-tick message produced by the Cmd.The decoder caps at 256 frames so a runaway file can't OOM the runtime; pause + manual step are always available even on long animations.

Test
----

[](#test)

```
composer install
vendor/bin/phpunit
```

Snapshot tests
--------------

[](#snapshot-tests)

Rendering output is pinned via `candy-testing`'s `assertGoldenAnsi` golden-file snapshots. Any change to the ANSI cell output must be intentional — re-record the fixture with `--update-golden` to accept a new canonical render.

###  Health Score

24

—

LowBetter than 31% of packages

Maintenance59

Moderate activity, may be stable

Popularity17

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

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.

### Community

Maintainers

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

---

Top Contributors

[![detain](https://avatars.githubusercontent.com/u/1364504?v=4)](https://github.com/detain "detain (84 commits)")

---

Tags

candycorecomposerphpsugarcraftterminaltui

### Embed Badge

![Health badge](/badges/sugarcraft-candy-flip/health.svg)

```
[![Health](https://phpackages.com/badges/sugarcraft-candy-flip/health.svg)](https://phpackages.com/packages/sugarcraft-candy-flip)
```

###  Alternatives

[illuminate/console

The Illuminate Console package.

13046.0M6.8k](/packages/illuminate-console)[styleci/cli

The CLI tool for StyleCI

71470.5k9](/packages/styleci-cli)[winbox/args

Windows command-line formatter

20720.9k21](/packages/winbox-args)[mallardduck/laravel-traits

A collection of useful Laravel snippets in the form of easy to use traits.

136.2k2](/packages/mallardduck-laravel-traits)

PHPackages © 2026

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