Encode files into invisible Unicode characters for steganography and data hiding
npm install invjsible> Encode any file into invisible Unicode characters. Hide data in plain sight.



invjsible is a powerful CLI tool that encodes files using invisible Unicode characters (Zero-Width Spaces, Zero-Width Non-Joiners, etc.). The encoded files look completely blank but contain all the original data. Perfect for steganography, data hiding, or just having fun with invisible text.
- ๐ Invisible Encoding: Encode any file into invisible Unicode characters
- ๐ฆ Maximum Compression: Uses Brotli compression at maximum level (11)
- ๐ Self-Extracting: Create runnable files that auto-extract and execute
- ๐ Lossless: Perfect roundtrip encoding/decoding with no data loss
- ๐ฏ Multi-Format: Works with text, binary, JavaScript, Python, Shell, Ruby files
- ๐ Analysis Tools: Detect and analyze invisible characters in files
- ๐งน Cleanup: Remove invisible characters from contaminated files
- โก Fast: Optimized encoding/decoding algorithms
bash
npm i -g invjsible
`$3
`bash
Clone the repository
git clone https://github.com/stringmanolo/invjsible.git
cd invjsibleMake it executable (Unix/Linux/Mac)
chmod +x invjsible.jsCreate global symlink
npm link
`๐ Quick Start
`bash
Help menu
invjsibleEncode a file in invisible characters
invjsible encode secret.txtEncode a file with compression (Recomended to always use)
invjsible encode secret.txt --compressCreate a self-extracting executable
invjsible encode app.js --compress --runableRun the encoded file
node app.js.encoded
or ./app.js.encoded
Decode the file
invjsible decode secret.txt.encodedAnalyze invisible characters
invjsible analyze suspicious.txt
`๐ Usage
$3
####
encode - Encode a file`bash
invjsible encode [options]Options:
--compress Compare direct vs compressed encoding, use smaller
--runable Generate self-extracting executable
-o, --output Output file (default: .encoded)
-v, --verbose Show detailed information
Examples:
invjsible encode document.txt
invjsible encode document.txt --compress
invjsible encode script.js --runable
invjsible encode app.js --compress --runable -v
`####
decode - Decode a file`bash
invjsible decode [options]Options:
-o, --output Output file (default: .decoded)
-v, --verbose Show detailed information
Examples:
invjsible decode document.txt.encoded
invjsible decode encoded.txt -o original.txt
`####
analyze - Analyze invisible characters`bash
invjsible analyze Example:
invjsible analyze suspicious.txt
`####
clean - Remove invisible characters`bash
invjsible clean [options]Options:
-o, --output Output file (default: .cleaned)
Example:
invjsible clean document.txt
`####
list - Show available invisible characters`bash
invjsible list
`๐ฏ Use Cases
$3
Hide secret messages in plain sight:
`bash
Encode a secret message
echo "Secret data" > secret.txt
invjsible encode secret.txtThe .encoded file looks blank but contains the data
cat secret.txt.encoded # Appears empty!Decode to recover
invjsible decode secret.txt.encoded
`$3
Create files that execute themselves:
`bash
Encode a Node.js application
invjsible encode server.js --compress --runableThe encoded file is executable
node server.js.encoded
or
./server.js.encoded # On Unix systems
`$3
Hide data in text documents:
`bash
Encode binary data
invjsible encode image.pngPaste the encoded content anywhere in a text document
The binary data is preserved as invisible characters
`$3
Add invisible watermarks to text:
`bash
Encode watermark data
echo "Copyright StringManolo 2025" >> copy.txt && invjsible encode copy.txtAppend to any file
cat copy.txt.encoded >> myDocument.txt
The watermark is invisible but recoverable
`๐ง How It Works
$3
1. Read File: Load the original file into memory
2. Compress (Optional): Apply Brotli compression at maximum level
3. Binary Encoding: Convert each byte to 8-bit binary representation
4. Invisible Mapping:
-
0 โ Zero-Width Space (U+200B)
- 1 โ Zero-Width Non-Joiner (U+200C)
5. Marker Addition: Add compression marker if compressed
6. Save: Write the invisible character string to file$3
When you use
--compress, invjsible automatically compares two methods and chooses the smaller result:Option 1: Direct Encode
- Encode directly without compression
- Faster encoding
Option 2: Compress โ Encode
- Compress first with Brotli, then encode
- Best for most files, especially repetitive content
- Marked with Zero-Width Joiner (
U+200D)The tool automatically selects the most efficient method, ensuring you always get the smallest possible output.
$3
1. Detect Format: Check for compression marker
2. Decompress (if needed): Apply decompression if marker is present
3. Binary Decoding: Convert invisible characters back to binary
4. Reconstruct: Rebuild the original file byte by byte
๐ Compression Performance
Typical compression ratios with
--compress:| File Type | Original Size | Encoded Size | Ratio |
|-----------|--------------|--------------|-------|
| Text (repetitive) | 100 KB | ~15 KB | 15% |
| Text (random) | 100 KB | ~30 KB | 30% |
| JavaScript | 100 KB | ~20 KB | 20% |
| Binary (PNG) | 100 KB | ~40 KB | 40% |
| Already Compressed | 100 KB | ~80 KB | 80% |
Note: Files already compressed (PNG, ZIP, etc.) don't compress well.
๐งช Testing
`bash
Install Jest
npm install --save-dev jestRun all tests
npm testRun with coverage report
npm run test:coverageWatch mode for development
npm run test:watchGenerate HTML coverage report
npm test -- --coverage --coverageReporters=html
Then open: coverage/index.html
`$3
The project has exceptional test coverage with 172 comprehensive tests:
`
Statements : 99.67% (305/306)
Branches : 94.59% (140/148)
Functions : 100% (19/19)
Lines : 99.66% (294/295)
`$3
โ
Core Functionality
- Encoding/decoding with invisible characters
- Compression vs non-compression selection
- Binary encoding (all byte values 0x00-0xFF)
โ
CLI Commands
- All commands:
encode, decode, analyze, clean, list, help
- All flags: --compress, --runable, --verbose, -o, --output
- Error handling for all commandsโ
Runnable Templates
- Self-extracting executables for:
.js, .mjs, .sh, .bash, .py, .rb, .txt
- Files without extensions
- Compression in runnable modeโ
File Types
- Text files (ASCII, UTF-8, Unicode)
- Binary files (images, executables)
- Empty files
- Files with special characters and emojis
- Files with null bytes
โ
Edge Cases
- Empty buffers and files
- Incomplete bytes (7 bits)
- All byte patterns (0x00, 0xFF, 0x55, 0xAA, sequential)
- Maximum compression scenarios
- Files with 20, 21, 50+ invisible characters
- Very long filenames (200+ characters)
- Corrupted compression data
โ
Integration Tests
- Complete encode/decode roundtrips
- Preservation of binary data integrity
- Runnable file execution and extraction
- CLI end-to-end workflows
โ
Performance Tests
- Large file encoding (< 5 seconds)
- Large file decoding (< 5 seconds)
- Compression efficiency verification
โ
Platform Compatibility
- Unix/Linux/Mac permissions (chmod)
- Windows graceful error handling
- Cross-platform file operations
๐ Technical Details
$3
| Character | Unicode | Code | Usage |
|-----------|---------|------|-------|
| Zero-Width Space | U+200B | 8203 | Binary
0 |
| Zero-Width Non-Joiner | U+200C | 8204 | Binary 1 |
| Zero-Width Joiner | U+200D | 8205 | Compression marker |$3
`
[Optional: 1-byte compression marker (U+200D)]
[Invisible character string representing binary data]
`$3
`javascript
#!/usr/bin/env node
// Self-extracting executable generated by invjsible
[Minified decoder + embedded invisible data]
`
๐ API Usage
You can also use invjsible as a module:
`javascript
const { encode, decode, encodeToInvisible, decodeFromInvisible } = require('./invjsible.js');// Encode a buffer
const buffer = Buffer.from('Hello World');
const invisible = encodeToInvisible(buffer);
console.log(invisible); // Invisible characters
// Decode back
const { buffer: decoded } = decodeFromInvisible(invisible);
console.log(decoded.toString()); // "Hello World"
// Encode a file
await encode('input.txt', 'output.encoded', {
compress: true,
runable: false,
verbose: true
});
// Decode a file
await decode('output.encoded', 'output.decoded', {
verbose: true
});
`๐ก๏ธ Security Considerations
- Not Encryption: This is encoding, not encryption. Data is not secure.
- Obfuscation Only: Provides obscurity, not cryptographic security.
- Steganography: Good for hiding data in plain sight.
- No Authentication: No way to verify data integrity or authenticity.
For actual security, combine with encryption tools like
gpg:`bash
Encrypt then encode
gpg --encrypt secret.txt
invjsible encode secret.txt.gpgDecode then decrypt
invjsible decode secret.txt.gpg.encoded
gpg --decrypt secret.txt.gpg.decoded
`Example
> This is an example of hidding a message into a html file and recovering it.
0. Create the html file
`bash
echo '
Hello World
' > myIndex.html
`1. Check the html file has no hidden data:
`bash
cat myIndex.html | xxd
``html
00000000: 3c21 444f 4354 5950 4520 6874 6d6c 3e0a .
00000010: 3c68 746d 6c20 6c61 6e67 3d22 656e 223e
00000020: 0a3c 6865 6164 2070 7265 6669 783d 226f .. 00000050: 6172 7365 743d 2275 7466 2d38 223e 0a20 arset="utf-8">.
00000060: 203c 6c69 6e6b 2072 656c 3d22 6963 6f6e . Hel
000000a0: 6c6f 2057 6f72 6c64 3c2f 7469 746c 653e lo World
000000b0: 0a3c 2f68 6561 643e 0a3c 626f 6479 3e3c ..<
000000c0: 212d 2d20 5468 6973 2068 746d 6c20 6669 !-- This html fi
000000d0: 6c65 2063 6f6e 7461 696e 7320 6869 6464 le contains hidd
000000e0: 656e 2064 6174 6120 2d2d 3e0a 2020 3c64 en data -->. 000000f0: 6976 2069 643d 226d 7941 7070 223e 3c2f iv id="myApp">
00000100: 6469 763e 0a20 203c 7363 7269 7074 3e0a div>. .<
00000170: 2f62 6f64 793e 0a3c 2f68 746d 6c3e 0a /body>..
`2. Create a hidden message (you can reaname any file to secret.txt)
`bash
echo "I'm a secret message" > secret.txt
`3. Encode the message
`bash
invjsible encode secret.txt
`4. Split the html in half by the line you want (9 in my case)
`bash
head -n 9 myIndex.html > half1.htmltail -n +10 myIndex.html > half2.html
`5. Create the file with the hidden message:
`bash
cat half1.html secret.txt.encoded half2.html > index.html
`6. Check the file has the hidden data
`bash
cat index.html | xxd
``html
00000000: 3c21 444f 4354 5950 4520 6874 6d6c 3e0a .
00000010: 3c68 746d 6c20 6c61 6e67 3d22 656e 223e
00000020: 0a20 203c 6865 6164 2070 7265 6669 783d . 00000030: 226f 673a 6874 7470 3a2f 2f6f 6770 2e6d "og:http://ogp.m> Chrome's view-source: cat, curl and other commands will not show the hidden data.
7. To decode, split the index.html in half, get the line with encoded data and decode it
`bash
1. Get line number 10 directly
sed -n '10p' index.html > secret.txt.encoded2. Decode and print it.
invjsible decode secret.txt.encoded && cat secret.txt.decodedUsing a single line:
sed -n '10p' index.html > secret.txt.encoded && invjsible decode secret.txt.encoded && cat secret.txt.decoded
`๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/AmazingFeature)
3. Commit your changes (git commit -m 'Add some AmazingFeature')
4. Push to the branch (git push origin feature/AmazingFeature`)This project is licensed under the GPLV3 License - see the LICENSE file for details.
If you find this project useful, please consider giving it a โญ on GitHub!