asciiqr

command module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 8 Imported by: 0

README

AsciiQR

Render text as a scannable QR code in your terminal.

┌─────────────────────────────────────┐
│                                     │
│                                     │
│    █▀▀▀▀▀█ ██▀▀▄ ▄█▀▄▀▀█ █▀▀▀▀▀█    │
│    █ ███ █ ▄▄█ ▄▀▀▀▄▄▀ ▄ █ ███ █    │
│    █ ▀▀▀ █  ▀█ ▀▀▄    █  █ ▀▀▀ █    │
│    ▀▀▀▀▀▀▀ █▄█ ▀▄█ ▀▄▀▄█ ▀▀▀▀▀▀▀    │
│    ▀ ▀█ ▀▀▀▄▄▀ ▄▀▀▄██▀█▄ █▄▄▀ ▀█    │
│    ▀▀▀ ▄▀▀█ █ ▀█▄██ ▀▄ ▀█▄▀▄ ▀▀▄    │
│    ▀▄ ▀▀▀▀  ▀ ▀▀▄   ▀▀█  ▄  ▀█▄▄    │
│    █▀▄█▀█▀▀▄▀▀▄▄▄▀ ▀▀▀██▄█▄▄ ▀█▀    │
│    ▀██▀▀▄▀▄▀▄█▄█▄ ▄▀ ▀▀▀  ▄▀█▄█     │
│    ▀  ▄▀█▀▄▀▄█▄▀  ▀▀▄█ ▀ ███ █      │
│     ▀▀  ▀▀ ▄▄▄ ▀█▄ ▄▀▀ █▀▀▀███▄▄    │
│    █▀▀▀▀▀█ █▄█▀▀▀  █ ▄▀█ ▀ ██ █▄    │
│    █ ███ █ ▄▀▄██▄█▄▄█ ▄▀█▀██▄▀▀▄    │
│    █ ▀▀▀ █ ▀▀▀ ▄▄▀▄ ▀  █▄ █ ▄▀▄▀    │
│    ▀▀▀▀▀▀▀ ▀▀   ▀▀▀  ▀▀▀▀▀    ▀     │
│                                     │
│                                     │
└─────────────────────────────────────┘

That code is real. Point your phone at it.

Install

go install github.com/jbrahy/asciiqr@latest

Usage

asciiqr "https://example.com"
echo "https://example.com" | asciiqr

Flags

Flag Default Description
-ec M Error-correction level: L (7%), M (15%), Q (25%), H (30%)
-ascii off Double-width ASCII (##) instead of half-blocks; no ANSI
-invert off Flip polarity
-no-color off Suppress ANSI colors, keep half-block glyphs
-no-frame off Omit the border drawn around the quiet zone
-version Print version and exit

Use it as a library

The packages are importable, so you can generate QR codes inside your own program without shelling out to the binary.

go get github.com/jbrahy/asciiqr
package main

import (
	"fmt"

	"github.com/jbrahy/asciiqr/qr"
	"github.com/jbrahy/asciiqr/render"
)

func main() {
	matrix, err := qr.Encode("https://example.com", qr.LevelMedium)
	if err != nil {
		panic(err)
	}

	fmt.Print(render.Render(matrix, render.Options{
		Mode:  render.HalfBlock, // or render.ASCII
		Frame: true,
		Color: true, // only when writing to a terminal
	}))
}

The API is deliberately small:

Symbol Purpose
qr.Encode(text, level) ([][]bool, error) Encode to a module matrix, indexed [row][col], true = dark, quiet zone included
qr.ParseLevel(string) (Level, error) Parse "L", "M", "Q", "H" (case-insensitive)
qr.QuietZone The 4-module margin constant
render.Render(matrix, Options) string Matrix to newline-terminated text
render.Options{Mode, Invert, Color, Frame} Rendering controls; zero value is half-block, no frame, no ANSI

render is pure — matrix in, string out, no I/O and no environment inspection — so it is safe to call from anywhere, including concurrently. Deciding whether the destination is a terminal is the caller's job.

Because qr.Encode returns a plain [][]bool, you can also skip the renderer entirely and draw the matrix yourself however you like.

Why it scans

Most terminal QR generators produce something that looks like a QR code. Four details decide whether a phone can actually read it, and each one fails silently:

Aspect ratio. Terminal cells are about twice as tall as they are wide, so one character per module yields a vertically stretched code that many scanners reject. AsciiQR packs two module rows into each line using half-block glyphs (▀ ▄ █), which restores square modules and halves the height.

Polarity. QR readers need dark modules on a light background. Print block characters in a dark-themed terminal and you get light-on-dark — inverted — which many phone scanners refuse. On a terminal, AsciiQR forces a white background with black text so the code reads correctly under any theme. When piped or redirected, ANSI is dropped and the output assumes a light background.

Quiet zone. The spec requires 4 light modules on every side; without them scanners cannot locate the symbol. The underlying encoder does not add one, so AsciiQR does.

The border. That quiet zone is whitespace, and whitespace is fragile — paste it anywhere that trims trailing spaces and the margin silently vanishes, taking scannability with it. The drawn frame sits entirely outside the quiet zone, making the margin visible and paste-safe without touching it.

Notes

Use -ascii for log files, plain-text documents, or terminals without UTF-8.

If the QR is wider than your terminal it will wrap and become unscannable. AsciiQR warns on stderr when that happens — shrink your terminal font, or use a lower -ec level to reduce the code's size.

Development

go test ./...

The suite decodes its own rendered output back to the original string across all four error-correction levels, both render modes, inverted polarity, framed output, and 600-byte content. A passing run is evidence the codes scan, not merely that the renderer agrees with itself.

Two limits are documented rather than glossed over, because the decoder is more forgiving than a phone is:

  • Round-trip tests cannot catch a missing quiet zone — the decoder reads a bare matrix with no border at all. Hardcoded assertions in qr cover it instead.
  • Round-trip tests cannot catch on-screen aspect ratio, since they rebuild a square-pixel image from the parsed grid.

Design notes and the implementation plan live in docs/superpowers/.

Credits

Created by John Brahy and Tre Brahy.

Built on yeqown/go-qrcode for encoding and makiuchi-d/gozxing for decode verification in tests.

License

MIT — see LICENSE.

Documentation

Overview

Command asciiqr renders text as a scannable QR code in the terminal.

Directories

Path Synopsis
Package qr encodes text into a QR code module matrix.
Package qr encodes text into a QR code module matrix.
Package render turns a QR module matrix into terminal text.
Package render turns a QR module matrix into terminal text.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL