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

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

sugarcraft/candy-shine
======================

PHP port of charmbracelet/glamour — Markdown → ANSI renderer with word-wrap, OSC 8 hyperlinks, syntax highlighting, and 8 stock themes (ansi/plain/dark/light/notty/dracula/tokyo-night/pink).

11.5kPHP

Since Jun 29Pushed 1mo agoCompare

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

READMEChangelogDependenciesVersions (1)Used By (0)

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

CandyShine
==========

[](#candyshine)

[![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/da1b44a30ab62b33d7faf98c0635591a09d936c84f8c4f7a55958de7314f32ae/68747470733a2f2f636f6465636f762e696f2f67682f64657461696e2f737567617263726166742f6272616e63682f6d61737465722f67726170682f62616467652e7376673f666c61673d63616e64792d7368696e65)](https://app.codecov.io/gh/detain/sugarcraft?flags%5B0%5D=candy-shine)[![Packagist Version](https://camo.githubusercontent.com/eed5227951029f4bd5662a319c744910c581ef890bbea4ff4059787ee4de6e95/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f737567617263726166742f63616e64792d7368696e653f6c6162656c3d7061636b6167697374)](https://packagist.org/packages/sugarcraft/candy-shine)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/fd3accad83cd317a9843432403191b4e555c55d57d63e10897f3f1dff5ed169e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d254532253839254135382e332d3838393262662e737667)](https://www.php.net/)

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

PHP port of [charmbracelet/glamour](https://github.com/charmbracelet/glamour) — Markdown → ANSI renderer built on `league/commonmark` and CandySprinkles.

```
composer require sugarcraft/candy-shine
```

> The `Renderer` exposes short-form aliases on every option: `theme` / `wordWrap` / `hyperlinks` / `baseURL` / `tableWrap` / `inlineTableLinks` / `preservedNewLines` / `emoji` / `standardStyle`. The upstream-mirroring `with*` long forms still work — pick whichever reads better at the call site.

Quickstart
----------

[](#quickstart)

```
use SugarCraft\Shine\Renderer;

echo (new Renderer())->render(render($markdown);
```

JSON shape: an object keyed by element name (`heading1`, `paragraph`, `bold`, `italic`, `code`, `codeBlock`, `link`, `blockquote`, `listMarker`, `rule`, `keyword`, `string`, `number`, `comment`, `strike`, `linkText`, `image`, `htmlBlock`, `htmlSpan`, `definitionTerm`, `definitionDescription`, `text`, `autolink`); each value carries `foreground` / `background` (hex / `ansi:N` / `ansi256:N`) plus the SGR flags (`bold`, `italic`, `underline`, `strike`, `faint`, `blink`, `reverse`).

Word-wrap + OSC 8 hyperlinks
----------------------------

[](#word-wrap--osc-8-hyperlinks)

```
$renderer = (new Renderer(Theme::dark()))
    ->withWordWrap(80)
    ->withHyperlinks(true);

echo $renderer->render($markdown);
```

`withHyperlinks(true)` (default) wraps every `[text](url)` in `OSC 8 ; ; URL ST text OSC 8 ; ; ST` so terminals that support it render real clickable links. Falls back to `text (url)` when off.

What it renders
---------------

[](#what-it-renders)

- Headings 1-6, paragraphs, `**bold**`, `_italic_`, `~~strike~~`.
- Inline code, fenced code blocks (with regex syntax highlighting for PHP / JS / TS / JSON / Python / Go / Bash / SQL), indented code.
- Bullet + ordered + nested lists.
- Block quotes (▎-prefixed).
- GFM tables (rendered via `Sprinkles\Table` with rounded border).
- Task lists (`☑` / `☐`).
- Links (with OSC 8 hyperlinks), autolinks, images (alt + url).
- HTML blocks + inline HTML — pass through with theme styling.
- Thematic breaks.

Authoring a custom theme
------------------------

[](#authoring-a-custom-theme)

A `Theme` is a value object — every slot is a `Style` (or scalar). Build one with the constructor and feed it to `new Renderer($theme)`:

```
use SugarCraft\Core\Util\Color;
use SugarCraft\Shine\Theme;
use SugarCraft\Sprinkles\Style;

$theme = new Theme(
    heading1:  Style::new()->bold()->underline()->foreground(Color::hex('#ff5f87')),
    heading2:  Style::new()->bold()->foreground(Color::hex('#ffd700')),
    heading3:  Style::new()->bold()->foreground(Color::ansi(14)),
    heading4:  Style::new()->bold()->foreground(Color::ansi(12)),
    heading5:  Style::new()->bold()->foreground(Color::ansi(13)),
    heading6:  Style::new()->bold()->foreground(Color::ansi(10)),
    paragraph: Style::new(),
    bold:      Style::new()->bold(),
    italic:    Style::new()->italic(),
    code:      Style::new()->foreground(Color::hex('#ffd700')),
    codeBlock: Style::new()->faint(),
    link:      Style::new()->underline()->foreground(Color::ansi(12)),
    blockquote: Style::new()->italic()->foreground(Color::ansi(8)),
    listMarker: Style::new()->foreground(Color::hex('#ff5f87')),
    rule:      Style::new()->foreground(Color::ansi(8)),

    // Element extensions:
    headingPrefix:    '❯ ',
    headingCase:      'upper',
    paragraphPrefix:  '  ',
    documentMargin:   1,
    listLevelIndent:  4,
    taskTickedGlyph:  '✓',
    taskUntickedGlyph:'·',
    horizontalRuleGlyph: '═',
    horizontalRuleLength: 60,
);

echo (new Renderer($theme))->render($markdown);
```

The full slot reference (left-to-right reading the constructor):

BlockSlotsHeadings`heading1` … `heading6` (with `headingPrefix`, `headingSuffix`, `headingCase`)Paragraphs`paragraph` (+ `paragraphPrefix` / `paragraphSuffix`)Inline`bold` · `italic` · `strike` · `code` · `link` · `linkText` · `autolink` · `image` · `imageText` · `text`Block`codeBlock` · `blockquote` · `rule` · `listMarker` · `htmlBlock` · `htmlSpan`Document`documentMargin` · `documentIndent` · `documentBlockPrefix` / `Suffix`Lists`orderedListMarker` · `unorderedListMarker` · `orderedListMarkerFormat` · `unorderedListMarkerGlyph` · `listLevelIndent`Task list`taskTickedGlyph` · `taskUntickedGlyph`Horizontal rule`horizontalRuleGlyph` · `horizontalRuleLength`Tables`tableHeader` · `tableCell` · `tableSeparator` · `tableCenterSeparator` · `tableColumnSeparator` · `tableRowSeparator`Definition lists`definitionTerm` · `definitionDescription` · `definitionList`Syntax highlighting`keyword` · `string` · `number` · `comment`Stock themes (`Theme::ansi()`, `Theme::dark()`, `Theme::dracula()`, `Theme::tokyoNight()`, `Theme::pink()`, `Theme::light()`, `Theme::ascii()`, `Theme::notty()`, `Theme::plain()`) are good starting points — copy the constructor call and adjust the slots you care about.

`Theme::fromEnvironment(?$default)` reads `GLAMOUR_STYLE` (case- insensitive, hyphen / underscore tolerant) so users can override the theme without code changes:

```
GLAMOUR_STYLE=tokyo-night php examples/render.php
```

Renderer options
----------------

[](#renderer-options)

```
new Renderer($theme)
    ->withWordWrap(80)               // wrap paragraphs / blockquotes / lists
    ->withHyperlinks(true)           // emit OSC 8 link envelopes
    ->withBaseURL('https://docs.example.com/')  // prefix relative links
    ->withTableWrap(true)            // wrap text inside table cells
    ->withInlineTableLinks(false)    // suppress (url) suffix in cells
    ->withPreservedNewLines(true)    // keep `\n\n+` runs from source
    ->withStandardStyle('dracula')   // re-pick the stock theme
    ->withEmoji(true);               // expand `:smile:` shortcodes
```

`Renderer::renderMarkdown($md, ?Theme)` is a one-shot static convenience for ad-hoc rendering. For repeated renders with the same theme, build a Renderer and reuse it (the parser is cached per instance).

Test
----

[](#test)

```
cd candy-shine && composer install && vendor/bin/phpunit
```

Demos
-----

[](#demos)

### Render

[](#render)

[![render](.vhs/render.gif)](.vhs/render.gif)

### Themes

[](#themes)

[![themes](.vhs/themes.gif)](.vhs/themes.gif)

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

[](#snapshot-tests)

Render output is covered by golden-file snapshot tests. Fixture files live in `tests/fixtures/` with a `.golden` extension and are compared against actual ANSI byte output via `SugarCraft\Testing\Snapshot\Assertions::assertGoldenAnsi()`. To re-record fixtures after intentional output changes:

```
UPDATE_GOLDENS=1 vendor/bin/phpunit
```

Related
-------

[](#related)

- [SugarCraft monorepo](https://github.com/detain/sugarcraft)
- Upstream: [charmbracelet/glamour](https://github.com/charmbracelet/glamour)

###  Health Score

26

—

LowBetter than 41% of packages

Maintenance59

Moderate activity, may be stable

Popularity22

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 99% 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 (102 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

ansicandycorecatppuccincode-highlightingcommonmarkdraculaglamourglamour-porthyperlinkmarkdownmarkdown-renderermarkdown-to-ansinordosc8syntax-highlightingterminalthemestuiword-wrap

### Embed Badge

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

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

###  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)
