PowerShell ColorScripts Enhanced

PowerShell ColorScripts Enhanced by Typpi / Nick2bad4u

View on GitHub

ANSI to ColorScript Conversion Guide

Looking for turnkey demos? See docs/examples/ansi-conversion/ for scripts that wrap the commands below.

Quick Start

Convert a single ANSI file:

.\Convert-AnsiToColorScript.ps1 -AnsiFile "myart.ans"

Batch Conversion

Convert all .ans files in a directory:

Get-ChildItem -Path "C:\ANSI-Art" -Filter "*.ans" | .\Convert-AnsiToColorScript.ps1

Advanced Options

Custom Output Name

.\Convert-AnsiToColorScript.ps1 -AnsiFile "art.ans" -OutputFile "my-custom-script.ps1"

Add Header Comments

.\Convert-AnsiToColorScript.ps1 -AnsiFile "art.ans" -AddComment

Verbose Mode

# See detailed information about conversion process
.\Convert-AnsiToColorScript.ps1 -AnsiFile "art.ans" -Verbose

# Example outputs:
# VERBOSE: Detected single-line ANSI file with cursor positioning - converting to multi-line format
# VERBOSE: Detected 80-column wrapped ANSI file - splitting into multiple lines
# VERBOSE: Detected multi-line ANSI file with some long lines - wrapping at 80 columns

Custom Output Directory

.\Convert-AnsiToColorScript.ps1 -AnsiFile "art.ans" -OutputDirectory ".\CustomScripts"

Preserve an Already-Formatted ANSI Stream

Use passthrough only when the decoded source already contains its final sequential SGR and line-ending stream and does not rely on cursor movement or terminal emulation:

.\Convert-AnsiToColorScript-Advanced.ps1 -AnsiFile "plant.ansi" -Encoding utf8 -Passthrough

Passthrough preserves the decoded source byte-for-byte inside one safe PowerShell literal and emits it with Write-Host -NoNewline. This retains exact color transitions, CRLF geometry, and trailing line endings. Provenance-backed imports record ConversionMode = 'Passthrough' externally; standalone legacy output keeps the equivalent verbose comment. Content-curation tooling reads either form and treats it as a source-fidelity lock. Artwork containing cursor positioning, erase commands, overstrikes, or terminal-width wrapping must use terminal emulation instead.

How It Works

  1. Reads the ANSI file - Uses CP437 (DOS/OEM) encoding to properly handle box-drawing and extended ASCII characters
  2. Converts to Unicode - Preserves all ANSI escape sequences and special characters
  3. Wraps in PowerShell - Creates a script using a safe, single-quoted multiline Write-Host literal. Terminal-emulated art starts below the opening quote so it has a leading display margin; passthrough output remains byte-exact.
  4. Saves to Scripts folder - Automatically places in ColorScripts-Enhanced/Scripts
  5. Auto-naming - Converts filename to lowercase with hyphens (PowerShell convention)

The ordinary single-quoted literal is intentional. A single-quoted here-string (@' ... '@) is also non-interpolating, but it adds a line-oriented terminator that archival text can collide with. A double-quoted here-string (@" ... "@) is unsafe for arbitrary artwork because PowerShell expands dollar-prefixed variables, subexpressions, and backtick escapes. The serializer instead doubles literal apostrophes and keeps every other artwork character as data.

For curated third-party imports, pass --provenance-record=<json-path>. The JSON keys use the authoritative audit/ArtworkProvenance.psd1 property names. The converter emits one compact offline title/artist attribution plus a script-scoped details URL, derives the source hash, geometry, encoding, conversion, and SAUCE/iCE fields, and updates the external PSD1 in the same rollback-safe transaction as the generated script. --provenance-path=<psd1-path> is available for fixtures; repository imports should use the default. The older --source-* options remain for standalone output and intentionally produce verbose comments.

ANSI File Format

The converter supports standard ANSI art files (.ans) which contain:

Single-Line ANSI Files

Some ANSI files don’t use traditional newlines. The converter automatically detects and converts these formats:

Format 1: Cursor Positioning

Files that use cursor positioning commands instead of newlines:

Before (single-line with positioning)

ESC[1;1HRed TextESC[2;1HGreen TextESC[3;1HBlue Text

After (multi-line with newlines)

Red Text
Green Text
Blue Text

Supported cursor commands

Format 2: 80-Column Wrapped

Files where all content is on one long line meant to wrap every 80 visible characters:

Before (single long line)

████████...████ ▄▄ ▄▄▄...▄▄ ██ ██ ▀ ▄...▄ ▀ ██...

After (split at 80 columns)

████████...████
██ ▄▄ ▄▄▄...▄▄ ██
██ ▀ ▄...▄ ▀ ██

Format 3: Mixed Format (Some Lines Need Wrapping)

Files with multiple lines where some individual lines exceed 80 characters:

Before (mixed line lengths)

Normal line (75 chars)
Very long line exceeding 80 chars that needs wrapping... (160 chars)
Another normal line (60 chars)

After (long lines split at 80)

Normal line (75 chars)
Very long line exceeding 80 chars that needs wrapping... (first 80)
(continuation of long line)
Another normal line (60 chars)

Detection: The converter checks each line and wraps any line with >100 visible characters.

The converter counts only visible characters - ANSI escape codes don’t count toward the 80-character width.

Examples

Example 1: Simple Conversion

# Input: dragon.ans
# Output: dragon.ps1 (in ColorScripts-Enhanced/Scripts)
.\Convert-AnsiToColorScript.ps1 -AnsiFile "dragon.ans"

Example 2: Batch with Comments

Get-ChildItem "*.ans" | ForEach-Object {
    .\Convert-AnsiToColorScript.ps1 -AnsiFile $_.FullName -AddComment
}

Example 3: Preview Before Converting

# Traditional .ANS files normally use CP437, not the platform's default text encoding.
$bytes = [System.IO.File]::ReadAllBytes((Resolve-Path "art.ans"))
$cp437 = [System.Text.Encoding]::GetEncoding(437)
$cp437.GetString($bytes) | Write-Host

# If it looks good, convert it
.\Convert-AnsiToColorScript.ps1 -AnsiFile "art.ans"

Tips

  1. Choose the source encoding deliberately - Traditional DOS/BBS .ANS art normally uses CP437. Use UTF-8 only when the source is known to be Unicode.
  2. Use the advanced converter when needed - Convert-AnsiToColorScript-Advanced.ps1 defaults to -Encoding cp437 and accepts -Encoding utf8 for known UTF-8 input.
  3. Inspect generated code - Review a generated .ps1 before executing art obtained from an untrusted source.
  4. File Naming - The converter normalizes names to lowercase PowerShell script names.
  5. Generated Encoding - Generated .ps1 files use UTF-8 with a BOM so non-ASCII art is decoded correctly by Windows PowerShell 5.1. This is separate from the encoding of the source .ANS file.

Troubleshooting

Characters Display as ?? or �

This happens when ANSI files using CP437 (DOS) encoding are incorrectly read as UTF-8. The fix is to re-convert the file:

# Re-convert with proper encoding support (included in latest version)
.\Convert-AnsiToColorScript.ps1 -AnsiFile "yourfile.ans" -OutputFile "yourfile.ps1"

Why this happens

Colors Look Wrong

Characters Display Incorrectly

Empty Output

Where to Find ANSI Art

Popular sources for ANSI art files:

Archive availability does not imply that every work is public domain or compatible with this project’s license. Record the source URL, artist/pack attribution, and applicable license or permission for every imported file.

Reviewed Collections

The collection now contains curated subsets from these sources. See Artwork Sources and Provenance for browse/download links, inclusion counts, exact licensing evidence, and the excluded Roy/SAC other-artists gallery.

Collection Approximate size Repository license Integration note
jifunks/botany 72 files reviewed ISC 17 sequential ANSI streams imported with byte-preserving passthrough conversion.
NNB/os-ansi 36 files reviewed ISC 2 genuinely multicolor files imported; 34 monochrome or duotone files rejected.
Asciiville 946 files reviewed MIT for the imported project wordmark 1 byte-preserved nine-color wordmark imported; image-derived and restricted galleries excluded.
Durdraw 16 examples reviewed BSD-3-Clause 1 native 80-by-32 ANSI stream imported; .dur animations require a frame-aware parser.
Roy/SAC ANSI gallery, official downloads, and 16colors 62 download archives plus live 16colors Roy inventory reviewed FAL-1.3 for each converted Roy file 126 unique Roy-authored works represented by 153 scripts; 2 .BIN files are outside the supported .ANS/.ICE scope.
16colors 5,479 enumerated packs and 64,929 .ANS or .ICE candidates reviewed for 1990-2026 Project-specific artist/rightsholder permission with attribution 15,073 retained works emitted as 21,495 scripts after content, adult-policy, quality, source-continuity, promotional-content, and duplicate-render curation; every archive year has a checked-in inventory fingerprint and disposition total.
HyFetch Many distro logos MIT Uses application-specific templates/placeholders, so it needs a purpose-built importer rather than raw .ANS conversion.

After Conversion

Once converted, your scripts will:

  1. Be automatically discovered by Get-ColorScriptList
  2. Work with Show-ColorScript -Name your-script
  3. Follow the deterministic bundled static-extraction path without executing script code
  4. Support discovery, metadata, filtering, and display through ColorScripts-Enhanced

Only expensive renderers explicitly listed in CachePolicy.psd1 use output caching. Do not add a static converted artwork to that policy merely because it is frequently displayed.

Example Workflow

# 1. Download or create ANSI art
# 2. Convert to PowerShell
.\Convert-AnsiToColorScript.ps1 -AnsiFile "cool-art.ans" -AddComment

# 3. Test it
Show-ColorScript -Name cool-art

# 4. List your script
Get-ColorScriptList -Name cool-art

Integration with Module

The converted scripts work seamlessly with ColorScripts-Enhanced:

# Import the module
Import-Module ColorScripts-Enhanced

# Your converted ANSI art is now available
Show-ColorScript -Name dragon

# Add to your profile for startup
Add-ColorScriptProfile -DefaultStartupScript dragon

Advanced Utilities

Split Super-Tall ANSI Art

For ANSI files that are too tall to display comfortably, use Split-AnsiFile.js:

# Preview suggested splits without writing files (looks for 4+ blank rows)
node scripts/Split-AnsiFile.js .\we-ACiDTrip.ANS --auto --dry-run

# Generate three 300-line chunks as PowerShell scripts
node scripts/Split-AnsiFile.js .\we-ACiDTrip.ANS --heights=300,300,300

# Emit ANSI slices instead of .ps1 wrappers
node scripts/Split-AnsiFile.js .\we-ACiDTrip.ANS --format=ansi --breaks=420,840

# Split an already converted colorscript
node scripts/Split-AnsiFile.js .\ColorScripts-Enhanced\Scripts\we-acidtrip.ps1 --input=ps1 --heights=320,320

# Split every 160 lines automatically
node scripts/Split-AnsiFile.js .\we-ACiDTrip.ANS --every=160

# Split a wide ANSI file only at reviewed logical panel boundaries
node scripts/Split-AnsiFile.js .\wide-menu.ANS --columns=160 --column-ranges=1-80,81-160

Options

Each provenance-backed PowerShell part records its original rendered line and column ranges in the external PSD1. Legacy standalone output keeps those ranges in comments. Horizontal slicing reconstructs the active SGR state from terminal cells at each panel boundary instead of cutting serialized escape sequences. Provenance values use the same validation rules as the main JavaScript converter, so untrusted metadata cannot inject executable source.

Each output chunk is normalized with a trailing ESC[0m so the terminal resets cleanly after display.

When the raw ANSI/ICE source is available, verify the generated family against the original rendered terminal cells:

node .\scripts\Verify-AnsiConversion.mjs `
  --source=.\ZII-UBBS.ANS `
  --prefix=16c-mist-30-zii-ubbs `
  --json=.\temp\zii-ubbs-verification.json

Verify-AnsiConversion.mjs checks every declared source-row and source-column slice, compares rendered characters and style state, and requires the selected scripts to cover the complete source canvas. This deterministically catches lost colors, squishing, reflow, cropping, shifted cells, stripped background-colored spaces, and missing blank rows. Use repeated --script options for explicit files, or --allow-partial when intentionally verifying only selected parts.

For collection-wide curation queues, run:

node .\scripts\Analyze-ColorScripts.mjs `
  --type=mergeable-adjacent-parts `
  --type=avoidable-extra-part `
  --type=dense-split-boundary `
  --type=continuous-split-review `
  --type=tiny-tail-part `
  --type=leading-blank-run `
  --type=trailing-blank-run `
  --type=mostly-plain-ascii `
  --type=low-structural-complexity `
  --type=low-color-variety `
  --type=suspicious-character-decoding `
  --json=.\temp\gallery-analysis.json

These are review signals, not automatic deletion rules. In particular, valid CP437 art intentionally decodes block and box-drawing bytes to Unicode, so a high extended-character ratio is not evidence of a bad conversion. Exact cell comparison is the fidelity test; complexity, density, and palette measurements help prioritize human review.

dense-split-boundary means the current cut crosses dense artwork even though a nearby blank boundary could keep every part within the row limit. continuous-split-review means both sides of the cut are dense and no such blank boundary exists. The latter requires a preview review: retain it only when every emitted part is a coherent standalone gallery entry; otherwise the source does not fit the random gallery even when its conversion is exact.

Use the queues according to the defect being investigated:

Review concern Relevant issue types
Unnecessary or undersized split parts mergeable-adjacent-parts, avoidable-extra-part, tiny-tail-part, very-small-output
Cuts through artwork or blank separators at part edges dense-split-boundary, continuous-split-review, leading-blank-run, trailing-blank-run
Repetitive, sparse, or unusually simple output low-cell-variety, low-structural-complexity, sparse-cell-density, low-color-variety
Mostly basic ASCII rather than CP437/block art mostly-plain-ascii
Actual decoding damage suspicious-character-decoding

SAUCE tInfo2 height remains provenance metadata; it is not proof that the stream reached the declared row count. Some files reserve a taller SAUCE canvas than their ANSI stream, while their official previews stop at the stream extent. The converter therefore preserves real source/cursor blank rows but does not manufacture unused trailing rows from SAUCE height alone. Likewise, a run of three or four blank rows is not automatically wrong: it may be an intentional separator between complete panels. Review it against the source preview before moving or removing it.

Other Developer Utilities

The repository includes additional helpers for developers:

See the npm Scripts Reference for complete details on development utilities.