{"id":31474597,"url":"https://github.com/fetchte/stain","last_synced_at":"2026-01-20T17:30:57.021Z","repository":{"id":317093421,"uuid":"1065945411","full_name":"fetchTe/stain","owner":"fetchTe","description":"Fluent, flexible, and fast ANSI styling that adds color to your terminal","archived":false,"fork":false,"pushed_at":"2025-09-28T19:34:07.000Z","size":8361,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-28T20:44:02.023Z","etag":null,"topics":["4-bit","8-bit","ansi","colors","dyslectic-friendly","fluent","no-color"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fetchTe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-28T18:40:41.000Z","updated_at":"2025-09-28T19:26:02.000Z","dependencies_parsed_at":"2025-09-28T20:44:06.708Z","dependency_job_id":null,"html_url":"https://github.com/fetchTe/stain","commit_stats":null,"previous_names":["fetchte/stain"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/fetchTe/stain","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetchTe%2Fstain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetchTe%2Fstain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetchTe%2Fstain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetchTe%2Fstain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fetchTe","download_url":"https://codeload.github.com/fetchTe/stain/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetchTe%2Fstain/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278254466,"owners_count":25956604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["4-bit","8-bit","ansi","colors","dyslectic-friendly","fluent","no-color"],"created_at":"2025-10-01T22:28:33.883Z","updated_at":"2025-10-04T02:15:11.504Z","avatar_url":"https://github.com/fetchTe.png","language":"TypeScript","readme":"\u003ch1\u003e\nStain - ANSI Styling\n\u003ca href=\"https://mibecode.com\"\u003e\n  \u003cimg align=\"right\" title=\"\u0026#8805;95% Human Code\" alt=\"\u0026#8805;95% Human Code\" src=\"https://mibecode.com/badge.svg\" /\u003e\n\u003c/a\u003e\n\u003cimg align=\"right\" alt=\"empty space\" src=\"https://mibecode.com/4px.svg\" /\u003e\n\u003cimg align=\"right\" alt=\"NPM Version\" src=\"https://img.shields.io/npm/v/stain?color=white\" /\u003e\n\u003c/h1\u003e\n\n\nStain the pane without the pain of remembering if it's `bgRed`, `redBg`, or ordering for that matter\n\n+ [Dyslectic](https://en.wikipedia.org/wiki/Dyslexia) friendly with any-[fluent](https://en.wikipedia.org/wiki/Fluent_interface)-chain API: `stain.white.bold.cyan.bg('No More Tears')`\n+ Supports: [4-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit) (16 colors), [8-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) (256 colors), **`bold`**, `dim`, \u003cins\u003e`underline`\u003c/ins\u003e, `inverse`, and [`NO_COLOR`](https://no-color.org)\n+ Nest-able: `stain.red.bold('bold' + stain.normal.blue(' normal ') + 'bold')`\n+ Fast-ish: ~180,000,000/sec (`NO_COLOR`), ~6,500,000/sec (`simpleEscape`), ~5,000,000/sec (default)\n+ [TypeScript](https://www.typescriptlang.org)'ed with zero dependencies\n\n\u003cbr /\u003e\n\n### ▎USAGE\n\n\n\u003cimg width=\"auto\" height=\"672\" alt=\"usage\" src=\"https://raw.githubusercontent.com/fetchTe/stain/master/docs/usage.png\" /\u003e\n\n\n\u003cblockquote \u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eCode\u003c/b\u003e\u003c/summary\u003e\n\n```ts\nimport stain, { createStain } from 'stain';\n\n// chain it \u0026 stain it\nconsole.log(stain.cyan('cyan fg'));\nconsole.log(stain.iblue('intense blue fg'));\nconsole.log(stain.bold.ired('bold intense red fg'));\n\n// apply a background color simply by adding '.bg' property after the color\nconsole.log(stain.icyan.bg.black('intense cyan bg with black fg'));\n// order of operations makes no difference\nconsole.log(stain.black.icyan.bg('intense cyan bg with black fg'));\n// last prop/chain always wins\nconsole.log(stain.blue.bg.red.black.icyan.bg('intense cyan bg with black fg'));\n\n// chain anything \u0026 everything till to your heart's content\nconsole.log(stain.blue.black.bg.yellow.underline('yellow fg with black bg and underlined'));\nconsole.log(stain.blue.black.bg.yellow.underline.inverse('yellow bg with black fg and underlined'));\nconsole.log(stain.even.this.works.yellow.bold('bold yellow fg'));\n\n// nesting works\nconsole.log(stain.purple.bold('bold-purple ' + stain.cyan.normal('normal-cyan') + ' bold-purple'));\n\n// xterm/256-color 'stain.x\u003cnumber\u003e' notation\nconsole.log(stain.x123('a lovely cornflower blue'));\n\n// create your own xterm/256-color palette with easy pasy to remember names\nconst customStain = createStain({\n  xterm: true,\n  colors: {\n    warn: 226, // yellow\n    error: 196, // red\n  },\n});\n\nconsole.log(customStain.warn('yellow/xterm=226 fg'));\nconsole.log(customStain.error('red/xterm=196 fg'));\nconsole.log(customStain.warn.error.bg('yellow/xterm=226 fg with red/xterm=196 bg'));\nconsole.log(customStain.warn.bg.error('red/xterm=196 fg with yellow/xterm=226 bg'));\n```\n\n\u003c/details\u003e\n\u003c/blockquote\u003e\n\n\u003c!-- \n\n\u003cblockquote \u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eColorized Output/Image\u003c/b\u003e\u003c/summary\u003e\n\u003cimg alt=\"quickstart-Screenshot_20250718_123526\" src=\"https://github.com/user-attachments/assets/80efe964-9ed9-4b3a-80b4-5a749b396a8e\" /\u003e\n\u003c/details\u003e\n\u003c/blockquote\u003e\n --\u003e\n\n\n### ▎INSTALL\n\n```sh\n# pick your poison\nnpm install stain\nbun add stain\npnpm add stain\nyarn add stain\n```\n\n\u003cbr /\u003e\n\n## API\n\n\n### ▎ `stain(?\u003coptions\u003e)`\n\n```ts\nimport stain from 'stain';\n\nconsole.log(stain.cyan('The Main Stain'));\n```\n\u003e Pre-initialized with `xterm` enabled\n\n\n\u003cbr /\u003e\n\n### ▎ `createStain(?\u003coptions\u003e)`\n\n```ts\nimport { createStain } from 'stain';\n\nconst myStain = createStain({\n  noColor: !!process.env['CI'],\n  xterm: true,\n  colors: {\n    peach: 216,\n    navy: 18,\n  },\n  format: (...args) =\u003e args.join(' | '),\n});\n\nprocess.stdout.write(`\n${myStain.x216('peach fg')}\n${myStain.peach('peach fg')}\n${myStain.x18.bg('navy bg')}\n${myStain.navy.bg('navy bg')}\n`);\n// styled format output: 'multiple | args | format'\nprocess.stdout.write(myStain.green('multiple', 'args', 'format'));\n```\n\n\u003cbr /\u003e\n\n\n### ▎ OPTIONS\n\n```ts\ntype StainOptions = {\n  /**\n   * Custom color mapping to 8-bit/256-color codes (0-255) (e.g: {error: 196})\n   * @default undefined\n   */\n  colors?: Record\u003cstring, number\u003e;\n  /**\n   * Custom format function\n   * @default simplified `util.format` with with `JSON.stringify` fallback\n   * @see {@link https://nodejs.org/api/util.html#utilformatformat-args}\n   */\n  format?: (...args: any[]) =\u003e string;\n  /**\n   * Disable ANSI color/styling (~50-250x faster)\n   * @default false (unless the `NO_COLOR` environment/CLI variable is set)\n   */\n  noColor?: boolean;\n  /**\n   * Use a simpler ANSI escape function without nesting support (~1.5-4x faster)\n   * @default false\n   */\n  simpleEscape?: boolean;\n  /**\n   * Enable 8-bit/256-color support via `x\u003cnumber\u003e` notation\n   * @default false (for `createStain`)\n   * @default true  (for default `stain` export)\n   * @see {@link https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit}\n   */\n  xterm?: boolean;\n};\n```\n\n\u003cbr /\u003e\n\n### ▎ FLUENT METHODS\n\n|                | Options                  |\n|----------------------------|:--------------------------------|\n| \u003cstamp\u003e**Background**\u003c/stamp\u003e            | append `.bg` to any foreground (e.g: `stain.white.bg`, `stain.iblue.bg`) |\n| \u003cstamp\u003e**[4-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit) Color**\u003c/stamp\u003e                  | ` black`, ` red`, ` green`, ` yellow`, ` blue`, ` purple`, ` cyan`, ` white` |\n| \u003cstamp\u003e**[4-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit) Color Intense**\u003c/stamp\u003e          | `iblack`, `ired`, `igreen`, `iyellow`, `iblue`, `ipurple`, `icyan`, `iwhite` |\n| \u003cstamp\u003e**[8-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) Color**\u003c/stamp\u003e           | `x0` through `x255` (e.g: `stain.x122`, `stain.x50`, `stain.x150.bg`)             |\n| \u003cstamp\u003e**Font**\u003c/stamp\u003e            | `bold`, `dim`, `normal`, `underline` |\n| \u003cstamp\u003e**Other**\u003c/stamp\u003e           | `inverse`, `reset` |\n\n\n\u003cblockquote \u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003e8-bit Color Grid\u003c/b\u003e\u003c/summary\u003e\n  \u003cimg alt=\"8bit-256-xterm\" src=\"https://raw.githubusercontent.com/fetchTe/stain/master/docs/8bit-256-xterm.png\" /\u003e\n\u003c/details\u003e\n\u003c/blockquote\u003e\n\n\n\u003cbr /\u003e\n\n#### ▎ EXAMPLES\n```ts\n// bold - makes text bold\nconsole.log(' ' + stain.bold('stain.bold'));\n// dim - makes text dim\nconsole.log(' ' + stain.dim('stain.dim'));\nconsole.log(' ' + stain.dim.white('stain.dim.white (tends to work better than gray)'));\n// underline - underlines text\nconsole.log(' ' + stain.red.underline('stain.red.underline'));\n// inverse - inverts the foreground and background colors\nconsole.log(' ' + stain.red.black.bg('stain.red.black.bg'));\nconsole.log(' ' + stain.red.black.bg.inverse('stain.red.black.bg.inverse'));\n// normal - resets bold and dim styles\nconsole.log(' ' + stain.cyan.bold(`stain.cyan.bold ${stain.normal(' stain.normal ')} stain.cyan.bold`));\nconsole.log(' ' + stain.cyan.dim(`stain.cyan.dim  ${stain.normal(' stain.normal ')} stain.cyan.dim`));\n// reset - resets all active styles, returning to the terminal default\nconsole.log(' ' + stain.underline.yellow.bold(`stain.underline.yellow.bold${stain.reset(' reset ')}stain.underline.yellow.bold`));\n```\n\u003e \u003cimg alt=\"examples\" src=\"https://raw.githubusercontent.com/fetchTe/stain/master/docs/examples.png\" /\u003e \u003cbr /\u003e\n\n\u003cbr /\u003e\n\n#### ▎ ALL FONT STYLES\n\n\u003cimg alt=\"all-font-color-styles\" src=\"https://raw.githubusercontent.com/fetchTe/stain/master/docs/all-font-color-styles.png\" /\u003e\n\n\u003c!-- \n\n#### ▎ ALL ANSI STAINS\n --\u003e\n\n\n\n\u003cbr /\u003e\n\n## Development/Contributing\n\u003e Required build dependencies: [Bun](https://bun.sh) and [Make](https://www.gnu.org/software/make/manual/make.html) \u003cbr /\u003e\n\n\n### ▎PULL REQUEST STEPS\n\n1. Clone repository\n2. Create and switch to a new branch for your work\n3. Make and commit changes\n4. Run `make release` to clean, setup, build, lint, and test\n5. If everything checks out, push branch to repository and submit pull request\n\u003cbr /\u003e\n\n### ▎MAKEFILE REFERENCE\n\n```\n# USAGE\n   make [flags...] \u003ctarget\u003e\n\n# TARGET\n  -------------------\n   run                   executes entry-point (./src/index.ts) via 'bun run'\n   release               clean, setup, build, lint, test, aok (everything but the kitchen sink)\n  -------------------\n   build                 builds the .{js,d.ts} (skips: lint, test, and .min.* build)\n   build_cjs             builds the .cjs export\n   build_esm             builds the .js (esm) export\n   build_declarations    builds typescript .d.{ts,mts,cts} declarations\n  -------------------\n   install               installs dependencies via bun\n   update                updates dependencies\n   update_dry            lists dependencies that would be updated via 'make update'\n  -------------------\n   lint                  lints via tsc \u0026 eslint\n   lint_eslint           lints via eslint\n   lint_eslint_fix       lints and auto-fixes via eslint --fix\n   lint_tsc              lints via tsc\n   lint_watch            lints via eslint \u0026 tsc with fs.watch to continuously lint on change\n  -------------------\n   test                  runs bun test(s)\n   test_watch            runs bun test(s) in watch mode\n   test_update           runs bun test --update-snapshots\n  -------------------\n   help                  displays (this) help screen\n\n# FLAGS\n  -------------------\n   BUN                   [? ] bun build flag(s) (e.g: make BUN=\"--banner='// bake until golden brown'\")\n  -------------------\n   CJS                   [?1] builds the cjs (common js) target on 'make release'\n   EXE                   [?js|mjs] default esm build extension\n   TAR                   [?0] build target env (-1=bun, 0=node, 1=dom, 2=dom+iife, 3=dom+iife+userscript)\n   MIN                   [?1] builds minified (*.min.{mjs,cjs,js}) targets on 'make release'\n  -------------------\n   BAIL                  [?1] fail fast (bail) on the first test or lint error\n   ENV                   [?DEV|PROD|TEST] sets the 'ENV' \u0026 'IS_*' static build variables (else auto-set)\n   TEST                  [?0] sets the 'IS_TEST' static build variable (always 1 if test target)\n   WATCH                 [?0] sets the '--watch' flag for bun/tsc (e.g: WATCH=1 make test)\n  -------------------\n   DEBUG                 [?0] enables verbose logging and sets the 'IS_DEBUG' static build variable\n   QUIET                 [?0] disables pretty-printed/log target (INIT/DONE) info\n   NO_COLOR              [?0] disables color logging/ANSI codes\n```\n\n\u003cbr /\u003e\n\n\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2025 te \u003clegal@fetchTe.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffetchte%2Fstain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffetchte%2Fstain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffetchte%2Fstain/lists"}