capstring
v1.1.0
Published
CaPiTaLiZe StRiNgS! Case conversion, code conventions, encodings, and fun text styles. Zero deps, Unicode safe.
Maintainers
Readme
capstring
CaPiTaLiZe StRiNgS!
A small, serious, zero-dependency library for turning text into any case, code convention, or ridiculous fun style. Unicode and emoji safe. Ships a CLI and TypeScript types.
Features
- Every style you need - case, code conventions, encodings, and Unicode art
- Zero dependencies - one 17 kB file, browser-safe
- Unicode aware -
Élan Vital,crème-brûlée, emoji and flags survive every style - Smart tokenizer -
XMLHttpRequestbecomesxml-http-request,hello_worldbecomeshelloWorld - Website, HTTP API, and docs - capstring.netlify.app: playground, Developer Docs, API Reference
- CLI -
npx capstring kebab "Hello World" - TypeScript types - autocomplete for every style name
- 100% test coverage
Try it online
capstring.netlify.app - type anything, see every style, click to copy.
Installation
npm install capstringQuick Start
import capstring from 'capstring';
capstring('hello world', 'title'); // 'Hello World'
capstring('hello world', 'kebab'); // 'hello-world'
capstring('hello world', 'constant'); // 'HELLO_WORLD'
capstring('hello world', 'sponge'); // 'HeLlO WoRlD'
capstring('hello world', 'flip'); // 'plɹoʍ ollǝɥ'
capstring('hello world', 'hashtag'); // '#HelloWorld'CLI
# no install, runs the latest version each time
npx capstring kebab "hello world" # hello-world
# or install once and use it anywhere
npm install -g capstring
capstring kebab "hello world" # hello-worldnpx capstring kebab "Hello World" # hello-world
echo "hello world" | npx capstring title # Hello World
npx capstring --all "hello world" # every style, one per line
npx capstring --list # style names
npx capstring --count "hello world" # words: 2, chars: 11, chars (no spaces): 10, spaces: 1
npx capstring snake --json "Hello World" # {"input":"Hello World","style":"snake","output":"hello_world"}Exit code 2 means a usage error (unknown style or option, missing text).
All Styles
Every style applied to hello world. Full explanations with more examples are in the Developer Docs.
Case
| Style | hello world becomes |
|-------|------------------------|
| same | hello world |
| none | (empty string) |
| proper | hello world |
| title | Hello World |
| sentence | Hello world |
| upper | HELLO WORLD |
| lower | hello world |
| swap | HELLO WORLD |
| capitalize | Hello world |
| lowerfirst | hello world |
Code
| Style | hello world becomes |
|-------|------------------------|
| camel | helloWorld |
| pascal | HelloWorld |
| snake | hello_world |
| kebab | hello-world |
| slug | hello-world |
| constant | HELLO_WORLD |
| python | HELLO_WORLD |
| dot | hello.world |
| path | hello/world |
| train | Hello-World |
| hashtag | #HelloWorld |
| acronym | HW |
| ada | Hello_World |
| cobol | HELLO-WORLD |
| initials | H.W. |
Fun
| Style | hello world becomes |
|-------|------------------------|
| reverse | dlrow olleh |
| sponge | HeLlO WoRlD |
| mock | hElLo wOrLd |
| alternate | hElLo WoRlD |
| crazy | HEllo WorlD |
| random | (random case, different every call) |
| clap | hello 👏 world |
| piglatin | ellohay orldway |
| spaced | h e l l o w o r l d |
| squish | helloworld |
| nato | Hotel Echo Lima Lima Oscar / Whiskey Oscar Romeo Lima Delta |
Encodings
| Style | hello world becomes |
|-------|------------------------|
| leet | h3110 w0r1d |
| rot13 | uryyb jbeyq |
| morse | .... . .-.. .-.. --- / .-- --- .-. .-.. -.. |
| binary | 01101000 01100101 01101100 01101100 01101111 00100000 01110111 01101111 01110010 01101100 01100100 |
| hex | 68 65 6c 6c 6f 20 77 6f 72 6c 64 |
| base64 | aGVsbG8gd29ybGQ= |
Unicode Art
| Style | hello world becomes |
|-------|------------------------|
| flip | plɹoʍ ollǝɥ |
| smallcaps | ʜᴇʟʟᴏ ᴡᴏʀʟᴅ |
| bubble | ⓗⓔⓛⓛⓞ ⓦⓞⓡⓛⓓ |
| wide | hello world |
| strike | h̶e̶l̶l̶o̶ w̶o̶r̶l̶d̶ |
| bold | 𝗵𝗲𝗹𝗹𝗼 𝘄𝗼𝗿𝗹𝗱 |
| italic | 𝘩𝘦𝘭𝘭𝘰 𝘸𝘰𝘳𝘭𝘥 |
| script | 𝓱𝓮𝓵𝓵𝓸 𝔀𝓸𝓻𝓵𝓭 |
All code styles share one tokenizer: words split on whitespace, _, -, ., /, punctuation,
emoji, and camelCase boundaries (XMLHttpRequest → xml-http-request). Letters stay attached to
digits (utf8). Apostrophes are dropped (don't → dont).
API
capstring(str, style = 'same', options?)
import capstring from 'capstring';
capstring('hello world', 'title'); // 'Hello World'
capstring('hello world'); // 'hello world' (default: same)
capstring(''); // ''
capstring(123); // false (not a string)
capstring('hello world', 'nope'); // 'hello world' (unknown style returns input)
// Strict mode throws instead
capstring(123, 'title', { strict: true }); // TypeError
capstring('hi', 'nope', { strict: true }); // RangeErrorcapstringAll(str, options?)
Every style at once, keyed by style name in STYLES order.
import { capstringAll } from 'capstring';
const all = capstringAll('hello world');
all.kebab; // 'hello-world'
all.morse; // '.... . .-.. .-.. --- / .-- --- .-. .-.. -..'
all.nato; // 'Hotel Echo Lima Lima Oscar / Whiskey Oscar Romeo Lima Delta'getStyles(), isValidStyle(style), STYLES, CATEGORIES
import { getStyles, isValidStyle, STYLES, CATEGORIES } from 'capstring';
getStyles(); // ['same', 'none', 'proper', ...] (fresh copy)
isValidStyle('kebab'); // true
STYLES; // frozen array of every style name
CATEGORIES.art; // ['flip', 'smallcaps', 'bubble', 'wide', 'strike'] (frozen)TypeScript
import capstring, { type Style } from 'capstring';
const style: Style = 'kebab'; // autocompletes every style name
capstring('Hello', style); // stringHTTP API
Free, no key, CORS enabled, hosted at https://capstring.netlify.app/api. Interactive reference
with try-it-out: capstring.netlify.app/api.
curl https://capstring.netlify.app/api/title/hello%20world
# {"input":"hello world","style":"title","output":"Hello World"}
curl https://capstring.netlify.app/api/sponge/hello%20world.txt
# HeLlO WoRlD
curl -H "Accept: text/csv" https://capstring.netlify.app/api/all/hello%20world
curl -X POST https://capstring.netlify.app/api/batch \
-H "Content-Type: application/json" \
-d '{"style":"slug","texts":["hello world","Hello World"]}'| Endpoint | Returns |
|----------|---------|
| GET /api/:style/:text | { input, style, output } |
| GET /api/all/:text | every style |
| POST /api/batch | { style, texts[] } (max 1,000 texts, 100,000 characters in total) |
| GET /api/spell/:text | spell-corrected text plus a corrections list, optional ?style= |
| GET /api/count/:text | words, characters, characters without spaces |
| GET /api/lorem/:count | lorem ipsum words (1 to 1000), optional ?style= |
| GET /api/badge/:style/:text | shields-style SVG badge, ?label= to override the left side |
| GET /api/styles | style names and categories |
Output is JSON by default. Pick another format with an extension (.txt, .html, .xml, .yaml,
.csv, .jsonp, .svg or .png for the result as an image), ?format=, or an Accept header. Text is limited to 10,000 characters (500 for
spell); GET URLs are capped around 8 KB by the host, so use POST /api/batch for longer text. Errors come back in the same format as { "error": { "code", "message" } }.
Behavior notes
Exact rules for title, sentence, slug, the tokenizer, and Unicode handling are documented per
style in the Developer Docs. The short version: every
style iterates code points, the reordering and art styles iterate grapheme clusters, slug is ASCII
only, and random is the only non-deterministic style.
Development
npm install # Install dependencies
npm test # Run tests
npm run lint # Run linter
npm run test:coverage # Test with coverage (100% required)
npm run dev # Netlify Dev: site + API at http://localhost:8888The website (web/: playground and Developer Docs; plain HTML/CSS/JS, no build step; the Swagger API
Reference is served by the API function at /api) and the API (netlify/functions/api.js) both import index.js directly. The spellcheck and PNG
dependencies (nspell, dictionary-en, @resvg/resvg-js) are devDependencies bundled into the function,
with the fonts for PNG rendering vendored in netlify/fonts/, so the npm package itself stays zero-dependency.
Contributing
Please read CONTRIBUTING.md for details on the code of conduct and the process for submitting pull requests.
Versioning
This project uses Semantic Versioning 2.0.
Requirements
- Node.js 22.13+ (or any modern browser)
- ES modules (
import/export)
License
MIT - Copyright 2016-2026 Brian Funk
