Transformers are instantiated using BaseTransformer class. Category is automatically assigned from the directory name.
Categories (auto-assigned from directory name):
encoding/- Base64, Hex, Binary, URL, HTML, etc.cipher/- ROT13, Caesar, Vigenère, Atbash, etc.unicode/- Cursive, Medieval, Monospace, Bubble, etc.case/- Snake case, Kebab case, Title case, etc.technical/- Morse, Braille, NATO, Brainfuck, etc.fantasy/- Elder Futhark, Tengwar, Klingon, Aurebesh, etc.ancient/- Hieroglyphics, Ogham, Roman Numerals, etc.format/- Leetspeak, Pig Latin, Reverse, etc.visual/- Emoji speak, Rovarspraket, etc.special/- Randomizer, etc.
name- Display name (string)func- Encoding function(text) => stringpriority- Decoder priority (number, 1-310)
reverse- Decoding function(text) => string(auto-generated ifmapprovided)map- Character mapping object (auto-generatesreverse)detector- Detection function(text) => boolean(for universal decoder)preview- Preview function(text) => string(defaults tofunc)canDecode- Boolean (default:true)description- Help text (string)
import BaseTransformer from '../BaseTransformer.js';
export default new BaseTransformer({
name: 'Cursive',
priority: 85,
map: {
'a': '𝒶', 'b': '𝒷', 'c': '𝒸',
// ... more mappings
},
func: function(text) {
return [...text].map(c => this.map[c] || c).join('');
}
// reverse is auto-generated from map!
});import BaseTransformer from '../BaseTransformer.js';
export default new BaseTransformer({
name: 'Base64',
priority: 270,
detector: function(text) {
const cleaned = text.trim().replace(/\s/g, '');
return cleaned.length >= 4 && /^[A-Za-z0-9+\/=]+$/.test(cleaned);
},
func: function(text) {
// Encoding logic
const encoder = new TextEncoder();
const bytes = encoder.encode(text);
let binaryString = '';
for (let i = 0; i < bytes.length; i++) {
binaryString += String.fromCharCode(bytes[i]);
}
return btoa(binaryString);
},
reverse: function(text) {
// Decoding logic
const binaryString = atob(text);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
},
preview: function(text) {
if (!text) return '[base64]';
const full = this.func(text);
return full.substring(0, 12) + (full.length > 12 ? '...' : '');
}
});export default new BaseTransformer({
name: 'Random Mix',
priority: 0,
canDecode: false,
func: function(text) {
// Encoding logic only
return randomized;
}
});Higher priority = more specific pattern (used for decoder result ordering):
- 310: Most exclusive (Semaphore Flags)
- 300: Exclusive character sets (Binary, Morse, Braille, Brainfuck, Tap Code)
- 290: Hexadecimal
- 285: Pattern-based (Pig Latin, Dovahzul)
- 280: Base32
- 270-275: Base encodings (Base64, Base58, Base45)
- 260: A1Z26
- 150: Active transform (user context)
- 100: High confidence (Fantasy scripts, unique Unicode ranges)
- 85: Unicode transformations (default)
- 70: Common encodings (URL, HTML, ASCII85)
- 60: Ciphers (ROT13, Caesar)
- 50: Generic text transforms
- 20: Low confidence generic
- 1: Invisible text (last resort)
- 0: Cannot decode / encode-only
- Place file in appropriate category directory
- Run
npm run build:transforms - Test in webapp
- Add
detectorfunction if format has distinctive patterns - Optionally add test cases to
tests/test_universal.js - Add a one-line description for the transform’s
nameinDESCRIPTIONSinsidebuild/readme-transform-section.js, then runnode build/readme-transform-section.jsand merge the printed block into the Text Transformations section of the rootREADME.md(the script exits with an error if a transform is missing fromDESCRIPTIONS)
All transformers with reverse are automatically tested by tests/test_universal.js.
For transformers with known limitations (e.g., lowercases input), add to limitations object in test_universal.js:
const limitations = {
'your_transform': {
issues: 'Description of changes',
normalize: { lowercase: true, stripEmoji: true }
}
};