CuB3y0nd/entropic
CuB3y0nd/entropic has 36 GitHub stars and 8 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-14 18:40 UTC. Last push 2026-10-12.
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
About
A retro textmode blog theme for purists.
SecurityREADME.md
OriginalEntropic
Entropic is a retro textmode blog theme for purists.
The implementation uses Astro, Vite, and Tailwind CSS utilities. The surface
uses fixed-width text, ASCII frames, volume indexes, ANSI colors, bitmap CJK
glyphs, and plain .phile documents.
Configuration
Edit entropic.config.ts at the repository root. It is the single entry for
site identity, home sections, 88x31 buttons, decorative artwork, colors,
effects, volume metadata, CVE records, analytics, and optional WKD publishing.
You do not need to edit files inside src/ to customize these settings.
The checked-in file is also the personal site configuration. home.asciiArt
inherits the banner from src/config/defaults.ts unless overridden; WKD and
the CVE page are explicitly enabled.
Set cves.enabled: false to omit the CVE page, its homepage links, and its sitemap
entry; the records can remain in cves.records for later use.
Article inspection and fragment links are enabled by default. Select article
text to inspect a value or prepare a link to that passage, then copy with your
browser's native Copy action. Fragment links locate the quoted text and briefly
highlight it; repeated passages need enough context to identify one match.
Set philes.inspect: false or philes.fragmentLinks: false to disable either
tool. Disabling fragment links also disables incoming passage navigation.
The file is a plain TypeScript object with as const satisfies EntropicConfig.
Your editor provides field descriptions and completion, including artwork
preset names and rotation modes. Omitted settings inherit internal defaults;
objects merge at documented leaves and arrays replace their defaults.
pnpm check:config
validate values, artwork selection, and optional public key input
pnpm check
also check unknown fields/types, source boundaries, and formatting
pnpm dev
preview configuration edits locally
Field comments in entropic.config.ts describe supported values, examples,
and default inheritance. The configuration types live in src/config/types.ts.
Directory Layout
entropic.config.ts the user-editable configuration
src/config/ internal types, defaults, validation, and projections
src/content/philes/ article source files
src/pages/ Astro file routes and HTTP output adapters
src/features/ home, site-badges, philes, volumes, cves, seo, and wkd
src/shared/textmode/ text cells, ANSI, bitmap CJK, and browser behaviors
src/shared/browser/ browser lifecycle helpers
src/layouts/ shared page shells
src/styles/ foundation, layer ordering, and responsive rules
src/assets/decorations/ original artwork grouped by series
src/generated/ generated glyph metadata
scripts/ font generation, checks, and Git hooks
tests/ configuration, content, browser, and security regressions
Features own their data access, rendering, components, and styles. Shared
textmode primitives have separate pure, server, and browser entry points.
Cross-feature imports use public entries; pnpm check:boundaries verifies
these interfaces and keeps server dependencies out of browser modules.
Tailwind handles common layout and spacing. Pixel typography, ANSI/CJK output, and animation rules live in native CSS. Theme utilities use the typed configuration; Preflight is not enabled. Astro bundles styles from their owning components and modules instead of loading every feature's CSS on every page.
Content
Articles are .phile files under:
src/content/philes/volume-*/**/*.phile
A phile is a frontmatter block followed by plain text.
Required fields:
title
date
Optional fields:
order
slug
redacted
lang
decoration
math
Credits come from each file's Git history, including renames and Co-authored-by trailers. The original author appears first, followed by contributors in order of first participation. GitHub nicknames are preferred; accounts without a nickname use their login. Unlinked identities keep their Git author name. A new, uncommitted article has no credits yet.
Names are resolved once per production build and embedded in the static pages. No GitHub requests run in the browser. Builds restore shallow history before reading credits; Vercel checkouts without an origin use its Git system variables. An optional build-time GITHUB_TOKEN increases the API request allowance. Cached profiles provide a fallback when GitHub is unavailable.
The body is rendered as textmode content. It preserves layout, wraps to the configured article width, renders images, accepts ANSI escape sequences, and supports the custom ink block syntax.
Set math: true in an article's frontmatter to render LaTeX formulas with
Temml. Use $...$ or \(...\) inline, and $$...$$ or \[...\] for display
equations. Standalone tall expressions also receive display space. Math is
converted to native MathML at build time; unsupported
commands fail the build. Code spans and fenced code keep their TeX literal.
The bundled Entropic Math font derives from STIX Two Math's CFF font:
https://github.com/stipub/stixfonts/releases/latest
Its license is included in fonts/STIXTwoMath.LICENSE.
Radical size variants have their short horizontal caps trimmed so
MathML's overbar joins directly to the diagonal without a pixel step. Other
glyph outlines are unchanged. Fraction, radical, overbar and underbar rule
thicknesses use 0.05em to avoid two-pixel bars at the article's 16/17px sizes.
Run pnpm fonts:math to regenerate from the latest upstream release (requires
uv). The script checks the radical geometry before replacing the font and
records the resolved source URL and SHA-256 in the font's metadata. Normal
builds and page visits use the bundled font without fetching upstream.
Temml requires a browser with native MathML support. Equation references
(\ref and \eqref) are not wired into the site's rendering pipeline yet.
Math articles retain the textmode font and colors, with unframed equations
aligned to the body. Prose wraps to the viewport; long equations scroll within
their own region instead of shrinking the entire article. Articles without
math: true retain the original text rendering, including literal dollar signs.
Ink style reference:
https://www.cubeyond.net/volume/3/ansi-ink-phile/
Article header artwork is chosen from the article's public URL. It stays the
same across reloads, rebuilds, and adding/removing other articles. Renaming its
slug or moving it to another volume can choose a different effect. The default
pool is life, maze (depth-first maze carving), sort (insertion sort),
bits (four byte registers), asm (a small assembly loop), and reorder
(out-of-order execution with in-order retirement). No extra controls interrupt
the reading layout.
Configure the pool and playback in entropic.config.ts:
philes: {
decoration: {
effects: ["life", "maze", "sort", "bits", "asm", "reorder"],
animated: true,
speed: 1
}
}
Omitted options inherit these defaults. effects must contain at least one
unique algorithm; use a single item to show the same effect everywhere.
Reordering the pool does not reshuffle articles. For the new effects, speed
ranges from 0.25 to 4 and animated: false keeps a still frame. The new artwork
also stays visible without JavaScript. Life uses its original renderer, grid,
color, and timing; these playback options do not change it. All effects
pause offscreen, in hidden tabs, and for reduced motion.
Set decoration: maze (or any other effect name) in an article's frontmatter
to pin its effect, including one outside the global pool. decoration: false
removes that article's artwork and closes the unused header space.
philes.decoration: false disables all article artwork, including overrides.
The processor illustrations use native Gohu text at the article's font size.
bits highlights the bits changed by XOR, rotate, and shift operations. asm
shows an executed instruction with its resulting registers and flags. reorder
shows dependency waits and two execution slots; completed instructions remain
in the queue until all earlier instructions can retire.
Example:
---
title: "Example"
date: 2026-05-31
---
--[ Summary ]-------------------------------------------------------------
target : ...
primitive : ...
--[ ink ]--
| 00400000-00401000 r--p 00000000 ./a.out ; ELF headers
~ BBBBBBBB.BBBBBBBB GGKK KKKKKKKK MMMMMMM
| 00401000-00402000 r-xp 00001000 ./a.out ; executable text
~ BBBBBBBB.BBBBBBBB GGRR KKKKKKKK MMMMMMM
#[B|B] address range
#[G|G] readable permission
#[R|R] executable permission
#[K|K] offset / padding
#[M|M] mapped object
Volumes
Volume numbers come from the directory name:
volume-0
volume-1
volume-2
The public routes are:
/volume/<n>/
/volume/<n>/<phile-name>/
Per-volume behavior is configured in entropic.config.ts under volumes.
Only the fields supplied for a volume override its generated defaults.
Set decoration to circuit, archive, study, or prism for a themed header
illustration. life keeps the original Game of Life frame and is the default
for unconfigured volumes; false removes the decoration. For example:
volumes: {
0: { title: "Security Research", decoration: "circuit" },
1: { title: "Historical Philes", decoration: "archive" }
}
The four illustrations also accept an options object:
decoration: {
kind: "study",
animated: true,
speed: 1,
calendar: { month: 12, day: 31 }
}
animated: false keeps a static illustration. speed is a playback multiplier
from 0.25 to 4: 0.5 is half speed, 2 is double speed. These optional settings
default to true and 1. calendar is only for study and defaults to December
31; use a numeric month and a valid day (February 29 is supported). The original
life frame uses the string shorthand. Every CPU transfer independently samples
an 8-bit value, including 00 and FF; consecutive random values may repeat.
The new illustrations remain visible without JavaScript. Their motion pauses
offscreen, in hidden tabs, and when reduced motion is requested. Article
headers use the separate philes.decoration settings described above.
Redactions
A redacted phile uses:
redacted: true
The loader discards redacted bodies from the content store and the public page renders the redacted screen. The pre-commit hook parses staged YAML with the same parser and unstages redacted philes, leaving the worktree untouched. Install dependencies before using the hook. Invalid frontmatter blocks the commit before the hook changes the index.
Redaction is a publishing flag, not secret storage: it does not erase files from existing Git history. Keep confidential source material outside Git.
Enable hooks in a fresh clone:
git config core.hooksPath scripts/hooks
Site Badges and Artwork
entropic.config.ts groups links and decoration under buttons. The default
rotates through all 25 presets daily in Asia/Shanghai:
buttons: {
items: [/* your 88x31 links or copy controls */],
shuffleOnBuild: true,
artwork: {
mode: "daily",
timeZone: "Asia/Shanghai",
seed: "entropic-artwork-v1",
fallback: "nagaraNozomi"
}
}
All visitors with the same date see the same composition, including after a refresh. Each cycle shuffles every selected preset once and avoids repeats at the cycle boundary. The date is checked on load and when returning to a tab or cached page; a continuously open page does not swap on a timer. No daily rebuild, endpoint, cookie, or browser storage is needed.
Use artwork: false for links alone, or
artwork: { mode: "fixed", preset: "nagaraNozomi" } for a fixed image.
An empty items array hides the panel. The inline configuration comments cover
custom images, preset pools, interval/visit modes, and the no-JavaScript fallback.
shuffleOnBuild: true shuffles buttons once per production build and keeps
that order across visits and artwork changes. Local development uses items order.
Each item supplies label, imageSrc, and either href or copyText.
Artwork originals live under src/assets/decorations/<series>/. Presets retain
the approved display sizes, overlap, and companion placement. Astro builds 1x
and 2x WebP images with lossless encoding; originals remain unchanged. Inert HTML
templates keep unselected compositions from fetching images. The shareable
animated site badge stays at /assets/88x31/button.gif for other sites to link to.
CSS grid and container queries own layout. Overlapped badges appear above the artwork on hover or keyboard focus; touch devices show them immediately. Artwork is decorative and cannot intercept link activation.
Commands
Use Node.js 24 or newer and the pinned pnpm 12.3.4. pnpm check:types runs
Astro diagnostics with the official TS 6 compatibility API and the native
TypeScript 7 checker. Keep both aliases until Astro supports the new API.
pnpm install --frozen-lockfile
install dependencies
pnpm dev
run the local development server
pnpm check
run Astro and TypeScript diagnostics, formatting/lint, and module boundaries
pnpm format
format TS/JS/CSS/JSON with Biome and Astro templates with Prettier
pnpm lint
lint the files covered by Biome
pnpm build
build the static site
pnpm test
run content, textmode, redaction-hook, and WKD regression tests
pnpm exec playwright install chromium firefox
install the browser revisions used by this Playwright version
pnpm test:browser http://127.0.0.1:4329
check fitting, animation lifecycle, and site badges against a production preview
set PLAYWRIGHT_BROWSER=firefox to use Firefox
pnpm test:wkd
verify optional WKD generation and key handling
pnpm assets:fonts
regenerate font subsets and CJK atlases
Font assets are committed. Normal production builds do not require local font tooling.
Run pnpm assets:fonts only when the committed font outputs need to change:
after editing font source files under `fonts/`
after changing CJK glyph coverage or bitmap atlas generation
after changing text that introduces new CJK glyphs which must render via
the bitmap CJK atlas
after changing the font subset scripts themselves
The command regenerates:
public/assets/fonts/gohu-subset.woff
public/assets/cjk/wqy-cjk-body.png
public/assets/cjk/wqy-cjk-link.png
src/generated/cjk-atlas.ts
Regenerating these assets requires fonttools. If pyftsubset is already on
PATH, the scripts use it directly. Otherwise, with uv installed, the
scripts resolve fonttools automatically and keep the uv cache under /tmp.
Branches
master is stable. dev is integration.
Feature and fix work should branch from dev. Pull requests should be
squash-merged. Commits should be signed and should use Conventional Commits.
Public Key Discovery
This personal site enables WKD for [email protected] in entropic.config.ts.
A new site that omits WKD settings leaves publication disabled. To configure it:
wkd: {
enabled: true,
email: "[email protected]",
publicKeyPath: "public/assets/pgp/public-key.asc"
}
Set wkd.enabled: false to disable publication while retaining the email and path. Replace the referenced file with your
public key export; its manual download URL also works without WKD. Key changes
require replacing only that file and rebuilding.
The configuration check rejects missing settings, private keys, and public keys whose UIDs do not match the email. The development server watches the configured public key file. Production requires a new deployment.
Migration: move the former WKD_EMAIL and WKD_PUBLIC_KEY_PATH values from
.env.local or the hosting environment into this object. Those old environment
variables no longer configure WKD; there is one source of truth. The email and
public-key path are public publishing settings, not credentials.
The build derives the mail domain and lookup hash, then generates the policy
and binary public key under dist/.well-known/openpgpkey/. Generated WKD
files are not committed. The Vercel header rules work with any mail domain.
For pnpm 12 on Vercel, use the pinned packageManager via Corepack
(ENABLE_EXPERIMENTAL_COREPACK=1 in the build environment). Confirm the actual
Node.js and pnpm versions in the deployment log; Vercel's default package-manager
detection is not the same as honoring this pin. Local builds do not verify the
remote environment.
For Vercel, deploy the configured public key and attach
openpgpkey.<mail-domain> directly to that environment, without a domain
redirect. Redeploy after changing the configuration. In Cloudflare DNS, add a
CNAME named openpgpkey using Vercel's displayed target, with Proxied (orange
cloud) and TTL Auto. Use Full (strict) for the connection to Vercel and wait
for domain verification, HTTPS certificates, and DNS caches to update.
Preserve Vercel's proxy prerequisites for certificate issuance and renewal:
allow HTTP access to /.well-known/acme-challenge/* without redirects or
browser checks, and leave /.well-known/vercel/* uncached. See:
https://vercel.com/docs/security/reverse-proxy
The proxy setting reflects deployment testing: direct Vercel connections failed during TLS 1.3 shutdown with GnuPG 2.5.21 / GnuTLS 3.8.13, while the same WKD lookup succeeded through Cloudflare with default TLS settings. Other static hosts need equivalent WKD response headers and their own live discovery checks.
WKD clients need public access without authentication or browser challenges. Cloudflare's Browser Integrity Check can reject non-browser clients with HTTP 403 / error 1010 even when GnuPG succeeds. Add a scoped exception:
Select your domain in Cloudflare, then open Rules > Overview.
Select Create rule > Configuration Rule and name it
WKD public access.Under When incoming requests match, choose a custom filter expression and open Edit expression. Replace the example hostname with your WKD hostname:
(http.host eq "openpgpkey.example.org" and starts_with(http.request.uri.path, "/.well-known/openpgpkey/") and http.request.method in {"GET" "HEAD"})Under Then the settings are, add Browser Integrity Check and set it to Off. This exception applies only to WKD GET/HEAD requests on that host.
Select Deploy.
Cloudflare documents configuration rules and selective BIC exceptions here: https://developers.cloudflare.com/rules/configuration-rules/create-dashboard/ https://developers.cloudflare.com/waf/tools/browser-integrity-check/#disable-selectively
After DNS changes have propagated, verify discovery with a fresh keyring:
gpg --homedir "$(mktemp -d)" --auto-key-locate clear,wkd \
--locate-keys [email protected]
Use your configured email and compare the complete primary fingerprint with your trusted public key export. Check that policy and key URLs accept both GET and HEAD with the expected content types and CORS headers. Test generic HTTP clients too: a successful GnuPG lookup alone does not rule out a Cloudflare browser check blocking another client. Local builds cannot verify production DNS, HTTPS, or the hosting provider's access rules.